]>
git.proxmox.com Git - pve-manager.git/blob - www/manager6/Utils.js
3 // avoid errors related to Accessible Rich Internet Applications
4 // (access for people with disabilities)
5 // TODO reenable after all components are upgraded
6 Ext
. enableAria
= false ;
7 Ext
. enableAriaButtons
= false ;
8 Ext
. enableAriaPanels
= false ;
10 // avoid errors when running without development tools
11 if (! Ext
. isDefined ( Ext
. global
. console
)) {
17 console
. log ( "Starting PVE Manager" );
19 Ext
. Ajax
. defaultHeaders
= {
20 'Accept' : 'application/json'
23 Ext
. Ajax
. on ( 'beforerequest' , function ( conn
, options
) {
24 if ( PVE
. CSRFPreventionToken
) {
25 if (! options
. headers
) {
28 options
. headers
. CSRFPreventionToken
= PVE
. CSRFPreventionToken
;
32 Ext
. define ( 'PVE.Utils' , { utilities
: {
34 // this singleton contains miscellaneous utilities
36 toolkit
: undefined , // (extjs|touch), set inside Toolkit.js
38 bus_match
: /^(ide|sata|virtio|scsi)\d+$/ ,
52 'c' : gettext ( 'Community' ),
53 'b' : gettext ( 'Basic' ),
54 's' : gettext ( 'Standard' ),
55 'p' : gettext ( 'Premium' )
58 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.' ,
62 { desc
: '4.X/3.X/2.6 Kernel' , val
: 'l26' },
63 { desc
: '2.4 Kernel' , val
: 'l24' }
65 'Microsoft Windows' : [
66 { desc
: '10/2016' , val
: 'win10' },
67 { desc
: '8.x/2012/2012r2' , val
: 'win8' },
68 { desc
: '7/2008r2' , val
: 'win7' },
69 { desc
: 'Vista/2008' , val
: 'w2k8' },
70 { desc
: 'XP/2003' , val
: 'wxp' },
71 { desc
: '2000' , val
: 'w2k' }
74 { desc
: '-' , val
: 'solaris' }
77 { desc
: '-' , val
: 'other' }
81 get_health_icon : function ( state
, circle
) {
82 if ( circle
=== undefined ) {
86 if ( state
=== undefined ) {
90 var icon
= 'faded fa-question' ;
93 icon
= 'good fa-check' ;
96 icon
= 'warning fa-exclamation' ;
99 icon
= 'critical fa-times' ;
113 'HEALTH_WARN' : 'warning' ,
114 'HEALTH_ERR' : 'critical'
117 render_ceph_health : function ( healthObj
) {
119 iconCls
: PVE
. Utils
. get_health_icon (),
123 if (! healthObj
|| ! healthObj
. status
) {
127 var health
= PVE
. Utils
. map_ceph_health
[ healthObj
. status
];
129 state
. iconCls
= PVE
. Utils
. get_health_icon ( health
, true );
130 state
. text
= healthObj
. status
;
135 get_kvm_osinfo : function ( value
) {
136 var info
= { base
: 'Other' }; // default
138 Ext
. each ( Object
. keys ( PVE
. Utils
. kvm_ostypes
), function ( k
) {
139 Ext
. each ( PVE
. Utils
. kvm_ostypes
[ k
], function ( e
) {
140 if ( e
. val
=== value
) {
141 info
= { desc
: e
. desc
, base
: k
};
149 render_kvm_ostype : function ( value
) {
150 var osinfo
= PVE
. Utils
. get_kvm_osinfo ( value
);
151 if ( osinfo
. desc
&& osinfo
. desc
!== '-' ) {
152 return osinfo
. base
+ ' ' + osinfo
. desc
;
158 render_hotplug_features : function ( value
) {
161 if (! value
|| ( value
=== '0' )) {
162 return gettext ( 'Disabled' );
166 value
= 'disk,network,usb' ;
169 Ext
. each ( value
. split ( ',' ), function ( el
) {
171 fa
. push ( gettext ( 'Disk' ));
172 } else if ( el
=== 'network' ) {
173 fa
. push ( gettext ( 'Network' ));
174 } else if ( el
=== 'usb' ) {
176 } else if ( el
=== 'memory' ) {
177 fa
. push ( gettext ( 'Memory' ));
178 } else if ( el
=== 'cpu' ) {
179 fa
. push ( gettext ( 'CPU' ));
185 return fa
. join ( ', ' );
188 network_iface_types
: {
189 eth
: gettext ( "Network Device" ),
190 bridge
: 'Linux Bridge' ,
192 OVSBridge
: 'OVS Bridge' ,
195 OVSIntPort
: 'OVS IntPort'
198 render_network_iface_type : function ( value
) {
199 return PVE
. Utils
. network_iface_types
[ value
] ||
200 PVE
. Utils
. unknownText
;
203 render_qemu_bios : function ( value
) {
205 return PVE
. Utils
. defaultText
+ ' (SeaBIOS)' ;
206 } else if ( value
=== 'seabios' ) {
208 } else if ( value
=== 'ovmf' ) {
209 return "OVMF (UEFI)" ;
215 render_scsihw : function ( value
) {
217 return PVE
. Utils
. defaultText
+ ' (LSI 53C895A)' ;
218 } else if ( value
=== 'lsi' ) {
219 return 'LSI 53C895A' ;
220 } else if ( value
=== 'lsi53c810' ) {
222 } else if ( value
=== 'megasas' ) {
223 return 'MegaRAID SAS 8708EM2' ;
224 } else if ( value
=== 'virtio-scsi-pci' ) {
225 return 'VirtIO SCSI' ;
226 } else if ( value
=== 'virtio-scsi-single' ) {
227 return 'VirtIO SCSI single' ;
228 } else if ( value
=== 'pvscsi' ) {
229 return 'VMware PVSCSI' ;
235 // fixme: auto-generate this
236 // for now, please keep in sync with PVE::Tools::kvmkeymaps
241 'de-ch' : 'German (Swiss)' ,
242 'en-gb' : 'English (UK)' ,
243 'en-us' : 'English (USA)' ,
247 //fo: 'Faroe Islands',
249 'fr-be' : 'French (Belgium)' ,
250 'fr-ca' : 'French (Canada)' ,
251 'fr-ch' : 'French (Swiss)' ,
261 //'nl-be': 'Dutch (Belgium)',
265 'pt-br' : 'Portuguese (Brazil)' ,
274 std
: gettext ( 'Standard VGA' ),
275 vmware
: gettext ( 'VMware compatible' ),
277 qxl2
: 'SPICE dual monitor' ,
278 qxl3
: 'SPICE three monitors' ,
279 qxl4
: 'SPICE four monitors' ,
280 serial0
: gettext ( 'Serial terminal' ) + ' 0' ,
281 serial1
: gettext ( 'Serial terminal' ) + ' 1' ,
282 serial2
: gettext ( 'Serial terminal' ) + ' 2' ,
283 serial3
: gettext ( 'Serial terminal' ) + ' 3'
286 render_kvm_language : function ( value
) {
288 return PVE
. Utils
. defaultText
;
290 var text
= PVE
. Utils
. kvm_keymaps
[ value
];
292 return text
+ ' (' + value
+ ')' ;
297 kvm_keymap_array : function () {
298 var data
= [[ '__default__' , PVE
. Utils
. render_kvm_language ( '' )]];
299 Ext
. Object
. each ( PVE
. Utils
. kvm_keymaps
, function ( key
, value
) {
300 data
. push ([ key
, PVE
. Utils
. render_kvm_language ( value
)]);
306 render_console_viewer : function ( value
) {
307 if (! value
|| value
=== '__default__' ) {
308 return PVE
. Utils
. defaultText
+ ' (HTML5)' ;
309 } else if ( value
=== 'vv' ) {
310 return 'SPICE (remote-viewer)' ;
311 } else if ( value
=== 'html5' ) {
312 return 'HTML5 (noVNC)' ;
323 eu
: 'Euskera (Basque)' ,
328 nb
: 'Norwegian (Bokmal)' ,
329 nn
: 'Norwegian (Nynorsk)' ,
330 fa
: 'Persian (Farsi)' ,
332 pt_BR
: 'Portuguese (Brazil)' ,
340 render_language : function ( value
) {
342 return PVE
. Utils
. defaultText
+ ' (English)' ;
344 var text
= PVE
. Utils
. language_map
[ value
];
346 return text
+ ' (' + value
+ ')' ;
351 language_array : function () {
352 var data
= [[ '__default__' , PVE
. Utils
. render_language ( '' )]];
353 Ext
. Object
. each ( PVE
. Utils
. language_map
, function ( key
, value
) {
354 data
. push ([ key
, PVE
. Utils
. render_language ( value
)]);
360 render_kvm_vga_driver : function ( value
) {
362 return PVE
. Utils
. defaultText
;
364 var text
= PVE
. Utils
. kvm_vga_drivers
[ value
];
366 return text
+ ' (' + value
+ ')' ;
371 kvm_vga_driver_array : function () {
372 var data
= [[ '__default__' , PVE
. Utils
. render_kvm_vga_driver ( '' )]];
373 Ext
. Object
. each ( PVE
. Utils
. kvm_vga_drivers
, function ( key
, value
) {
374 data
. push ([ key
, PVE
. Utils
. render_kvm_vga_driver ( value
)]);
380 render_kvm_startup : function ( value
) {
381 var startup
= PVE
. Parser
. parseStartup ( value
);
384 if ( startup
. order
=== undefined ) {
387 res
+= startup
. order
;
389 if ( startup
. up
!== undefined ) {
390 res
+= ',up=' + startup
. up
;
392 if ( startup
. down
!== undefined ) {
393 res
+= ',down=' + startup
. down
;
400 return Ext
. util
. Cookies
. get ( 'PVEAuthCookie' );
403 authClear : function () {
404 Ext
. util
. Cookies
. clear ( "PVEAuthCookie" );
407 // fixme: remove - not needed?
408 gridLineHeigh : function () {
416 extractRequestError : function ( result
, verbose
) {
417 var msg
= gettext ( 'Successful' );
419 if (! result
. success
) {
420 msg
= gettext ( "Unknown error" );
421 if ( result
. message
) {
422 msg
= result
. message
;
424 msg
+= ' (' + result
. status
+ ')' ;
427 if ( verbose
&& Ext
. isObject ( result
. errors
)) {
429 Ext
. Object
. each ( result
. errors
, function ( prop
, desc
) {
430 msg
+= "<br><b>" + Ext
. htmlEncode ( prop
) + "</b>: " +
431 Ext
. htmlEncode ( desc
);
439 extractFormActionError : function ( action
) {
441 switch ( action
. failureType
) {
442 case Ext
. form
. action
. Action
. CLIENT_INVALID
:
443 msg
= gettext ( 'Form fields may not be submitted with invalid values' );
445 case Ext
. form
. action
. Action
. CONNECT_FAILURE
:
446 msg
= gettext ( 'Connection error' );
447 var resp
= action
. response
;
448 if ( resp
. status
&& resp
. statusText
) {
449 msg
+= " " + resp
. status
+ ": " + resp
. statusText
;
452 case Ext
. form
. action
. Action
. LOAD_FAILURE
:
453 case Ext
. form
. action
. Action
. SERVER_INVALID
:
454 msg
= PVE
. Utils
. extractRequestError ( action
. result
, true );
461 API2Request : function ( reqOpts
) {
463 var newopts
= Ext
. apply ({
464 waitMsg
: gettext ( 'Please wait...' )
467 if (! newopts
. url
. match ( /^\/api2/ )) {
468 newopts
. url
= '/api2/extjs' + newopts
. url
;
470 delete newopts
. callback
;
472 var createWrapper = function ( successFn
, callbackFn
, failureFn
) {
474 success : function ( response
, options
) {
475 if ( options
. waitMsgTarget
) {
476 if ( PVE
. Utils
. toolkit
=== 'touch' ) {
477 options
. waitMsgTarget
. setMasked ( false );
479 options
. waitMsgTarget
. setLoading ( false );
482 var result
= Ext
. decode ( response
. responseText
);
483 response
. result
= result
;
484 if (! result
. success
) {
485 response
. htmlStatus
= PVE
. Utils
. extractRequestError ( result
, true );
486 Ext
. callback ( callbackFn
, options
. scope
, [ options
, false , response
]);
487 Ext
. callback ( failureFn
, options
. scope
, [ response
, options
]);
490 Ext
. callback ( callbackFn
, options
. scope
, [ options
, true , response
]);
491 Ext
. callback ( successFn
, options
. scope
, [ response
, options
]);
493 failure : function ( response
, options
) {
494 if ( options
. waitMsgTarget
) {
495 if ( PVE
. Utils
. toolkit
=== 'touch' ) {
496 options
. waitMsgTarget
. setMasked ( false );
498 options
. waitMsgTarget
. setLoading ( false );
501 response
. result
= {};
503 response
. result
= Ext
. decode ( response
. responseText
);
505 var msg
= gettext ( 'Connection error' ) + ' - server offline?' ;
506 if ( response
. aborted
) {
507 msg
= gettext ( 'Connection error' ) + ' - aborted.' ;
508 } else if ( response
. timedout
) {
509 msg
= gettext ( 'Connection error' ) + ' - Timeout.' ;
510 } else if ( response
. status
&& response
. statusText
) {
511 msg
= gettext ( 'Connection error' ) + ' ' + response
. status
+ ': ' + response
. statusText
;
513 response
. htmlStatus
= msg
;
514 Ext
. callback ( callbackFn
, options
. scope
, [ options
, false , response
]);
515 Ext
. callback ( failureFn
, options
. scope
, [ response
, options
]);
520 createWrapper ( reqOpts
. success
, reqOpts
. callback
, reqOpts
. failure
);
522 var target
= newopts
. waitMsgTarget
;
524 if ( PVE
. Utils
. toolkit
=== 'touch' ) {
525 target
. setMasked ({ xtype
: 'loadmask' , message
: newopts
. waitMsg
} );
527 // Note: ExtJS bug - this does not work when component is not rendered
528 target
. setLoading ( newopts
. waitMsg
);
531 Ext
. Ajax
. request ( newopts
);
534 assemble_field_data : function ( values
, data
) {
535 if ( Ext
. isObject ( data
)) {
536 Ext
. Object
. each ( data
, function ( name
, val
) {
537 if ( values
. hasOwnProperty ( name
)) {
538 var bucket
= values
[ name
];
539 if (! Ext
. isArray ( bucket
)) {
540 bucket
= values
[ name
] = [ bucket
];
542 if ( Ext
. isArray ( val
)) {
543 values
[ name
] = bucket
. concat ( val
);
554 checked_command : function ( orig_cmd
) {
555 PVE
. Utils
. API2Request ({
556 url
: '/nodes/localhost/subscription' ,
559 failure : function ( response
, opts
) {
560 Ext
. Msg
. alert ( gettext ( 'Error' ), response
. htmlStatus
);
562 success : function ( response
, opts
) {
563 var data
= response
. result
. data
;
565 if ( data
. status
!== 'Active' ) {
567 title
: gettext ( 'No valid subscription' ),
568 icon
: Ext
. Msg
. WARNING
,
569 msg
: PVE
. Utils
. noSubKeyHtml
,
571 callback : function ( btn
) {
586 diskinit
: [ 'Disk' , gettext ( 'Initialize Disk with GPT' ) ],
587 vncproxy
: [ 'VM/CT' , gettext ( 'Console' ) ],
588 spiceproxy
: [ 'VM/CT' , gettext ( 'Console' ) + ' (Spice)' ],
589 vncshell
: [ '' , gettext ( 'Shell' ) ],
590 spiceshell
: [ '' , gettext ( 'Shell' ) + ' (Spice)' ],
591 qmsnapshot
: [ 'VM' , gettext ( 'Snapshot' ) ],
592 qmrollback
: [ 'VM' , gettext ( 'Rollback' ) ],
593 qmdelsnapshot
: [ 'VM' , gettext ( 'Delete Snapshot' ) ],
594 qmcreate
: [ 'VM' , gettext ( 'Create' ) ],
595 qmrestore
: [ 'VM' , gettext ( 'Restore' ) ],
596 qmdestroy
: [ 'VM' , gettext ( 'Destroy' ) ],
597 qmigrate
: [ 'VM' , gettext ( 'Migrate' ) ],
598 qmclone
: [ 'VM' , gettext ( 'Clone' ) ],
599 qmmove
: [ 'VM' , gettext ( 'Move disk' ) ],
600 qmtemplate
: [ 'VM' , gettext ( 'Convert to template' ) ],
601 qmstart
: [ 'VM' , gettext ( 'Start' ) ],
602 qmstop
: [ 'VM' , gettext ( 'Stop' ) ],
603 qmreset
: [ 'VM' , gettext ( 'Reset' ) ],
604 qmshutdown
: [ 'VM' , gettext ( 'Shutdown' ) ],
605 qmsuspend
: [ 'VM' , gettext ( 'Suspend' ) ],
606 qmresume
: [ 'VM' , gettext ( 'Resume' ) ],
607 qmconfig
: [ 'VM' , gettext ( 'Configure' ) ],
608 vzsnapshot
: [ 'CT' , gettext ( 'Snapshot' ) ],
609 vzrollback
: [ 'CT' , gettext ( 'Rollback' ) ],
610 vzdelsnapshot
: [ 'CT' , gettext ( 'Delete Snapshot' ) ],
611 vzcreate
: [ 'CT' , gettext ( 'Create' ) ],
612 vzrestore
: [ 'CT' , gettext ( 'Restore' ) ],
613 vzdestroy
: [ 'CT' , gettext ( 'Destroy' ) ],
614 vzmigrate
: [ 'CT' , gettext ( 'Migrate' ) ],
615 vzclone
: [ 'CT' , gettext ( 'Clone' ) ],
616 vztemplate
: [ 'CT' , gettext ( 'Convert to template' ) ],
617 vzstart
: [ 'CT' , gettext ( 'Start' ) ],
618 vzstop
: [ 'CT' , gettext ( 'Stop' ) ],
619 vzmount
: [ 'CT' , gettext ( 'Mount' ) ],
620 vzumount
: [ 'CT' , gettext ( 'Unmount' ) ],
621 vzshutdown
: [ 'CT' , gettext ( 'Shutdown' ) ],
622 vzsuspend
: [ 'CT' , gettext ( 'Suspend' ) ],
623 vzresume
: [ 'CT' , gettext ( 'Resume' ) ],
624 hamigrate
: [ 'HA' , gettext ( 'Migrate' ) ],
625 hastart
: [ 'HA' , gettext ( 'Start' ) ],
626 hastop
: [ 'HA' , gettext ( 'Stop' ) ],
627 srvstart
: [ 'SRV' , gettext ( 'Start' ) ],
628 srvstop
: [ 'SRV' , gettext ( 'Stop' ) ],
629 srvrestart
: [ 'SRV' , gettext ( 'Restart' ) ],
630 srvreload
: [ 'SRV' , gettext ( 'Reload' ) ],
631 cephcreatemon
: [ 'Ceph Monitor' , gettext ( 'Create' ) ],
632 cephdestroymon
: [ 'Ceph Monitor' , gettext ( 'Destroy' ) ],
633 cephcreateosd
: [ 'Ceph OSD' , gettext ( 'Create' ) ],
634 cephdestroyosd
: [ 'Ceph OSD' , gettext ( 'Destroy' ) ],
635 cephcreatepool
: [ 'Ceph Pool' , gettext ( 'Create' ) ],
636 cephdestroypool
: [ 'Ceph Pool' , gettext ( 'Destroy' ) ],
637 imgcopy
: [ '' , gettext ( 'Copy data' ) ],
638 imgdel
: [ '' , gettext ( 'Erase data' ) ],
639 download
: [ '' , gettext ( 'Download' ) ],
640 vzdump
: [ '' , gettext ( 'Backup' ) ],
641 aptupdate
: [ '' , gettext ( 'Update package database' ) ],
642 startall
: [ '' , gettext ( 'Start all VMs and Containers' ) ],
643 stopall
: [ '' , gettext ( 'Stop all VMs and Containers' ) ],
644 migrateall
: [ '' , gettext ( 'Migrate all VMs and Containers' ) ]
647 format_task_description : function ( type
, id
) {
648 var farray
= PVE
. Utils
. task_desc_table
[ type
];
652 var prefix
= farray
[ 0 ];
653 var text
= farray
[ 1 ];
655 return prefix
+ ' ' + id
+ ' - ' + text
;
660 parse_task_upid : function ( upid
) {
663 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]+):$/ );
665 throw "unable to parse upid '" + upid
+ "'" ;
668 task
. pid
= parseInt ( res
[ 2 ], 16 );
669 task
. pstart
= parseInt ( res
[ 3 ], 16 );
670 task
. starttime
= parseInt ( res
[ 4 ], 16 );
675 task
. desc
= PVE
. Utils
. format_task_description ( task
. type
, task
. id
);
680 format_size : function ( size
) {
681 /*jslint confusion: true */
683 var units
= [ '' , 'Ki' , 'Mi' , 'Gi' , 'Ti' , 'Pi' , 'Ei' , 'Zi' , 'Yi' ];
686 while ( size
>= 1024 && (( num
++)+ 1 ) < units
. length
) {
690 return size
. toFixed (( num
> 0 )? 2 : 0 ) + " " + units
[ num
] + "B" ;
693 format_html_bar : function ( per
, text
) {
695 return "<div class='pve-bar-wrap'>" + text
+ "<div class='pve-bar-border'>" +
696 "<div class='pve-bar-inner' style='width:" + per
+ "%;'></div>" +
701 format_cpu_bar : function ( per1
, per2
, text
) {
703 return "<div class='pve-bar-border'>" +
704 "<div class='pve-bar-inner' style='width:" + per1
+ "%;'></div>" +
705 "<div class='pve-bar-inner2' style='width:" + per2
+ "%;'></div>" +
706 "<div class='pve-bar-text'>" + text
+ "</div>" +
710 format_large_bar : function ( per
, text
) {
713 text
= per
. toFixed ( 1 ) + "%" ;
716 return "<div class='pve-largebar-border'>" +
717 "<div class='pve-largebar-inner' style='width:" + per
+ "%;'></div>" +
718 "<div class='pve-largebar-text'>" + text
+ "</div>" +
722 format_duration_long : function ( ut
) {
724 var days
= Math
. floor ( ut
/ 86400 );
726 var hours
= Math
. floor ( ut
/ 3600 );
728 var mins
= Math
. floor ( ut
/ 60 );
731 var hours_str
= '00' + hours
. toString ();
732 hours_str
= hours_str
. substr ( hours_str
. length
- 2 );
733 var mins_str
= "00" + mins
. toString ();
734 mins_str
= mins_str
. substr ( mins_str
. length
- 2 );
735 var ut_str
= "00" + ut
. toString ();
736 ut_str
= ut_str
. substr ( ut_str
. length
- 2 );
739 var ds
= days
> 1 ? PVE
. Utils
. daysText
: PVE
. Utils
. dayText
;
740 return days
. toString () + ' ' + ds
+ ' ' +
741 hours_str
+ ':' + mins_str
+ ':' + ut_str
;
743 return hours_str
+ ':' + mins_str
+ ':' + ut_str
;
747 format_duration_short : function ( ut
) {
750 return ut
. toFixed ( 1 ) + 's' ;
755 return mins
. toFixed ( 1 ) + 'm' ;
759 var hours
= ut
/ 3600 ;
760 return hours
. toFixed ( 1 ) + 'h' ;
763 var days
= ut
/ 86400 ;
764 return days
. toFixed ( 1 ) + 'd' ;
767 yesText
: gettext ( 'Yes' ),
768 noText
: gettext ( 'No' ),
769 enabledText
: gettext ( 'Enabled' ),
770 disabledText
: gettext ( 'Disabled' ),
771 noneText
: gettext ( 'none' ),
772 errorText
: gettext ( 'Error' ),
773 unknownText
: gettext ( 'Unknown' ),
774 defaultText
: gettext ( 'Default' ),
775 daysText
: gettext ( 'days' ),
776 dayText
: gettext ( 'day' ),
777 runningText
: gettext ( 'running' ),
778 stoppedText
: gettext ( 'stopped' ),
779 neverText
: gettext ( 'never' ),
780 totalText
: gettext ( 'Total' ),
781 usedText
: gettext ( 'Used' ),
782 directoryText
: gettext ( 'Directory' ),
783 imagesText
: gettext ( 'Disk image' ),
784 backupFileText
: gettext ( 'VZDump backup file' ),
785 vztmplText
: gettext ( 'Container template' ),
786 isoImageText
: gettext ( 'ISO image' ),
787 containersText
: gettext ( 'Container' ),
788 stateText
: gettext ( 'State' ),
789 groupText
: gettext ( 'Group' ),
791 format_expire : function ( date
) {
793 return PVE
. Utils
. neverText
;
795 return Ext
. Date
. format ( date
, "Y-m-d" );
798 format_storage_type : function ( value
, md
, record
) {
799 if ( value
=== 'rbd' && record
) {
800 value
= ( record
. get ( 'monhost' )? 'rbd_ext' : 'pveceph' );
802 if ( value
=== 'dir' ) {
803 return PVE
. Utils
. directoryText
;
804 } else if ( value
=== 'nfs' ) {
806 } else if ( value
=== 'glusterfs' ) {
808 } else if ( value
=== 'lvm' ) {
810 } else if ( value
=== 'lvmthin' ) {
812 } else if ( value
=== 'iscsi' ) {
814 } else if ( value
=== 'rbd' ) {
816 } else if ( value
=== 'rbd_ext' ) {
817 return 'RBD (external)' ;
818 } else if ( value
=== 'pveceph' ) {
820 } else if ( value
=== 'sheepdog' ) {
822 } else if ( value
=== 'zfs' ) {
823 return 'ZFS over iSCSI' ;
824 } else if ( value
=== 'zfspool' ) {
826 } else if ( value
=== 'iscsidirect' ) {
827 return 'iSCSIDirect' ;
828 } else if ( value
=== 'drbd' ) {
831 return PVE
. Utils
. unknownText
;
835 format_boolean_with_default : function ( value
) {
836 if ( Ext
. isDefined ( value
) && value
!== '__default__' ) {
837 return value
? PVE
. Utils
. yesText
: PVE
. Utils
. noText
;
839 return PVE
. Utils
. defaultText
;
842 format_boolean : function ( value
) {
843 return value
? PVE
. Utils
. yesText
: PVE
. Utils
. noText
;
846 format_neg_boolean : function ( value
) {
847 return ! value
? PVE
. Utils
. yesText
: PVE
. Utils
. noText
;
850 format_enabled_toggle : function ( value
) {
851 return value
? PVE
. Utils
. enabledText
: PVE
. Utils
. disabledText
;
854 format_ha : function ( value
) {
855 var text
= PVE
. Utils
. noneText
;
858 text
= value
. state
|| PVE
. Utils
. noneText
;
860 text
+= ', ' + PVE
. Utils
. groupText
+ ': ' ;
861 text
+= value
. group
|| PVE
. Utils
. noneText
;
867 format_content_types : function ( value
) {
870 Ext
. each ( value
. split ( ',' ). sort (), function ( ct
) {
871 if ( ct
=== 'images' ) {
872 cta
. push ( PVE
. Utils
. imagesText
);
873 } else if ( ct
=== 'backup' ) {
874 cta
. push ( PVE
. Utils
. backupFileText
);
875 } else if ( ct
=== 'vztmpl' ) {
876 cta
. push ( PVE
. Utils
. vztmplText
);
877 } else if ( ct
=== 'iso' ) {
878 cta
. push ( PVE
. Utils
. isoImageText
);
879 } else if ( ct
=== 'rootdir' ) {
880 cta
. push ( PVE
. Utils
. containersText
);
884 return cta
. join ( ', ' );
887 render_storage_content : function ( value
, metaData
, record
) {
888 var data
= record
. data
;
889 if ( Ext
. isNumber ( data
. channel
) &&
890 Ext
. isNumber ( data
. id
) &&
891 Ext
. isNumber ( data
. lun
)) {
893 Ext
. String
. leftPad ( data
. channel
, 2 , '0' ) +
894 " ID " + data
. id
+ " LUN " + data
. lun
;
896 return data
. volid
. replace ( /^.*:(.*\/)?/ , '' );
899 render_serverity : function ( value
) {
900 return PVE
. Utils
. log_severity_hash
[ value
] || value
;
903 render_cpu : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
905 if (!( record
. data
. uptime
&& Ext
. isNumeric ( value
))) {
909 var maxcpu
= record
. data
. maxcpu
|| 1 ;
911 if (! Ext
. isNumeric ( maxcpu
) && ( maxcpu
>= 1 )) {
915 var per
= value
* 100 ;
917 return per
. toFixed ( 1 ) + '% of ' + maxcpu
. toString () + ( maxcpu
> 1 ? 'CPUs' : 'CPU' );
920 render_size : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
921 /*jslint confusion: true */
923 if (! Ext
. isNumeric ( value
)) {
927 return PVE
. Utils
. format_size ( value
);
930 render_bandwidth : function ( value
) {
931 if (! Ext
. isNumeric ( value
)) {
935 return PVE
. Utils
. format_size ( value
) + '/s' ;
938 render_timestamp : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
939 var servertime
= new Date ( value
* 1000 );
940 return Ext
. Date
. format ( servertime
, 'Y-m-d H:i:s' );
943 render_timestamp_human_readable : function ( value
) {
944 return Ext
. Date
. format ( new Date ( value
* 1000 ), 'l d F Y H:i:s' );
947 render_duration : function ( value
) {
948 if ( value
=== undefined ) {
951 return PVE
. Utils
. format_duration_short ( value
);
954 calculate_mem_usage : function ( data
) {
955 if (! Ext
. isNumeric ( data
. mem
) ||
961 return ( data
. mem
/ data
. maxmem
);
964 render_mem_usage_percent : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
965 if (! Ext
. isNumeric ( value
) || value
=== - 1 ) {
969 // we got no percentage but bytes
971 var maxmem
= record
. data
. maxmem
;
972 if (! record
. data
. uptime
||
974 ! Ext
. isNumeric ( mem
)) {
978 return (( mem
* 100 )/ maxmem
). toFixed ( 1 ) + " %" ;
980 return ( value
* 100 ). toFixed ( 1 ) + " %" ;
983 render_mem_usage : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
986 var maxmem
= record
. data
. maxmem
;
988 if (! record
. data
. uptime
) {
992 if (!( Ext
. isNumeric ( mem
) && maxmem
)) {
996 return PVE
. Utils
. render_size ( value
);
999 calculate_disk_usage : function ( data
) {
1001 if (! Ext
. isNumeric ( data
. disk
) ||
1002 data
. type
=== 'qemu' ||
1003 ( data
. type
=== 'lxc' && data
. uptime
=== 0 ) ||
1004 data
. maxdisk
=== 0 ) {
1008 return ( data
. disk
/ data
. maxdisk
);
1011 render_disk_usage_percent : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
1012 if (! Ext
. isNumeric ( value
) || value
=== - 1 ) {
1016 return ( value
* 100 ). toFixed ( 1 ) + " %" ;
1019 render_disk_usage : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
1022 var maxdisk
= record
. data
. maxdisk
;
1023 var type
= record
. data
. type
;
1025 if (! Ext
. isNumeric ( disk
) ||
1028 ( type
=== 'lxc' && record
. data
. uptime
=== 0 )) {
1032 return PVE
. Utils
. render_size ( value
);
1035 get_object_icon_class : function ( type
, record
) {
1039 if ( type
=== 'type' ) {
1041 objType
= record
. groupbyid
;
1042 } else if ( record
. template
) {
1044 objType
= 'template' ;
1048 status
= record
. status
+ ' ha-' + record
. hastate
;
1051 var defaults
= PVE
. tree
. ResourceTree
. typeDefaults
[ objType
];
1052 if ( defaults
&& defaults
. iconCls
) {
1053 var retVal
= defaults
. iconCls
+ ' ' + status
;
1060 render_resource_type : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
1062 var cls
= PVE
. Utils
. get_object_icon_class ( value
, record
. data
);
1064 var fa
= '<i class="fa-fw x-grid-icon-custom ' + cls
+ '"></i> ' ;
1068 render_uptime : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
1072 if ( uptime
=== undefined ) {
1080 return PVE
. Utils
. format_duration_long ( uptime
);
1083 render_support_level : function ( value
, metaData
, record
) {
1084 return PVE
. Utils
. support_level_hash
[ value
] || '-' ;
1087 render_upid : function ( value
, metaData
, record
) {
1088 var type
= record
. data
. type
;
1089 var id
= record
. data
. id
;
1091 return PVE
. Utils
. format_task_description ( type
, id
);
1094 /* render functions for new status panel */
1096 render_usage : function ( val
) {
1097 return ( val
* 100 ). toFixed ( 2 ) + '%' ;
1100 render_cpu_usage : function ( val
, max
) {
1101 return Ext
. String
. format ( gettext ( '{0}% of {1}' ) +
1102 ' ' + gettext ( 'CPU(s)' ), ( val
* 100 ). toFixed ( 2 ), max
);
1105 render_size_usage : function ( val
, max
) {
1107 return gettext ( 'N/A' );
1109 return ( val
* 100 / max
). toFixed ( 2 ) + '% ' + '(' +
1110 Ext
. String
. format ( gettext ( '{0} of {1}' ),
1111 PVE
. Utils
. render_size ( val
), PVE
. Utils
. render_size ( max
)) + ')' ;
1114 /* this is different for nodes */
1115 render_node_cpu_usage : function ( value
, record
) {
1116 return PVE
. Utils
. render_cpu_usage ( value
, record
. cpus
);
1119 /* this is different for nodes */
1120 render_node_size_usage : function ( record
) {
1121 return PVE
. Utils
. render_size_usage ( record
. used
, record
. total
);
1124 dialog_title : function ( subject
, create
, isAdd
) {
1127 return gettext ( 'Add' ) + ': ' + subject
;
1129 return gettext ( 'Create' ) + ': ' + subject
;
1132 return gettext ( 'Edit' ) + ': ' + subject
;
1136 windowHostname : function () {
1137 return window
. location
. hostname
. replace ( PVE
. Utils
. IP6_bracket_match
,
1138 function ( m
, addr
, offset
, original
) { return addr
; });
1141 openDefaultConsoleWindow : function ( allowSpice
, vmtype
, vmid
, nodename
, vmname
) {
1142 var dv
= PVE
. Utils
. defaultViewer ( allowSpice
);
1143 PVE
. Utils
. openConsoleWindow ( dv
, vmtype
, vmid
, nodename
, vmname
);
1146 openConsoleWindow : function ( viewer
, vmtype
, vmid
, nodename
, vmname
) {
1147 // kvm, lxc, shell, upgrade
1149 if ( vmid
== undefined && ( vmtype
=== 'kvm' || vmtype
=== 'lxc' )) {
1150 throw "missing vmid" ;
1154 throw "no nodename specified" ;
1157 if ( viewer
=== 'html5' ) {
1158 PVE
. Utils
. openVNCViewer ( vmtype
, vmid
, nodename
, vmname
);
1159 } else if ( viewer
=== 'vv' ) {
1161 var params
= { proxy
: PVE
. Utils
. windowHostname () };
1162 if ( vmtype
=== 'kvm' ) {
1163 url
= '/nodes/' + nodename
+ '/qemu/' + vmid
. toString () + '/spiceproxy' ;
1164 PVE
. Utils
. openSpiceViewer ( url
, params
);
1165 } else if ( vmtype
=== 'lxc' ) {
1166 url
= '/nodes/' + nodename
+ '/lxc/' + vmid
. toString () + '/spiceproxy' ;
1167 PVE
. Utils
. openSpiceViewer ( url
, params
);
1168 } else if ( vmtype
=== 'shell' ) {
1169 url
= '/nodes/' + nodename
+ '/spiceshell' ;
1170 PVE
. Utils
. openSpiceViewer ( url
, params
);
1171 } else if ( vmtype
=== 'upgrade' ) {
1172 url
= '/nodes/' + nodename
+ '/spiceshell' ;
1174 PVE
. Utils
. openSpiceViewer ( url
, params
);
1177 throw "unknown viewer type" ;
1181 defaultViewer : function ( allowSpice
) {
1182 var vncdefault
= 'html5' ;
1183 var dv
= PVE
. VersionInfo
. console
|| vncdefault
;
1184 if ( dv
=== 'vv' && ! allowSpice
) {
1191 openVNCViewer : function ( vmtype
, vmid
, nodename
, vmname
) {
1192 var url
= Ext
. urlEncode ({
1193 console
: vmtype
, // kvm, lxc, upgrade or shell
1199 var nw
= window
. open ( "?" + url
, '_blank' , "innerWidth=745,innerheight=427" );
1203 openSpiceViewer : function ( url
, params
){
1205 var downloadWithName = function ( uri
, name
) {
1206 var link
= Ext
. DomHelper
. append ( document
. body
, {
1209 css
: 'display:none;visibility:hidden;height:0px;'
1212 // Note: we need to tell android the correct file name extension
1213 // but we do not set 'download' tag for other environments, because
1214 // It can have strange side effects (additional user prompt on firefox)
1215 var andriod
= navigator
. userAgent
. match ( /Android/i ) ? true : false ;
1217 link
. download
= name
;
1220 if ( link
. fireEvent
) {
1221 link
. fireEvent ( 'onclick' );
1223 var evt
= document
. createEvent ( "MouseEvents" );
1224 evt
. initMouseEvent ( 'click' , true , true , window
, 1 , 0 , 0 , 0 , 0 , false , false , false , false , 0 , null );
1225 link
. dispatchEvent ( evt
);
1229 PVE
. Utils
. API2Request ({
1233 failure : function ( response
, opts
){
1234 Ext
. Msg
. alert ( 'Error' , response
. htmlStatus
);
1236 success : function ( response
, opts
){
1237 var raw
= "[virt-viewer] \n " ;
1238 Ext
. Object
. each ( response
. result
. data
, function ( k
, v
) {
1239 raw
+= k
+ "=" + v
+ " \n " ;
1241 var url
= 'data:application/x-virt-viewer;charset=UTF-8,' +
1242 encodeURIComponent ( raw
);
1244 downloadWithName ( url
, "pve-spice.vv" );
1249 // comp.setLoading() is buggy in ExtJS 4.0.7, so we
1250 // use el.mask() instead
1251 setErrorMask : function ( comp
, msg
) {
1260 el
. mask ( gettext ( "Loading..." ));
1267 monStoreErrors : function ( me
, store
) {
1268 me
. mon ( store
, 'beforeload' , function ( s
, operation
, eOpts
) {
1269 if (! me
. loadCount
) {
1270 me
. loadCount
= 0 ; // make sure it is numeric
1271 PVE
. Utils
. setErrorMask ( me
, true );
1275 // only works with 'pve' proxy
1276 me
. mon ( store
. proxy
, 'afterload' , function ( proxy
, request
, success
) {
1280 PVE
. Utils
. setErrorMask ( me
, false );
1285 /*jslint nomen: true */
1286 var operation
= request
. _operation
;
1287 var error
= operation
. getError ();
1288 if ( error
. statusText
) {
1289 msg
= error
. statusText
+ ' (' + error
. status
+ ')' ;
1291 msg
= gettext ( 'Connection error' );
1293 PVE
. Utils
. setErrorMask ( me
, msg
);
1297 openTreeConsole : function ( tree
, record
, item
, index
, e
) {
1299 var nodename
= record
. data
. node
;
1300 var vmid
= record
. data
. vmid
;
1301 var vmname
= record
. data
. name
;
1302 if ( record
. data
. type
=== 'qemu' && ! record
. data
. template
) {
1303 PVE
. Utils
. API2Request ({
1304 url
: '/nodes/' + nodename
+ '/qemu/' + vmid
+ '/status/current' ,
1305 failure : function ( response
, opts
) {
1306 Ext
. Msg
. alert ( 'Error' , response
. htmlStatus
);
1308 success : function ( response
, opts
) {
1309 var allowSpice
= response
. result
. data
. spice
;
1310 PVE
. Utils
. openDefaultConsoleWindow ( allowSpice
, 'kvm' , vmid
, nodename
, vmname
);
1313 } else if ( record
. data
. type
=== 'lxc' && ! record
. data
. template
) {
1314 PVE
. Utils
. openDefaultConsoleWindow ( true , 'lxc' , vmid
, nodename
, vmname
);
1318 // test automation helper
1319 call_menu_handler : function ( menu
, text
) {
1321 var list
= menu
. query ( 'menuitem' );
1323 Ext
. Array
. each ( list
, function ( item
) {
1324 if ( item
. text
=== text
) {
1335 createCmdMenu : function ( v
, record
, item
, index
, event
) {
1337 if (!( v
instanceof Ext
. tree
. View
)) {
1342 if ( record
. data
. type
=== 'qemu' && ! record
. data
. template
) {
1343 menu
= Ext
. create ( 'PVE.qemu.CmdMenu' , {
1346 } else if ( record
. data
. type
=== 'qemu' && record
. data
. template
) {
1347 menu
= Ext
. create ( 'PVE.qemu.TemplateMenu' , {
1350 } else if ( record
. data
. type
=== 'lxc' && ! record
. data
. template
) {
1351 menu
= Ext
. create ( 'PVE.lxc.CmdMenu' , {
1354 } else if ( record
. data
. type
=== 'lxc' && record
. data
. template
) {
1355 /* since clone does not work reliably, disable for now
1356 menu = Ext.create('PVE.lxc.TemplateMenu', {
1362 } else if ( record
. data
. type
=== 'node' ){
1363 menu
= Ext
. create ( 'PVE.node.CmdMenu' , {
1364 nodename
: record
. data
. node
1371 menu
. showAt ( event
. getXY ());
1374 // helper for deleting field which are set to there default values
1375 delete_if_default : function ( values
, fieldname
, default_val
, create
) {
1376 if ( values
[ fieldname
] === '' || values
[ fieldname
] === default_val
) {
1378 if ( values
[ 'delete' ]) {
1379 values
[ 'delete' ] += ',' + fieldname
;
1381 values
[ 'delete' ] = fieldname
;
1385 delete values
[ fieldname
];
1390 constructor : function () {
1392 Ext
. apply ( me
, me
. utilities
);
1394 var IPV4_OCTET
= "(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])" ;
1395 var IPV4_REGEXP
= "(?:(?:" + IPV4_OCTET
+ " \\ .){3}" + IPV4_OCTET
+ ")" ;
1396 var IPV6_H16
= "(?:[0-9a-fA-F]{1,4})" ;
1397 var IPV6_LS32
= "(?:(?:" + IPV6_H16
+ ":" + IPV6_H16
+ ")|" + IPV4_REGEXP
+ ")" ;
1400 me
. IP4_match
= new RegExp ( "^(?:" + IPV4_REGEXP
+ ")$" );
1401 me
. IP4_cidr_match
= new RegExp ( "^(?:" + IPV4_REGEXP
+ ")\/([0-9]{1,2})$" );
1403 var IPV6_REGEXP
= "(?:" +
1404 "(?:(?:" + "(?:" + IPV6_H16
+ ":){6})" + IPV6_LS32
+ ")|" +
1405 "(?:(?:" + "::" + "(?:" + IPV6_H16
+ ":){5})" + IPV6_LS32
+ ")|" +
1406 "(?:(?:(?:" + IPV6_H16
+ ")?::" + "(?:" + IPV6_H16
+ ":){4})" + IPV6_LS32
+ ")|" +
1407 "(?:(?:(?:(?:" + IPV6_H16
+ ":){0,1}" + IPV6_H16
+ ")?::" + "(?:" + IPV6_H16
+ ":){3})" + IPV6_LS32
+ ")|" +
1408 "(?:(?:(?:(?:" + IPV6_H16
+ ":){0,2}" + IPV6_H16
+ ")?::" + "(?:" + IPV6_H16
+ ":){2})" + IPV6_LS32
+ ")|" +
1409 "(?:(?:(?:(?:" + IPV6_H16
+ ":){0,3}" + IPV6_H16
+ ")?::" + "(?:" + IPV6_H16
+ ":){1})" + IPV6_LS32
+ ")|" +
1410 "(?:(?:(?:(?:" + IPV6_H16
+ ":){0,4}" + IPV6_H16
+ ")?::" + ")" + IPV6_LS32
+ ")|" +
1411 "(?:(?:(?:(?:" + IPV6_H16
+ ":){0,5}" + IPV6_H16
+ ")?::" + ")" + IPV6_H16
+ ")|" +
1412 "(?:(?:(?:(?:" + IPV6_H16
+ ":){0,7}" + IPV6_H16
+ ")?::" + ")" + ")" +
1415 me
. IP6_match
= new RegExp ( "^(?:" + IPV6_REGEXP
+ ")$" );
1416 me
. IP6_cidr_match
= new RegExp ( "^(?:" + IPV6_REGEXP
+ ")\/([0-9]{1,3})$" );
1417 me
. IP6_bracket_match
= new RegExp ( "^ \\ [(" + IPV6_REGEXP
+ ") \\ ]" );
1419 me
. IP64_match
= new RegExp ( "^(?:" + IPV6_REGEXP
+ "|" + IPV4_REGEXP
+ ")$" );
1421 var DnsName_REGEXP
= "(?:(([a-zA-Z0-9]([a-zA-Z0-9 \\ -]*[a-zA-Z0-9])?) \\ .)*([A-Za-z0-9]([A-Za-z0-9 \\ -]*[A-Za-z0-9])?))" ;
1422 me
. DnsName_match
= new RegExp ( "^" + DnsName_REGEXP
+ "$" );
1424 me
. HostPort_match
= new RegExp ( "^(" + IPV4_REGEXP
+ "|" + DnsName_REGEXP
+ ")(: \\ d+)?$" );
1425 me
. HostPortBrackets_match
= new RegExp ( "^ \\ [(?:" + IPV6_REGEXP
+ "|" + IPV4_REGEXP
+ "|" + DnsName_REGEXP
+ ") \\ ](: \\ d+)?$" );
1426 me
. IP6_dotnotation_match
= new RegExp ( "^" + IPV6_REGEXP
+ "( \\ . \\ d+)?$" );