]>
git.proxmox.com Git - pve-manager.git/blob - www/manager/Utils.js
09788cfc8c855346e28c9f232466739b46ee1cb8
3 // avoid errors when running without development tools
4 if (! Ext
. isDefined ( Ext
. global
. console
)) {
10 console
. log ( "Starting PVE Manager" );
12 Ext
. Ajax
. defaultHeaders
= {
13 'Accept' : 'application/json'
16 Ext
. Ajax
. on ( 'beforerequest' , function ( conn
, options
) {
17 if ( PVE
. CSRFPreventionToken
) {
18 if (! options
. headers
) {
21 options
. headers
. CSRFPreventionToken
= PVE
. CSRFPreventionToken
;
25 var IPV4_OCTET
= "(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])" ;
26 var IPV4_REGEXP
= "(?:(?:" + IPV4_OCTET
+ " \\ .){3}" + IPV4_OCTET
+ ")" ;
27 var IPV6_H16
= "(?:[0-9a-fA-F]{1,4})" ;
28 var IPV6_LS32
= "(?:(?:" + IPV6_H16
+ ":" + IPV6_H16
+ ")|" + IPV4_REGEXP
+ ")" ;
30 var IP4_match
= new RegExp ( "^(?:" + IPV4_REGEXP
+ ")$" );
31 var IP4_cidr_match
= new RegExp ( "^(?:" + IPV4_REGEXP
+ ")\/[1-3]?[0-9]$" );
33 var IPV6_REGEXP
= "(?:" +
34 "(?:(?:" + "(?:" + IPV6_H16
+ ":){6})" + IPV6_LS32
+ ")|" +
35 "(?:(?:" + "::" + "(?:" + IPV6_H16
+ ":){5})" + IPV6_LS32
+ ")|" +
36 "(?:(?:(?:" + IPV6_H16
+ ")?::" + "(?:" + IPV6_H16
+ ":){4})" + IPV6_LS32
+ ")|" +
37 "(?:(?:(?:(?:" + IPV6_H16
+ ":){0,1}" + IPV6_H16
+ ")?::" + "(?:" + IPV6_H16
+ ":){3})" + IPV6_LS32
+ ")|" +
38 "(?:(?:(?:(?:" + IPV6_H16
+ ":){0,2}" + IPV6_H16
+ ")?::" + "(?:" + IPV6_H16
+ ":){2})" + IPV6_LS32
+ ")|" +
39 "(?:(?:(?:(?:" + IPV6_H16
+ ":){0,3}" + IPV6_H16
+ ")?::" + "(?:" + IPV6_H16
+ ":){1})" + IPV6_LS32
+ ")|" +
40 "(?:(?:(?:(?:" + IPV6_H16
+ ":){0,4}" + IPV6_H16
+ ")?::" + ")" + IPV6_LS32
+ ")|" +
41 "(?:(?:(?:(?:" + IPV6_H16
+ ":){0,5}" + IPV6_H16
+ ")?::" + ")" + IPV6_H16
+ ")|" +
42 "(?:(?:(?:(?:" + IPV6_H16
+ ":){0,7}" + IPV6_H16
+ ")?::" + ")" + ")" +
45 var IP6_match
= new RegExp ( "^(?:" + IPV6_REGEXP
+ ")$" );
46 var IP6_cidr_match
= new RegExp ( "^(?:" + IPV6_REGEXP
+ ")\/[0-9]{1,3}?$" );
47 var IP6_bracket_match
= new RegExp ( "^ \\ [(" + IPV6_REGEXP
+ ") \\ ]" );
49 var IP64_match
= new RegExp ( "^(?:" + IPV6_REGEXP
+ "|" + IPV4_REGEXP
+ ")$" );
51 Ext
. define ( 'PVE.Utils' , { statics
: {
53 // this class only contains static functions
55 toolkit
: undefined , // (extjs|touch), set inside Toolkit.js
69 'c' : gettext ( 'Community' ),
70 'b' : gettext ( 'Basic' ),
71 's' : gettext ( 'Standard' ),
72 'p' : gettext ( 'Premium' )
75 noSubKeyHtml
: 'You do not have a valid subscription for this server. Please visit <a target="_blank" href="http://www.proxmox.com/products/proxmox-ve/subscription-service-plans">www.proxmox.com</a> to get a list of available options.' ,
78 other
: gettext ( 'Other OS types' ),
79 wxp
: 'Microsoft Windows XP/2003' ,
80 w2k
: 'Microsoft Windows 2000' ,
81 w2k8
: 'Microsoft Windows Vista/2008' ,
82 win7
: 'Microsoft Windows 7/2008r2' ,
83 win8
: 'Microsoft Windows 8/10/2012' ,
84 l24
: 'Linux 2.4 Kernel' ,
85 l26
: 'Linux 4.X/3.X/2.6 Kernel' ,
86 solaris
: 'Solaris Kernel'
89 render_kvm_ostype : function ( value
) {
91 return gettext ( 'Other OS types' );
93 var text
= PVE
. Utils
. kvm_ostypes
[ value
];
95 return text
+ ' (' + value
+ ')' ;
100 render_hotplug_features : function ( value
) {
103 if (! value
|| ( value
=== '0' )) {
104 return gettext ( 'disabled' );
107 Ext
. each ( value
. split ( ',' ), function ( el
) {
109 fa
. push ( gettext ( 'Disk' ));
110 } else if ( el
=== 'network' ) {
111 fa
. push ( gettext ( 'Network' ));
112 } else if ( el
=== 'usb' ) {
113 fa
. push ( gettext ( 'USB' ));
114 } else if ( el
=== 'memory' ) {
115 fa
. push ( gettext ( 'Memory' ));
116 } else if ( el
=== 'cpu' ) {
117 fa
. push ( gettext ( 'CPU' ));
123 return fa
. join ( ', ' );
126 network_iface_types
: {
127 eth
: gettext ( "Network Device" ),
128 bridge
: 'Linux Bridge' ,
130 vlan
: 'Linux Vlan interface' ,
131 OVSBridge
: 'OVS Bridge' ,
134 OVSIntPort
: 'OVS IntPort'
137 render_network_iface_type : function ( value
) {
138 return PVE
. Utils
. network_iface_types
[ value
] ||
139 PVE
. Utils
. unknownText
;
142 render_qemu_bios : function ( value
) {
144 return PVE
. Utils
. defaultText
+ ' (SeaBIOS)' ;
145 } else if ( value
=== 'seabios' ) {
147 } else if ( value
=== 'ovmf' ) {
148 return "OVMF (UEFI)" ;
154 render_scsihw : function ( value
) {
156 return PVE
. Utils
. defaultText
+ ' (LSI 53C895A)' ;
157 } else if ( value
=== 'lsi' ) {
158 return 'LSI 53C895A' ;
159 } else if ( value
=== 'lsi53c810' ) {
161 } else if ( value
=== 'megasas' ) {
162 return 'MegaRAID SAS 8708EM2' ;
163 } else if ( value
=== 'virtio-scsi-pci' ) {
165 } else if ( value
=== 'virtio-scsi-single' ) {
166 return 'VIRTIO single' ;
167 } else if ( value
=== 'pvscsi' ) {
168 return 'VMware PVSCSI' ;
174 // fixme: auto-generate this
175 // for now, please keep in sync with PVE::Tools::kvmkeymaps
180 'de-ch' : 'German (Swiss)' ,
181 'en-gb' : 'English (UK)' ,
182 'en-us' : 'English (USA)' ,
186 //fo: 'Faroe Islands',
188 'fr-be' : 'French (Belgium)' ,
189 'fr-ca' : 'French (Canada)' ,
190 'fr-ch' : 'French (Swiss)' ,
200 //'nl-be': 'Dutch (Belgium)',
204 'pt-br' : 'Portuguese (Brazil)' ,
213 std
: gettext ( 'Standard VGA' ),
214 vmware
: gettext ( 'VMWare compatible' ),
215 cirrus
: 'Cirrus Logic GD5446' ,
217 qxl2
: 'SPICE dual monitor' ,
218 qxl3
: 'SPICE three monitors' ,
219 qxl4
: 'SPICE four monitors' ,
220 serial0
: gettext ( 'Serial terminal' ) + ' 0' ,
221 serial1
: gettext ( 'Serial terminal' ) + ' 1' ,
222 serial2
: gettext ( 'Serial terminal' ) + ' 2' ,
223 serial3
: gettext ( 'Serial terminal' ) + ' 3'
226 render_kvm_language : function ( value
) {
228 return PVE
. Utils
. defaultText
;
230 var text
= PVE
. Utils
. kvm_keymaps
[ value
];
232 return text
+ ' (' + value
+ ')' ;
237 kvm_keymap_array : function () {
238 var data
= [[ '' , PVE
. Utils
. render_kvm_language ( '' )]];
239 Ext
. Object
. each ( PVE
. Utils
. kvm_keymaps
, function ( key
, value
) {
240 data
. push ([ key
, PVE
. Utils
. render_kvm_language ( value
)]);
246 render_console_viewer : function ( value
) {
248 return PVE
. Utils
. defaultText
+ ' (HTML5)' ;
249 } else if ( value
=== 'vv' ) {
250 return 'SPICE (remote-viewer)' ;
251 } else if ( value
=== 'applet' || value
=== 'html5' ) {
252 return 'HTML5 (noVNC)' ;
263 eu
: 'Euskera (Basque)' ,
270 nb
: 'Norwegian (Bokmal)' ,
271 nn
: 'Norwegian (Nynorsk)' ,
272 fa
: 'Persian (Farsi)' ,
274 pt_BR
: 'Portuguese (Brazil)' ,
282 render_language : function ( value
) {
284 return PVE
. Utils
. defaultText
+ ' (English)' ;
286 var text
= PVE
. Utils
. language_map
[ value
];
288 return text
+ ' (' + value
+ ')' ;
293 language_array : function () {
294 var data
= [[ '' , PVE
. Utils
. render_language ( '' )]];
295 Ext
. Object
. each ( PVE
. Utils
. language_map
, function ( key
, value
) {
296 data
. push ([ key
, PVE
. Utils
. render_language ( value
)]);
302 render_kvm_vga_driver : function ( value
) {
304 return PVE
. Utils
. defaultText
;
306 var text
= PVE
. Utils
. kvm_vga_drivers
[ value
];
308 return text
+ ' (' + value
+ ')' ;
313 kvm_vga_driver_array : function () {
314 var data
= [[ '' , PVE
. Utils
. render_kvm_vga_driver ( '' )]];
315 Ext
. Object
. each ( PVE
. Utils
. kvm_vga_drivers
, function ( key
, value
) {
316 data
. push ([ key
, PVE
. Utils
. render_kvm_vga_driver ( value
)]);
322 render_kvm_startup : function ( value
) {
323 var startup
= PVE
. Parser
. parseStartup ( value
);
326 if ( startup
. order
=== undefined ) {
329 res
+= startup
. order
;
331 if ( startup
. up
!== undefined ) {
332 res
+= ',up=' + startup
. up
;
334 if ( startup
. down
!== undefined ) {
335 res
+= ',down=' + startup
. down
;
342 return Ext
. util
. Cookies
. get ( 'PVEAuthCookie' );
345 authClear : function () {
346 Ext
. util
. Cookies
. clear ( "PVEAuthCookie" );
349 // fixme: remove - not needed?
350 gridLineHeigh : function () {
358 extractRequestError : function ( result
, verbose
) {
359 var msg
= gettext ( 'Successful' );
361 if (! result
. success
) {
362 msg
= gettext ( "Unknown error" );
363 if ( result
. message
) {
364 msg
= result
. message
;
366 msg
+= ' (' + result
. status
+ ')' ;
369 if ( verbose
&& Ext
. isObject ( result
. errors
)) {
371 Ext
. Object
. each ( result
. errors
, function ( prop
, desc
) {
372 msg
+= "<br><b>" + Ext
. htmlEncode ( prop
) + "</b>: " +
373 Ext
. htmlEncode ( desc
);
381 extractFormActionError : function ( action
) {
383 switch ( action
. failureType
) {
384 case Ext
. form
. action
. Action
. CLIENT_INVALID
:
385 msg
= gettext ( 'Form fields may not be submitted with invalid values' );
387 case Ext
. form
. action
. Action
. CONNECT_FAILURE
:
388 msg
= gettext ( 'Connection error' );
389 var resp
= action
. response
;
390 if ( resp
. status
&& resp
. statusText
) {
391 msg
+= " " + resp
. status
+ ": " + resp
. statusText
;
394 case Ext
. form
. action
. Action
. LOAD_FAILURE
:
395 case Ext
. form
. action
. Action
. SERVER_INVALID
:
396 msg
= PVE
. Utils
. extractRequestError ( action
. result
, true );
403 API2Request : function ( reqOpts
) {
405 var newopts
= Ext
. apply ({
406 waitMsg
: gettext ( 'Please wait...' )
409 if (! newopts
. url
. match ( /^\/api2/ )) {
410 newopts
. url
= '/api2/extjs' + newopts
. url
;
412 delete newopts
. callback
;
414 var createWrapper = function ( successFn
, callbackFn
, failureFn
) {
416 success : function ( response
, options
) {
417 if ( options
. waitMsgTarget
) {
418 if ( PVE
. Utils
. toolkit
=== 'touch' ) {
419 options
. waitMsgTarget
. setMasked ( false );
421 options
. waitMsgTarget
. setLoading ( false );
424 var result
= Ext
. decode ( response
. responseText
);
425 response
. result
= result
;
426 if (! result
. success
) {
427 response
. htmlStatus
= PVE
. Utils
. extractRequestError ( result
, true );
428 Ext
. callback ( callbackFn
, options
. scope
, [ options
, false , response
]);
429 Ext
. callback ( failureFn
, options
. scope
, [ response
, options
]);
432 Ext
. callback ( callbackFn
, options
. scope
, [ options
, true , response
]);
433 Ext
. callback ( successFn
, options
. scope
, [ response
, options
]);
435 failure : function ( response
, options
) {
436 if ( options
. waitMsgTarget
) {
437 if ( PVE
. Utils
. toolkit
=== 'touch' ) {
438 options
. waitMsgTarget
. setMasked ( false );
440 options
. waitMsgTarget
. setLoading ( false );
443 response
. result
= {};
445 response
. result
= Ext
. decode ( response
. responseText
);
447 var msg
= gettext ( 'Connection error' ) + ' - server offline?' ;
448 if ( response
. aborted
) {
449 msg
= gettext ( 'Connection error' ) + ' - aborted.' ;
450 } else if ( response
. timedout
) {
451 msg
= gettext ( 'Connection error' ) + ' - Timeout.' ;
452 } else if ( response
. status
&& response
. statusText
) {
453 msg
= gettext ( 'Connection error' ) + ' ' + response
. status
+ ': ' + response
. statusText
;
455 response
. htmlStatus
= msg
;
456 Ext
. callback ( callbackFn
, options
. scope
, [ options
, false , response
]);
457 Ext
. callback ( failureFn
, options
. scope
, [ response
, options
]);
462 createWrapper ( reqOpts
. success
, reqOpts
. callback
, reqOpts
. failure
);
464 var target
= newopts
. waitMsgTarget
;
466 if ( PVE
. Utils
. toolkit
=== 'touch' ) {
467 target
. setMasked ({ xtype
: 'loadmask' , message
: newopts
. waitMsg
} );
469 // Note: ExtJS bug - this does not work when component is not rendered
470 target
. setLoading ( newopts
. waitMsg
);
473 Ext
. Ajax
. request ( newopts
);
476 assemble_field_data : function ( values
, data
) {
477 if ( Ext
. isObject ( data
)) {
478 Ext
. Object
. each ( data
, function ( name
, val
) {
479 if ( values
. hasOwnProperty ( name
)) {
480 var bucket
= values
[ name
];
481 if (! Ext
. isArray ( bucket
)) {
482 bucket
= values
[ name
] = [ bucket
];
484 if ( Ext
. isArray ( val
)) {
485 values
[ name
] = bucket
. concat ( val
);
496 checked_command : function ( orig_cmd
) {
497 PVE
. Utils
. API2Request ({
498 url
: '/nodes/localhost/subscription' ,
501 failure : function ( response
, opts
) {
502 Ext
. Msg
. alert ( gettext ( 'Error' ), response
. htmlStatus
);
504 success : function ( response
, opts
) {
505 var data
= response
. result
. data
;
507 if ( data
. status
!== 'Active' ) {
509 title
: gettext ( 'No valid subscription' ),
510 icon
: Ext
. Msg
. WARNING
,
511 msg
: PVE
. Utils
. noSubKeyHtml
,
513 callback : function ( btn
) {
528 vncproxy
: [ 'VM/CT' , gettext ( 'Console' ) ],
529 spiceproxy
: [ 'VM/CT' , gettext ( 'Console' ) + ' (Spice)' ],
530 vncshell
: [ '' , gettext ( 'Shell' ) ],
531 spiceshell
: [ '' , gettext ( 'Shell' ) + ' (Spice)' ],
532 qmsnapshot
: [ 'VM' , gettext ( 'Snapshot' ) ],
533 qmrollback
: [ 'VM' , gettext ( 'Rollback' ) ],
534 qmdelsnapshot
: [ 'VM' , gettext ( 'Delete Snapshot' ) ],
535 qmcreate
: [ 'VM' , gettext ( 'Create' ) ],
536 qmrestore
: [ 'VM' , gettext ( 'Restore' ) ],
537 qmdestroy
: [ 'VM' , gettext ( 'Destroy' ) ],
538 qmigrate
: [ 'VM' , gettext ( 'Migrate' ) ],
539 qmclone
: [ 'VM' , gettext ( 'Clone' ) ],
540 qmmove
: [ 'VM' , gettext ( 'Move disk' ) ],
541 qmtemplate
: [ 'VM' , gettext ( 'Convert to template' ) ],
542 qmstart
: [ 'VM' , gettext ( 'Start' ) ],
543 qmstop
: [ 'VM' , gettext ( 'Stop' ) ],
544 qmreset
: [ 'VM' , gettext ( 'Reset' ) ],
545 qmshutdown
: [ 'VM' , gettext ( 'Shutdown' ) ],
546 qmsuspend
: [ 'VM' , gettext ( 'Suspend' ) ],
547 qmresume
: [ 'VM' , gettext ( 'Resume' ) ],
548 qmconfig
: [ 'VM' , gettext ( 'Configure' ) ],
549 vzcreate
: [ 'CT' , gettext ( 'Create' ) ],
550 vzrestore
: [ 'CT' , gettext ( 'Restore' ) ],
551 vzdestroy
: [ 'CT' , gettext ( 'Destroy' ) ],
552 vzmigrate
: [ 'CT' , gettext ( 'Migrate' ) ],
553 vzstart
: [ 'CT' , gettext ( 'Start' ) ],
554 vzstop
: [ 'CT' , gettext ( 'Stop' ) ],
555 vzmount
: [ 'CT' , gettext ( 'Mount' ) ],
556 vzumount
: [ 'CT' , gettext ( 'Unmount' ) ],
557 vzshutdown
: [ 'CT' , gettext ( 'Shutdown' ) ],
558 vzsuspend
: [ 'CT' , gettext ( 'Suspend' ) ],
559 vzresume
: [ 'CT' , gettext ( 'Resume' ) ],
560 vzsnapshot
: [ 'CT' , gettext ( 'Snapshot' ) ],
561 vzrollback
: [ 'CT' , gettext ( 'Rollback' ) ],
562 vzdelsnapshot
: [ 'CT' , gettext ( 'Delete Snapshot' ) ],
563 vztemplate
: [ 'CT' , gettext ( 'Convert to template' ) ],
564 vzclone
: [ 'CT' , gettext ( 'Clone' ) ],
565 hamigrate
: [ 'HA' , gettext ( 'Migrate' ) ],
566 hastart
: [ 'HA' , gettext ( 'Start' ) ],
567 hastop
: [ 'HA' , gettext ( 'Stop' ) ],
568 srvstart
: [ 'SRV' , gettext ( 'Start' ) ],
569 srvstop
: [ 'SRV' , gettext ( 'Stop' ) ],
570 srvrestart
: [ 'SRV' , gettext ( 'Restart' ) ],
571 srvreload
: [ 'SRV' , gettext ( 'Reload' ) ],
572 cephcreatemon
: [ 'Ceph Monitor' , gettext ( 'Create' ) ],
573 cephdestroymon
: [ 'Ceph Monitor' , gettext ( 'Destroy' ) ],
574 cephcreateosd
: [ 'Ceph OSD' , gettext ( 'Create' ) ],
575 cephdestroyosd
: [ 'Ceph OSD' , gettext ( 'Destroy' ) ],
576 imgcopy
: [ '' , gettext ( 'Copy data' ) ],
577 imgdel
: [ '' , gettext ( 'Erase data' ) ],
578 download
: [ '' , gettext ( 'Download' ) ],
579 vzdump
: [ '' , gettext ( 'Backup' ) ],
580 aptupdate
: [ '' , gettext ( 'Update package database' ) ],
581 startall
: [ '' , gettext ( 'Start all VMs and Containers' ) ],
582 stopall
: [ '' , gettext ( 'Stop all VMs and Containers' ) ],
583 migrateall
: [ '' , gettext ( 'Migrate all VMs and Containers' ) ]
586 format_task_description : function ( type
, id
) {
587 var farray
= PVE
. Utils
. task_desc_table
[ type
];
591 var prefix
= farray
[ 0 ];
592 var text
= farray
[ 1 ];
594 return prefix
+ ' ' + id
+ ' - ' + text
;
599 parse_task_upid : function ( upid
) {
602 var res
= upid
. match ( /^UPID:(\S+):([0-9A-Fa-f]{8}):([0-9A-Fa-f]{8,9}):([0-9A-Fa-f]{8}):([^:\s]+):([^:\s]*):([^:\s]+):$/ );
604 throw "unable to parse upid '" + upid
+ "'" ;
607 task
. pid
= parseInt ( res
[ 2 ], 16 );
608 task
. pstart
= parseInt ( res
[ 3 ], 16 );
609 task
. starttime
= parseInt ( res
[ 4 ], 16 );
614 task
. desc
= PVE
. Utils
. format_task_description ( task
. type
, task
. id
);
619 format_size : function ( size
) {
620 /*jslint confusion: true */
626 var kb
= size
/ 1024 ;
629 return kb
. toFixed ( 0 ) + "KB" ;
632 var mb
= size
/ ( 1024 * 1024 );
635 return mb
. toFixed ( 0 ) + "MB" ;
641 return gb
. toFixed ( 2 ) + "GB" ;
646 return tb
. toFixed ( 2 ) + "TB" ;
650 format_html_bar : function ( per
, text
) {
652 return "<div class='pve-bar-wrap'>" + text
+ "<div class='pve-bar-border'>" +
653 "<div class='pve-bar-inner' style='width:" + per
+ "%;'></div>" +
658 format_cpu_bar : function ( per1
, per2
, text
) {
660 return "<div class='pve-bar-border'>" +
661 "<div class='pve-bar-inner' style='width:" + per1
+ "%;'></div>" +
662 "<div class='pve-bar-inner2' style='width:" + per2
+ "%;'></div>" +
663 "<div class='pve-bar-text'>" + text
+ "</div>" +
667 format_large_bar : function ( per
, text
) {
670 text
= per
. toFixed ( 1 ) + "%" ;
673 return "<div class='pve-largebar-border'>" +
674 "<div class='pve-largebar-inner' style='width:" + per
+ "%;'></div>" +
675 "<div class='pve-largebar-text'>" + text
+ "</div>" +
679 format_duration_long : function ( ut
) {
681 var days
= Math
. floor ( ut
/ 86400 );
683 var hours
= Math
. floor ( ut
/ 3600 );
685 var mins
= Math
. floor ( ut
/ 60 );
688 var hours_str
= '00' + hours
. toString ();
689 hours_str
= hours_str
. substr ( hours_str
. length
- 2 );
690 var mins_str
= "00" + mins
. toString ();
691 mins_str
= mins_str
. substr ( mins_str
. length
- 2 );
692 var ut_str
= "00" + ut
. toString ();
693 ut_str
= ut_str
. substr ( ut_str
. length
- 2 );
696 var ds
= days
> 1 ? PVE
. Utils
. daysText
: PVE
. Utils
. dayText
;
697 return days
. toString () + ' ' + ds
+ ' ' +
698 hours_str
+ ':' + mins_str
+ ':' + ut_str
;
700 return hours_str
+ ':' + mins_str
+ ':' + ut_str
;
704 format_duration_short : function ( ut
) {
707 return ut
. toString () + 's' ;
712 return mins
. toFixed ( 0 ) + 'm' ;
716 var hours
= ut
/ 3600 ;
717 return hours
. toFixed ( 0 ) + 'h' ;
720 var days
= ut
/ 86400 ;
721 return days
. toFixed ( 0 ) + 'd' ;
724 yesText
: gettext ( 'Yes' ),
725 noText
: gettext ( 'No' ),
726 noneText
: gettext ( 'none' ),
727 errorText
: gettext ( 'Error' ),
728 unknownText
: gettext ( 'Unknown' ),
729 defaultText
: gettext ( 'Default' ),
730 daysText
: gettext ( 'days' ),
731 dayText
: gettext ( 'day' ),
732 runningText
: gettext ( 'running' ),
733 stoppedText
: gettext ( 'stopped' ),
734 neverText
: gettext ( 'never' ),
735 totalText
: gettext ( 'Total' ),
736 usedText
: gettext ( 'Used' ),
737 directoryText
: gettext ( 'Directory' ),
738 imagesText
: gettext ( 'Disk image' ),
739 backupFileText
: gettext ( 'VZDump backup file' ),
740 vztmplText
: gettext ( 'Container template' ),
741 isoImageText
: gettext ( 'ISO image' ),
742 containersText
: gettext ( 'Container' ),
744 format_expire : function ( date
) {
746 return PVE
. Utils
. neverText
;
748 return Ext
. Date
. format ( date
, "Y-m-d" );
751 format_storage_type : function ( value
) {
752 if ( value
=== 'dir' ) {
753 return PVE
. Utils
. directoryText
;
754 } else if ( value
=== 'nfs' ) {
756 } else if ( value
=== 'glusterfs' ) {
758 } else if ( value
=== 'lvm' ) {
760 } else if ( value
=== 'lvmthin' ) {
762 } else if ( value
=== 'iscsi' ) {
764 } else if ( value
=== 'rbd' ) {
766 } else if ( value
=== 'sheepdog' ) {
768 } else if ( value
=== 'zfs' ) {
769 return 'ZFS over iSCSI' ;
770 } else if ( value
=== 'zfspool' ) {
772 } else if ( value
=== 'iscsidirect' ) {
773 return 'iSCSIDirect' ;
774 } else if ( value
=== 'drbd' ) {
777 return PVE
. Utils
. unknownText
;
781 format_boolean_with_default : function ( value
) {
782 if ( Ext
. isDefined ( value
) && value
!== '' ) {
783 return value
? PVE
. Utils
. yesText
: PVE
. Utils
. noText
;
785 return PVE
. Utils
. defaultText
;
788 format_boolean : function ( value
) {
789 return value
? PVE
. Utils
. yesText
: PVE
. Utils
. noText
;
792 format_neg_boolean : function ( value
) {
793 return ! value
? PVE
. Utils
. yesText
: PVE
. Utils
. noText
;
796 format_content_types : function ( value
) {
799 Ext
. each ( value
. split ( ',' ). sort (), function ( ct
) {
800 if ( ct
=== 'images' ) {
801 cta
. push ( PVE
. Utils
. imagesText
);
802 } else if ( ct
=== 'backup' ) {
803 cta
. push ( PVE
. Utils
. backupFileText
);
804 } else if ( ct
=== 'vztmpl' ) {
805 cta
. push ( PVE
. Utils
. vztmplText
);
806 } else if ( ct
=== 'iso' ) {
807 cta
. push ( PVE
. Utils
. isoImageText
);
808 } else if ( ct
=== 'rootdir' ) {
809 cta
. push ( PVE
. Utils
. containersText
);
813 return cta
. join ( ', ' );
816 render_storage_content : function ( value
, metaData
, record
) {
817 var data
= record
. data
;
818 if ( Ext
. isNumber ( data
. channel
) &&
819 Ext
. isNumber ( data
. id
) &&
820 Ext
. isNumber ( data
. lun
)) {
822 Ext
. String
. leftPad ( data
. channel
, 2 , '0' ) +
823 " ID " + data
. id
+ " LUN " + data
. lun
;
825 return data
. volid
. replace ( /^.*:(.*\/)?/ , '' );
828 render_serverity : function ( value
) {
829 return PVE
. Utils
. log_severity_hash
[ value
] || value
;
832 render_cpu : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
834 if (!( record
. data
. uptime
&& Ext
. isNumeric ( value
))) {
838 var maxcpu
= record
. data
. maxcpu
|| 1 ;
840 if (! Ext
. isNumeric ( maxcpu
) && ( maxcpu
>= 1 )) {
844 var per
= value
* 100 ;
846 return per
. toFixed ( 1 ) + '% of ' + maxcpu
. toString () + ( maxcpu
> 1 ? 'CPUs' : 'CPU' );
849 render_size : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
850 /*jslint confusion: true */
852 if (! Ext
. isNumeric ( value
)) {
856 return PVE
. Utils
. format_size ( value
);
859 render_timestamp : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
860 var servertime
= new Date ( value
* 1000 );
861 return Ext
. Date
. format ( servertime
, 'Y-m-d H:i:s' );
864 render_mem_usage : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
867 var maxmem
= record
. data
. maxmem
;
869 if (! record
. data
. uptime
) {
873 if (!( Ext
. isNumeric ( mem
) && maxmem
)) {
877 var per
= ( mem
* 100 ) / maxmem
;
879 return per
. toFixed ( 1 ) + '%' ;
882 render_disk_usage : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
885 var maxdisk
= record
. data
. maxdisk
;
887 if (!( Ext
. isNumeric ( disk
) && maxdisk
)) {
891 var per
= ( disk
* 100 ) / maxdisk
;
893 return per
. toFixed ( 1 ) + '%' ;
896 render_resource_type : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
898 var cls
= 'pve-itype-icon-' + value
;
900 if ( record
. data
. running
) {
901 metaData
. tdCls
= cls
+ "-running" ;
902 } else if ( record
. data
. template
) {
903 metaData
. tdCls
= cls
+ "-template" ;
905 metaData
. tdCls
= cls
;
911 render_uptime : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
915 if ( uptime
=== undefined ) {
923 return PVE
. Utils
. format_duration_long ( uptime
);
926 render_support_level : function ( value
, metaData
, record
) {
927 return PVE
. Utils
. support_level_hash
[ value
] || '-' ;
930 render_upid : function ( value
, metaData
, record
) {
931 var type
= record
. data
. type
;
932 var id
= record
. data
. id
;
934 return PVE
. Utils
. format_task_description ( type
, id
);
937 dialog_title : function ( subject
, create
, isAdd
) {
940 return gettext ( 'Add' ) + ': ' + subject
;
942 return gettext ( 'Create' ) + ': ' + subject
;
945 return gettext ( 'Edit' ) + ': ' + subject
;
949 windowHostname : function () {
950 return window
. location
. hostname
. replace ( IP6_bracket_match
,
951 function ( m
, addr
, offset
, original
) { return addr
; });
954 openDefaultConsoleWindow : function ( allowSpice
, vmtype
, vmid
, nodename
, vmname
) {
955 var dv
= PVE
. Utils
. defaultViewer ( allowSpice
);
956 PVE
. Utils
. openConsoleWindow ( dv
, vmtype
, vmid
, nodename
, vmname
);
959 openConsoleWindow : function ( viewer
, vmtype
, vmid
, nodename
, vmname
) {
960 // kvm, lxc, shell, upgrade
962 if ( vmid
== undefined && ( vmtype
=== 'kvm' || vmtype
=== 'lxc' )) {
963 throw "missing vmid" ;
967 throw "no nodename specified" ;
970 if ( viewer
=== 'applet' || viewer
=== 'html5' ) {
971 PVE
. Utils
. openVNCViewer ( vmtype
, vmid
, nodename
, vmname
, true );
972 } else if ( viewer
=== 'vv' ) {
974 var params
= { proxy
: PVE
. Utils
. windowHostname () };
975 if ( vmtype
=== 'kvm' ) {
976 url
= '/nodes/' + nodename
+ '/qemu/' + vmid
. toString () + '/spiceproxy' ;
977 PVE
. Utils
. openSpiceViewer ( url
, params
);
978 } else if ( vmtype
=== 'lxc' ) {
979 url
= '/nodes/' + nodename
+ '/lxc/' + vmid
. toString () + '/spiceproxy' ;
980 PVE
. Utils
. openSpiceViewer ( url
, params
);
981 } else if ( vmtype
=== 'shell' ) {
982 url
= '/nodes/' + nodename
+ '/spiceshell' ;
983 PVE
. Utils
. openSpiceViewer ( url
, params
);
984 } else if ( vmtype
=== 'upgrade' ) {
985 url
= '/nodes/' + nodename
+ '/spiceshell' ;
987 PVE
. Utils
. openSpiceViewer ( url
, params
);
990 throw "unknown viewer type" ;
994 defaultViewer : function ( allowSpice
) {
995 var vncdefault
= 'html5' ;
996 var dv
= PVE
. VersionInfo
. console
|| vncdefault
;
997 if ( dv
=== 'vv' && ! allowSpice
) {
1004 openVNCViewer : function ( vmtype
, vmid
, nodename
, vmname
, novnc
) {
1005 var url
= Ext
. urlEncode ({
1006 console
: vmtype
, // kvm, lxc, upgrade or shell
1007 novnc
: novnc
? 1 : 0 ,
1012 var nw
= window
. open ( "?" + url
, '_blank' , "innerWidth=745,innerheight=427" );
1016 openSpiceViewer : function ( url
, params
){
1018 var downloadWithName = function ( uri
, name
) {
1019 var link
= Ext
. DomHelper
. append ( document
. body
, {
1022 css
: 'display:none;visibility:hidden;height:0px;'
1025 // Note: we need to tell android the correct file name extension
1026 // but we do not set 'download' tag for other environments, because
1027 // It can have strange side effects (additional user prompt on firefox)
1028 var andriod
= navigator
. userAgent
. match ( /Android/i ) ? true : false ;
1030 link
. download
= name
;
1033 if ( link
. fireEvent
) {
1034 link
. fireEvent ( 'onclick' );
1036 var evt
= document
. createEvent ( "MouseEvents" );
1037 evt
. initMouseEvent ( 'click' , true , true , window
, 1 , 0 , 0 , 0 , 0 , false , false , false , false , 0 , null );
1038 link
. dispatchEvent ( evt
);
1042 PVE
. Utils
. API2Request ({
1046 failure : function ( response
, opts
){
1047 Ext
. Msg
. alert ( 'Error' , response
. htmlStatus
);
1049 success : function ( response
, opts
){
1050 var raw
= "[virt-viewer] \n " ;
1051 Ext
. Object
. each ( response
. result
. data
, function ( k
, v
) {
1052 raw
+= k
+ "=" + v
+ " \n " ;
1054 var url
= 'data:application/x-virt-viewer;charset=UTF-8,' +
1055 encodeURIComponent ( raw
);
1057 downloadWithName ( url
, "pve-spice.vv" );
1062 // comp.setLoading() is buggy in ExtJS 4.0.7, so we
1063 // use el.mask() instead
1064 setErrorMask : function ( comp
, msg
) {
1073 el
. mask ( gettext ( "Loading..." ));
1080 monStoreErrors : function ( me
, store
) {
1081 me
. mon ( store
, 'beforeload' , function ( s
, operation
, eOpts
) {
1082 if (! me
. loadCount
) {
1083 me
. loadCount
= 0 ; // make sure it is numeric
1084 PVE
. Utils
. setErrorMask ( me
, true );
1088 // only works with 'pve' proxy
1089 me
. mon ( store
. proxy
, 'afterload' , function ( proxy
, request
, success
) {
1093 PVE
. Utils
. setErrorMask ( me
, false );
1098 var operation
= request
. operation
;
1099 var error
= operation
. getError ();
1100 if ( error
. statusText
) {
1101 msg
= error
. statusText
+ ' (' + error
. status
+ ')' ;
1103 msg
= gettext ( 'Connection error' );
1105 PVE
. Utils
. setErrorMask ( me
, msg
);