]>
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
)) {
16 console
. log ( "Starting PVE Manager" );
18 Ext
. Ajax
. defaultHeaders
= {
19 'Accept' : 'application/json'
22 /*jslint confusion: true */
23 Ext
. define ( 'PVE.Utils' , { utilities
: {
25 // this singleton contains miscellaneous utilities
27 toolkit
: undefined , // (extjs|touch), set inside Toolkit.js
29 bus_match
: /^(ide|sata|virtio|scsi)\d+$/ ,
43 'c' : gettext ( 'Community' ),
44 'b' : gettext ( 'Basic' ),
45 's' : gettext ( 'Standard' ),
46 'p' : gettext ( 'Premium' )
49 noSubKeyHtml
: 'You do not have a valid subscription for this server. Please visit <a target="_blank" href="https://www.proxmox.com/products/proxmox-ve/subscription-service-plans">www.proxmox.com</a> to get a list of available options.' ,
53 { desc
: '5.x - 2.6 Kernel' , val
: 'l26' },
54 { desc
: '2.4 Kernel' , val
: 'l24' }
56 'Microsoft Windows' : [
57 { desc
: '10/2016/2019' , val
: 'win10' },
58 { desc
: '8.x/2012/2012r2' , val
: 'win8' },
59 { desc
: '7/2008r2' , val
: 'win7' },
60 { desc
: 'Vista/2008' , val
: 'w2k8' },
61 { desc
: 'XP/2003' , val
: 'wxp' },
62 { desc
: '2000' , val
: 'w2k' }
65 { desc
: '-' , val
: 'solaris' }
68 { desc
: '-' , val
: 'other' }
72 get_health_icon : function ( state
, circle
) {
73 if ( circle
=== undefined ) {
77 if ( state
=== undefined ) {
81 var icon
= 'faded fa-question' ;
84 icon
= 'good fa-check' ;
87 icon
= 'warning fa-upload' ;
90 icon
= 'warning fa-refresh' ;
93 icon
= 'warning fa-exclamation' ;
96 icon
= 'critical fa-times' ;
108 parse_ceph_version : function ( service
) {
109 if ( service
. ceph_version_short
) {
110 return service
. ceph_version_short
;
113 if ( service
. ceph_version
) {
114 var match
= service
. ceph_version
. match ( /version (\d+(\.\d+)*)/ );
123 compare_ceph_versions : function ( a
, b
) {
131 if ( Ext
. isArray ( a
)) {
132 avers
= a
. slice (); // copy array
134 avers
= a
. toString (). split ( '.' );
137 if ( Ext
. isArray ( b
)) {
138 bvers
= b
. slice (); // copy array
140 bvers
= b
. toString (). split ( '.' );
144 let av
= avers
. shift ();
145 let bv
= bvers
. shift ();
147 if ( av
=== undefined && bv
=== undefined ) {
149 } else if ( av
=== undefined ) {
151 } else if ( bv
=== undefined ) {
154 let diff
= parseInt ( av
, 10 ) - parseInt ( bv
, 10 );
155 if ( diff
!= 0 ) return diff
;
156 // else we need to look at the next parts
162 get_ceph_icon_html : function ( health
, fw
) {
163 var state
= PVE
. Utils
. map_ceph_health
[ health
];
164 var cls
= PVE
. Utils
. get_health_icon ( state
);
168 return "<i class='fa " + cls
+ "'></i> " ;
173 'HEALTH_UPGRADE' : 'upgrade' ,
175 'HEALTH_WARN' : 'warning' ,
176 'HEALTH_ERR' : 'critical'
179 render_ceph_health : function ( healthObj
) {
181 iconCls
: PVE
. Utils
. get_health_icon (),
185 if (! healthObj
|| ! healthObj
. status
) {
189 var health
= PVE
. Utils
. map_ceph_health
[ healthObj
. status
];
191 state
. iconCls
= PVE
. Utils
. get_health_icon ( health
, true );
192 state
. text
= healthObj
. status
;
197 render_zfs_health : function ( value
) {
198 if ( typeof value
== 'undefined' ){
201 var iconCls
= 'question-circle' ;
205 iconCls
= 'check-circle good' ;
209 iconCls
= 'exclamation-circle warning' ;
214 iconCls
= 'times-circle critical' ;
219 return '<i class="fa fa-' + iconCls
+ '"></i> ' + value
;
223 get_kvm_osinfo : function ( value
) {
224 var info
= { base
: 'Other' }; // default
226 Ext
. each ( Object
. keys ( PVE
. Utils
. kvm_ostypes
), function ( k
) {
227 Ext
. each ( PVE
. Utils
. kvm_ostypes
[ k
], function ( e
) {
228 if ( e
. val
=== value
) {
229 info
= { desc
: e
. desc
, base
: k
};
237 render_kvm_ostype : function ( value
) {
238 var osinfo
= PVE
. Utils
. get_kvm_osinfo ( value
);
239 if ( osinfo
. desc
&& osinfo
. desc
!== '-' ) {
240 return osinfo
. base
+ ' ' + osinfo
. desc
;
246 render_hotplug_features : function ( value
) {
249 if (! value
|| ( value
=== '0' )) {
250 return gettext ( 'Disabled' );
254 value
= 'disk,network,usb' ;
257 Ext
. each ( value
. split ( ',' ), function ( el
) {
259 fa
. push ( gettext ( 'Disk' ));
260 } else if ( el
=== 'network' ) {
261 fa
. push ( gettext ( 'Network' ));
262 } else if ( el
=== 'usb' ) {
264 } else if ( el
=== 'memory' ) {
265 fa
. push ( gettext ( 'Memory' ));
266 } else if ( el
=== 'cpu' ) {
267 fa
. push ( gettext ( 'CPU' ));
273 return fa
. join ( ', ' );
276 render_qga_features : function ( value
) {
278 return Proxmox
. Utils
. defaultText
+ ' (' + Proxmox
. Utils
. disabledText
+ ')' ;
280 var props
= PVE
. Parser
. parsePropertyString ( value
, 'enabled' );
281 if (! PVE
. Parser
. parseBoolean ( props
. enabled
)) {
282 return Proxmox
. Utils
. disabledText
;
285 delete props
. enabled
;
286 var agentstring
= Proxmox
. Utils
. enabledText
;
288 Ext
. Object
. each ( props
, function ( key
, value
) {
290 agentstring
+= ', ' + key
+ ': ' ;
292 if ( key
=== 'type' ) {
297 agentstring
+= map
[ value
] || Proxmox
. Utils
. unknownText
;
299 if ( PVE
. Parser
. parseBoolean ( value
)) {
300 agentstring
+= Proxmox
. Utils
. enabledText
;
302 agentstring
+= Proxmox
. Utils
. disabledText
;
310 render_qemu_machine : function ( value
) {
311 return value
|| ( Proxmox
. Utils
. defaultText
+ ' (i440fx)' );
314 render_qemu_bios : function ( value
) {
316 return Proxmox
. Utils
. defaultText
+ ' (SeaBIOS)' ;
317 } else if ( value
=== 'seabios' ) {
319 } else if ( value
=== 'ovmf' ) {
320 return "OVMF (UEFI)" ;
326 render_dc_ha_opts : function ( value
) {
328 return Proxmox
. Utils
. defaultText
;
330 return PVE
. Parser
. printPropertyString ( value
);
333 render_as_property_string : function ( value
) {
334 return (! value
) ? Proxmox
. Utils
. defaultText
335 : PVE
. Parser
. printPropertyString ( value
);
338 render_scsihw : function ( value
) {
340 return Proxmox
. Utils
. defaultText
+ ' (LSI 53C895A)' ;
341 } else if ( value
=== 'lsi' ) {
342 return 'LSI 53C895A' ;
343 } else if ( value
=== 'lsi53c810' ) {
345 } else if ( value
=== 'megasas' ) {
346 return 'MegaRAID SAS 8708EM2' ;
347 } else if ( value
=== 'virtio-scsi-pci' ) {
348 return 'VirtIO SCSI' ;
349 } else if ( value
=== 'virtio-scsi-single' ) {
350 return 'VirtIO SCSI single' ;
351 } else if ( value
=== 'pvscsi' ) {
352 return 'VMware PVSCSI' ;
358 render_spice_enhancements : function ( values
) {
359 let props
= PVE
. Parser
. parsePropertyString ( values
);
360 if ( Ext
. Object
. isEmpty ( props
)) {
361 return Proxmox
. Utils
. noneText
;
365 if ( PVE
. Parser
. parseBoolean ( props
. foldersharing
)) {
366 output
. push ( 'Folder Sharing: ' + gettext ( 'Enabled' ));
368 if ( props
. videostreaming
=== 'all' || props
. videostreaming
=== 'filter' ) {
369 output
. push ( 'Video Streaming: ' + props
. videostreaming
);
371 return output
. join ( ', ' );
374 // fixme: auto-generate this
375 // for now, please keep in sync with PVE::Tools::kvmkeymaps
380 'de-ch' : 'German (Swiss)' ,
381 'en-gb' : 'English (UK)' ,
382 'en-us' : 'English (USA)' ,
386 //fo: 'Faroe Islands',
388 'fr-be' : 'French (Belgium)' ,
389 'fr-ca' : 'French (Canada)' ,
390 'fr-ch' : 'French (Swiss)' ,
400 //'nl-be': 'Dutch (Belgium)',
404 'pt-br' : 'Portuguese (Brazil)' ,
413 std
: gettext ( 'Standard VGA' ),
414 vmware
: gettext ( 'VMware compatible' ),
416 qxl2
: 'SPICE dual monitor' ,
417 qxl3
: 'SPICE three monitors' ,
418 qxl4
: 'SPICE four monitors' ,
419 serial0
: gettext ( 'Serial terminal' ) + ' 0' ,
420 serial1
: gettext ( 'Serial terminal' ) + ' 1' ,
421 serial2
: gettext ( 'Serial terminal' ) + ' 2' ,
422 serial3
: gettext ( 'Serial terminal' ) + ' 3' ,
423 virtio
: 'VirtIO-GPU' ,
424 none
: Proxmox
. Utils
. noneText
427 render_kvm_language : function ( value
) {
428 if (! value
|| value
=== '__default__' ) {
429 return Proxmox
. Utils
. defaultText
;
431 var text
= PVE
. Utils
. kvm_keymaps
[ value
];
433 return text
+ ' (' + value
+ ')' ;
438 kvm_keymap_array : function () {
439 var data
= [[ '__default__' , PVE
. Utils
. render_kvm_language ( '' )]];
440 Ext
. Object
. each ( PVE
. Utils
. kvm_keymaps
, function ( key
, value
) {
441 data
. push ([ key
, PVE
. Utils
. render_kvm_language ( value
)]);
448 '__default__' : Proxmox
. Utils
. defaultText
+ ' (xterm.js)' ,
449 'vv' : 'SPICE (remote-viewer)' ,
450 'html5' : 'HTML5 (noVNC)' ,
451 'xtermjs' : 'xterm.js'
454 render_console_viewer : function ( value
) {
455 value
= value
|| '__default__' ;
456 if ( PVE
. Utils
. console_map
[ value
]) {
457 return PVE
. Utils
. console_map
[ value
];
462 console_viewer_array : function () {
463 return Ext
. Array
. map ( Object
. keys ( PVE
. Utils
. console_map
), function ( v
) {
464 return [ v
, PVE
. Utils
. render_console_viewer ( v
)];
468 render_kvm_vga_driver : function ( value
) {
470 return Proxmox
. Utils
. defaultText
;
472 var vga
= PVE
. Parser
. parsePropertyString ( value
, 'type' );
473 var text
= PVE
. Utils
. kvm_vga_drivers
[ vga
. type
];
475 text
= Proxmox
. Utils
. defaultText
;
478 return text
+ ' (' + value
+ ')' ;
483 kvm_vga_driver_array : function () {
484 var data
= [[ '__default__' , PVE
. Utils
. render_kvm_vga_driver ( '' )]];
485 Ext
. Object
. each ( PVE
. Utils
. kvm_vga_drivers
, function ( key
, value
) {
486 data
. push ([ key
, PVE
. Utils
. render_kvm_vga_driver ( value
)]);
492 render_kvm_startup : function ( value
) {
493 var startup
= PVE
. Parser
. parseStartup ( value
);
496 if ( startup
. order
=== undefined ) {
499 res
+= startup
. order
;
501 if ( startup
. up
!== undefined ) {
502 res
+= ',up=' + startup
. up
;
504 if ( startup
. down
!== undefined ) {
505 res
+= ',down=' + startup
. down
;
511 extractFormActionError : function ( action
) {
513 switch ( action
. failureType
) {
514 case Ext
. form
. action
. Action
. CLIENT_INVALID
:
515 msg
= gettext ( 'Form fields may not be submitted with invalid values' );
517 case Ext
. form
. action
. Action
. CONNECT_FAILURE
:
518 msg
= gettext ( 'Connection error' );
519 var resp
= action
. response
;
520 if ( resp
. status
&& resp
. statusText
) {
521 msg
+= " " + resp
. status
+ ": " + resp
. statusText
;
524 case Ext
. form
. action
. Action
. LOAD_FAILURE
:
525 case Ext
. form
. action
. Action
. SERVER_INVALID
:
526 msg
= Proxmox
. Utils
. extractRequestError ( action
. result
, true );
532 format_duration_short : function ( ut
) {
535 return ut
. toFixed ( 1 ) + 's' ;
540 return mins
. toFixed ( 1 ) + 'm' ;
544 var hours
= ut
/ 3600 ;
545 return hours
. toFixed ( 1 ) + 'h' ;
548 var days
= ut
/ 86400 ;
549 return days
. toFixed ( 1 ) + 'd' ;
553 'images' : gettext ( 'Disk image' ),
554 'backup' : gettext ( 'VZDump backup file' ),
555 'vztmpl' : gettext ( 'Container template' ),
556 'iso' : gettext ( 'ISO image' ),
557 'rootdir' : gettext ( 'Container' ),
558 'snippets' : gettext ( 'Snippets' )
561 volume_is_qemu_backup : function ( volid
, format
) {
562 return format
=== 'pbs-vm' || volid
. match ( ':backup/vzdump-qemu-' );
565 volume_is_lxc_backup : function ( volid
, format
) {
566 return format
=== 'pbs-ct' || volid
. match ( ':backup/vzdump-(lxc|openvz)-' );
571 name
: Proxmox
. Utils
. directoryText
,
572 ipanel
: 'DirInputPanel' ,
577 ipanel
: 'LVMInputPanel' ,
582 ipanel
: 'LvmThinInputPanel' ,
587 ipanel
: 'NFSInputPanel' ,
592 ipanel
: 'CIFSInputPanel' ,
597 ipanel
: 'GlusterFsInputPanel' ,
602 ipanel
: 'IScsiInputPanel' ,
607 ipanel
: 'CephFSInputPanel' ,
611 name
: 'CephFS (PVE)' ,
612 ipanel
: 'CephFSInputPanel' ,
618 ipanel
: 'RBDInputPanel' ,
623 ipanel
: 'RBDInputPanel' ,
628 name
: 'ZFS over iSCSI' ,
629 ipanel
: 'ZFSInputPanel' ,
634 ipanel
: 'ZFSPoolInputPanel' ,
638 name
: 'Proxmox Backup Server' ,
639 //ipanel: '', // TODO
663 ipanel
: 'VlanInputPanel' ,
668 ipanel
: 'QinQInputPanel' ,
673 ipanel
: 'VxlanInputPanel' ,
678 ipanel
: 'EvpnInputPanel' ,
683 sdncontrollerSchema
: {
690 ipanel
: 'EvpnInputPanel' ,
695 format_sdnvnet_type : function ( value
, md
, record
) {
696 var schema
= PVE
. Utils
. sdnvnetSchema
[ value
];
700 return Proxmox
. Utils
. unknownText
;
703 format_sdnzone_type : function ( value
, md
, record
) {
704 var schema
= PVE
. Utils
. sdnzoneSchema
[ value
];
706 return schema
. name
. toUpperCase ();
708 return Proxmox
. Utils
. unknownText
;
711 format_sdncontroller_type : function ( value
, md
, record
) {
712 var schema
= PVE
. Utils
. sdncontrollerSchema
[ value
];
716 return Proxmox
. Utils
. unknownText
;
719 format_storage_type : function ( value
, md
, record
) {
720 if ( value
=== 'rbd' ) {
721 value
= (! record
|| record
. get ( 'monhost' ) ? 'rbd' : 'pveceph' );
722 } else if ( value
=== 'cephfs' ) {
723 value
= (! record
|| record
. get ( 'monhost' ) ? 'cephfs' : 'pvecephfs' );
726 var schema
= PVE
. Utils
. storageSchema
[ value
];
730 return Proxmox
. Utils
. unknownText
;
733 format_ha : function ( value
) {
734 var text
= Proxmox
. Utils
. noneText
;
737 text
= value
. state
|| Proxmox
. Utils
. noneText
;
739 text
+= ', ' + Proxmox
. Utils
. groupText
+ ': ' ;
740 text
+= value
. group
|| Proxmox
. Utils
. noneText
;
746 format_content_types : function ( value
) {
747 return value
. split ( ',' ). sort (). map ( function ( ct
) {
748 return PVE
. Utils
. contentTypes
[ ct
] || ct
;
752 render_storage_content : function ( value
, metaData
, record
) {
753 var data
= record
. data
;
754 if ( Ext
. isNumber ( data
. channel
) &&
755 Ext
. isNumber ( data
. id
) &&
756 Ext
. isNumber ( data
. lun
)) {
758 Ext
. String
. leftPad ( data
. channel
, 2 , '0' ) +
759 " ID " + data
. id
+ " LUN " + data
. lun
;
761 return data
. volid
. replace ( /^.*?:(.*?\/)?/ , '' );
764 render_serverity : function ( value
) {
765 return PVE
. Utils
. log_severity_hash
[ value
] || value
;
768 render_cpu : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
770 if (!( record
. data
. uptime
&& Ext
. isNumeric ( value
))) {
774 var maxcpu
= record
. data
. maxcpu
|| 1 ;
776 if (! Ext
. isNumeric ( maxcpu
) && ( maxcpu
>= 1 )) {
780 var per
= value
* 100 ;
782 return per
. toFixed ( 1 ) + '% of ' + maxcpu
. toString () + ( maxcpu
> 1 ? 'CPUs' : 'CPU' );
785 render_size : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
786 /*jslint confusion: true */
788 if (! Ext
. isNumeric ( value
)) {
792 return Proxmox
. Utils
. format_size ( value
);
795 render_bandwidth : function ( value
) {
796 if (! Ext
. isNumeric ( value
)) {
800 return Proxmox
. Utils
. format_size ( value
) + '/s' ;
803 render_timestamp_human_readable : function ( value
) {
804 return Ext
. Date
. format ( new Date ( value
* 1000 ), 'l d F Y H:i:s' );
807 render_duration : function ( value
) {
808 if ( value
=== undefined ) {
811 return PVE
. Utils
. format_duration_short ( value
);
814 calculate_mem_usage : function ( data
) {
815 if (! Ext
. isNumeric ( data
. mem
) ||
821 return ( data
. mem
/ data
. maxmem
);
824 render_mem_usage_percent : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
825 if (! Ext
. isNumeric ( value
) || value
=== - 1 ) {
829 // we got no percentage but bytes
831 var maxmem
= record
. data
. maxmem
;
832 if (! record
. data
. uptime
||
834 ! Ext
. isNumeric ( mem
)) {
838 return (( mem
* 100 )/ maxmem
). toFixed ( 1 ) + " %" ;
840 return ( value
* 100 ). toFixed ( 1 ) + " %" ;
843 render_mem_usage : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
846 var maxmem
= record
. data
. maxmem
;
848 if (! record
. data
. uptime
) {
852 if (!( Ext
. isNumeric ( mem
) && maxmem
)) {
856 return PVE
. Utils
. render_size ( value
);
859 calculate_disk_usage : function ( data
) {
861 if (! Ext
. isNumeric ( data
. disk
) ||
862 data
. type
=== 'qemu' ||
863 ( data
. type
=== 'lxc' && data
. uptime
=== 0 ) ||
864 data
. maxdisk
=== 0 ) {
868 return ( data
. disk
/ data
. maxdisk
);
871 render_disk_usage_percent : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
872 if (! Ext
. isNumeric ( value
) || value
=== - 1 ) {
876 return ( value
* 100 ). toFixed ( 1 ) + " %" ;
879 render_disk_usage : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
882 var maxdisk
= record
. data
. maxdisk
;
883 var type
= record
. data
. type
;
885 if (! Ext
. isNumeric ( disk
) ||
888 ( type
=== 'lxc' && record
. data
. uptime
=== 0 )) {
892 return PVE
. Utils
. render_size ( value
);
895 get_object_icon_class : function ( type
, record
) {
899 if ( type
=== 'type' ) {
901 objType
= record
. groupbyid
;
902 } else if ( record
. template
) {
904 objType
= 'template' ;
908 status
= record
. status
+ ' ha-' + record
. hastate
;
912 status
+= ' locked lock-' + record
. lock
;
915 var defaults
= PVE
. tree
. ResourceTree
. typeDefaults
[ objType
];
916 if ( defaults
&& defaults
. iconCls
) {
917 var retVal
= defaults
. iconCls
+ ' ' + status
;
924 render_resource_type : function ( value
, metaData
, record
, rowIndex
, colIndex
, store
) {
926 var cls
= PVE
. Utils
. get_object_icon_class ( value
, record
. data
);
928 var fa
= '<i class="fa-fw x-grid-icon-custom ' + cls
+ '"></i> ' ;
932 render_support_level : function ( value
, metaData
, record
) {
933 return PVE
. Utils
. support_level_hash
[ value
] || '-' ;
936 render_upid : function ( value
, metaData
, record
) {
937 var type
= record
. data
. type
;
938 var id
= record
. data
. id
;
940 return Proxmox
. Utils
. format_task_description ( type
, id
);
943 /* render functions for new status panel */
945 render_usage : function ( val
) {
946 return ( val
* 100 ). toFixed ( 2 ) + '%' ;
949 render_cpu_usage : function ( val
, max
) {
950 return Ext
. String
. format ( gettext ( '{0}% of {1}' ) +
951 ' ' + gettext ( 'CPU(s)' ), ( val
* 100 ). toFixed ( 2 ), max
);
954 render_size_usage : function ( val
, max
) {
956 return gettext ( 'N/A' );
958 return ( val
* 100 / max
). toFixed ( 2 ) + '% ' + '(' +
959 Ext
. String
. format ( gettext ( '{0} of {1}' ),
960 PVE
. Utils
. render_size ( val
), PVE
. Utils
. render_size ( max
)) + ')' ;
963 /* this is different for nodes */
964 render_node_cpu_usage : function ( value
, record
) {
965 return PVE
. Utils
. render_cpu_usage ( value
, record
. cpus
);
968 /* this is different for nodes */
969 render_node_size_usage : function ( record
) {
970 return PVE
. Utils
. render_size_usage ( record
. used
, record
. total
);
973 render_optional_url : function ( value
) {
975 if ( value
&& ( match
= value
. match ( /^https?:\/\// )) !== null ) {
976 return '<a target="_blank" href="' + value
+ '">' + value
+ '</a>' ;
981 render_san : function ( value
) {
983 if ( Ext
. isArray ( value
)) {
984 value
. forEach ( function ( val
) {
985 if (! Ext
. isNumber ( val
)) {
989 return names
. join ( '<br>' );
994 render_full_name : function ( firstname
, metaData
, record
) {
995 var first
= firstname
|| '' ;
996 var last
= record
. data
. lastname
|| '' ;
997 return Ext
. htmlEncode ( first
+ " " + last
);
1000 render_u2f_error : function ( error
) {
1002 '1' : gettext ( 'Other Error' ),
1003 '2' : gettext ( 'Bad Request' ),
1004 '3' : gettext ( 'Configuration Unsupported' ),
1005 '4' : gettext ( 'Device Ineligible' ),
1006 '5' : gettext ( 'Timeout' )
1008 return "U2F Error: " + ErrorNames
[ error
] || Proxmox
. Utils
. unknownText
;
1011 windowHostname : function () {
1012 return window
. location
. hostname
. replace ( Proxmox
. Utils
. IP6_bracket_match
,
1013 function ( m
, addr
, offset
, original
) { return addr
; });
1016 openDefaultConsoleWindow : function ( consoles
, vmtype
, vmid
, nodename
, vmname
, cmd
) {
1017 var dv
= PVE
. Utils
. defaultViewer ( consoles
);
1018 PVE
. Utils
. openConsoleWindow ( dv
, vmtype
, vmid
, nodename
, vmname
, cmd
);
1021 openConsoleWindow : function ( viewer
, vmtype
, vmid
, nodename
, vmname
, cmd
) {
1022 // kvm, lxc, shell, upgrade
1024 if ( vmid
== undefined && ( vmtype
=== 'kvm' || vmtype
=== 'lxc' )) {
1025 throw "missing vmid" ;
1029 throw "no nodename specified" ;
1032 if ( viewer
=== 'html5' ) {
1033 PVE
. Utils
. openVNCViewer ( vmtype
, vmid
, nodename
, vmname
, cmd
);
1034 } else if ( viewer
=== 'xtermjs' ) {
1035 Proxmox
. Utils
. openXtermJsViewer ( vmtype
, vmid
, nodename
, vmname
, cmd
);
1036 } else if ( viewer
=== 'vv' ) {
1038 var params
= { proxy
: PVE
. Utils
. windowHostname () };
1039 if ( vmtype
=== 'kvm' ) {
1040 url
= '/nodes/' + nodename
+ '/qemu/' + vmid
. toString () + '/spiceproxy' ;
1041 PVE
. Utils
. openSpiceViewer ( url
, params
);
1042 } else if ( vmtype
=== 'lxc' ) {
1043 url
= '/nodes/' + nodename
+ '/lxc/' + vmid
. toString () + '/spiceproxy' ;
1044 PVE
. Utils
. openSpiceViewer ( url
, params
);
1045 } else if ( vmtype
=== 'shell' ) {
1046 url
= '/nodes/' + nodename
+ '/spiceshell' ;
1047 PVE
. Utils
. openSpiceViewer ( url
, params
);
1048 } else if ( vmtype
=== 'upgrade' ) {
1049 url
= '/nodes/' + nodename
+ '/spiceshell' ;
1051 PVE
. Utils
. openSpiceViewer ( url
, params
);
1052 } else if ( vmtype
=== 'cmd' ) {
1053 url
= '/nodes/' + nodename
+ '/spiceshell' ;
1055 PVE
. Utils
. openSpiceViewer ( url
, params
);
1058 throw "unknown viewer type" ;
1062 defaultViewer : function ( consoles
) {
1064 var allowSpice
, allowXtermjs
;
1066 if ( consoles
=== true ) {
1068 allowXtermjs
= true ;
1069 } else if ( typeof consoles
=== 'object' ) {
1070 allowSpice
= consoles
. spice
;
1071 allowXtermjs
= !! consoles
. xtermjs
;
1073 var dv
= PVE
. VersionInfo
. console
|| 'xtermjs' ;
1074 if ( dv
=== 'vv' && ! allowSpice
) {
1075 dv
= ( allowXtermjs
) ? 'xtermjs' : 'html5' ;
1076 } else if ( dv
=== 'xtermjs' && ! allowXtermjs
) {
1077 dv
= ( allowSpice
) ? 'vv' : 'html5' ;
1083 openVNCViewer : function ( vmtype
, vmid
, nodename
, vmname
, cmd
) {
1084 let scaling
= 'off' ;
1085 if ( Proxmox
. Utils
. toolkit
!== 'touch' ) {
1086 var sp
= Ext
. state
. Manager
. getProvider ();
1087 scaling
= sp
. get ( 'novnc-scaling' , 'off' );
1089 var url
= Ext
. Object
. toQueryString ({
1090 console
: vmtype
, // kvm, lxc, upgrade or shell
1098 var nw
= window
. open ( "?" + url
, '_blank' , "innerWidth=745,innerheight=427" );
1104 openSpiceViewer : function ( url
, params
){
1106 var downloadWithName = function ( uri
, name
) {
1107 var link
= Ext
. DomHelper
. append ( document
. body
, {
1110 css
: 'display:none;visibility:hidden;height:0px;'
1113 // Note: we need to tell android the correct file name extension
1114 // but we do not set 'download' tag for other environments, because
1115 // It can have strange side effects (additional user prompt on firefox)
1116 var andriod
= navigator
. userAgent
. match ( /Android/i ) ? true : false ;
1118 link
. download
= name
;
1121 if ( link
. fireEvent
) {
1122 link
. fireEvent ( 'onclick' );
1124 var evt
= document
. createEvent ( "MouseEvents" );
1125 evt
. initMouseEvent ( 'click' , true , true , window
, 1 , 0 , 0 , 0 , 0 , false , false , false , false , 0 , null );
1126 link
. dispatchEvent ( evt
);
1130 Proxmox
. Utils
. API2Request ({
1134 failure : function ( response
, opts
){
1135 Ext
. Msg
. alert ( 'Error' , response
. htmlStatus
);
1137 success : function ( response
, opts
){
1138 var raw
= "[virt-viewer] \n " ;
1139 Ext
. Object
. each ( response
. result
. data
, function ( k
, v
) {
1140 raw
+= k
+ "=" + v
+ " \n " ;
1142 var url
= 'data:application/x-virt-viewer;charset=UTF-8,' +
1143 encodeURIComponent ( raw
);
1145 downloadWithName ( url
, "pve-spice.vv" );
1150 openTreeConsole : function ( tree
, record
, item
, index
, e
) {
1152 var nodename
= record
. data
. node
;
1153 var vmid
= record
. data
. vmid
;
1154 var vmname
= record
. data
. name
;
1155 if ( record
. data
. type
=== 'qemu' && ! record
. data
. template
) {
1156 Proxmox
. Utils
. API2Request ({
1157 url
: '/nodes/' + nodename
+ '/qemu/' + vmid
+ '/status/current' ,
1158 failure : function ( response
, opts
) {
1159 Ext
. Msg
. alert ( 'Error' , response
. htmlStatus
);
1161 success : function ( response
, opts
) {
1162 let conf
= response
. result
. data
;
1164 spice
: !! conf
. spice
,
1165 xtermjs
: !! conf
. serial
,
1167 PVE
. Utils
. openDefaultConsoleWindow ( consoles
, 'kvm' , vmid
, nodename
, vmname
);
1170 } else if ( record
. data
. type
=== 'lxc' && ! record
. data
. template
) {
1171 PVE
. Utils
. openDefaultConsoleWindow ( true , 'lxc' , vmid
, nodename
, vmname
);
1175 // test automation helper
1176 call_menu_handler : function ( menu
, text
) {
1178 var list
= menu
. query ( 'menuitem' );
1180 Ext
. Array
. each ( list
, function ( item
) {
1181 if ( item
. text
=== text
) {
1192 createCmdMenu : function ( v
, record
, item
, index
, event
) {
1194 if (!( v
instanceof Ext
. tree
. View
)) {
1198 var template
= !! record
. data
. template
;
1199 var type
= record
. data
. type
;
1202 if ( type
=== 'qemu' || type
== 'lxc' ) {
1203 menu
= Ext
. create ( 'PVE.menu.TemplateMenu' , {
1207 } else if ( type
=== 'qemu' ||
1210 menu
= Ext
. create ( 'PVE.' + type
+ '.CmdMenu' , {
1212 nodename
: record
. data
. node
1218 menu
. showAt ( event
. getXY ());
1222 // helper for deleting field which are set to there default values
1223 delete_if_default : function ( values
, fieldname
, default_val
, create
) {
1224 if ( values
[ fieldname
] === '' || values
[ fieldname
] === default_val
) {
1226 if ( values
[ 'delete' ]) {
1227 values
[ 'delete' ] += ',' + fieldname
;
1229 values
[ 'delete' ] = fieldname
;
1233 delete values
[ fieldname
];
1237 loadSSHKeyFromFile : function ( file
, callback
) {
1238 // ssh-keygen produces 740 bytes for an average 4096 bit rsa key, with
1239 // a user@host comment, 1420 for 8192 bits; current max is 16kbit
1240 // assume: 740*8 for max. 32kbit (5920 byte file)
1241 // round upwards to nearest nice number => 8192 bytes, leaves lots of comment space
1242 if ( file
. size
> 8192 ) {
1243 Ext
. Msg
. alert ( gettext ( 'Error' ), gettext ( "Invalid file size: " ) + file
. size
);
1249 var reader
= new FileReader ();
1250 reader
. onload = function ( evt
) {
1251 callback ( evt
. target
. result
);
1253 reader
. readAsText ( file
);
1256 diskControllerMaxIDs
: {
1263 // types is either undefined (all busses), an array of busses, or a single bus
1264 forEachBus : function ( types
, func
) {
1265 var busses
= Object
. keys ( PVE
. Utils
. diskControllerMaxIDs
);
1266 var i
, j
, count
, cont
;
1268 if ( Ext
. isArray ( types
)) {
1270 } else if ( Ext
. isDefined ( types
)) {
1274 // check if we only have valid busses
1275 for ( i
= 0 ; i
< busses
. length
; i
++) {
1276 if (! PVE
. Utils
. diskControllerMaxIDs
[ busses
[ i
]]) {
1277 throw "invalid bus: '" + busses
[ i
] + "'" ;
1281 for ( i
= 0 ; i
< busses
. length
; i
++) {
1282 count
= PVE
. Utils
. diskControllerMaxIDs
[ busses
[ i
]];
1283 for ( j
= 0 ; j
< count
; j
++) {
1284 cont
= func ( busses
[ i
], j
);
1285 if (! cont
&& cont
!== undefined ) {
1292 mp_counts
: { mps
: 256 , unused
: 256 },
1294 forEachMP : function ( func
, includeUnused
) {
1296 for ( i
= 0 ; i
< PVE
. Utils
. mp_counts
. mps
; i
++) {
1297 cont
= func ( 'mp' , i
);
1298 if (! cont
&& cont
!== undefined ) {
1303 if (! includeUnused
) {
1307 for ( i
= 0 ; i
< PVE
. Utils
. mp_counts
. unused
; i
++) {
1308 cont
= func ( 'unused' , i
);
1309 if (! cont
&& cont
!== undefined ) {
1315 hardware_counts
: { net
: 32 , usb
: 5 , hostpci
: 16 , audio
: 1 , efidisk
: 1 , serial
: 4 , rng
: 1 },
1317 cleanEmptyObjectKeys : function ( obj
) {
1319 for ( propName
in obj
) {
1320 if ( obj
. hasOwnProperty ( propName
)) {
1321 if ( obj
[ propName
] === null || obj
[ propName
] === undefined ) {
1322 delete obj
[ propName
];
1328 handleStoreErrorOrMask : function ( me
, store
, regex
, callback
) {
1330 me
. mon ( store
, 'load' , function ( proxy
, response
, success
, operation
) {
1333 Proxmox
. Utils
. setErrorMask ( me
, false );
1338 if ( operation
. error
. statusText
) {
1339 if ( operation
. error
. statusText
. match ( regex
)) {
1340 callback ( me
, operation
. error
);
1343 msg
= operation
. error
. statusText
+ ' (' + operation
. error
. status
+ ')' ;
1346 msg
= gettext ( 'Connection error' );
1348 Proxmox
. Utils
. setErrorMask ( me
, msg
);
1352 showCephInstallOrMask : function ( container
, msg
, nodename
, callback
){
1353 var regex
= new RegExp ( "not (installed|initialized)" , "i" );
1354 if ( msg
. match ( regex
)) {
1355 if ( Proxmox
. UserName
=== 'root@pam' ) {
1356 container
. el
. mask ();
1357 if (! container
. down ( 'pveCephInstallWindow' )){
1358 var isInstalled
= msg
. match ( /not initialized/i ) ? true : false ;
1359 var win
= Ext
. create ( 'PVE.ceph.Install' , {
1362 win
. getViewModel (). set ( 'isInstalled' , isInstalled
);
1368 container
. mask ( Ext
. String
. format ( gettext ( '{0} not installed.' ) +
1369 ' ' + gettext ( 'Log in as root to install.' ), 'Ceph' ), [ 'pve-static-mask' ]);
1377 propertyStringSet : function ( target
, source
, name
, value
) {
1379 if ( value
=== undefined ) {
1380 target
[ name
] = source
;
1382 target
[ name
] = value
;
1385 delete target
[ name
];
1389 updateColumns : function ( container
) {
1390 let mode
= Ext
. state
. Manager
. get ( 'summarycolumns' ) || 'auto' ;
1392 if ( mode
!== 'auto' ) {
1393 factor
= parseInt ( mode
, 10 );
1394 if ( Number
. isNaN ( factor
)) {
1398 factor
= container
. getSize (). width
< 1400 ? 1 : 2 ;
1401 if ( container
. oldFactor
=== factor
) {
1405 let items
= container
. query ( '>' ); // direct childs
1406 factor
= Math
. min ( factor
, items
. length
);
1407 container
. oldFactor
= factor
;
1409 items
. forEach (( item
) => {
1410 item
. columnWidth
= 1 / factor
;
1413 // we have to update the layout twice, since the first layout change
1414 // can trigger the scrollbar which reduces the amount of space left
1415 container
. updateLayout ();
1416 container
. updateLayout ();
1419 forEachCorosyncLink : function ( nodeinfo
, cb
) {
1420 let re
= /(?:ring|link)(\d+)_addr/ ;
1421 Ext
. iterate ( nodeinfo
, ( prop
, val
) => {
1422 let match
= re
. exec ( prop
);
1424 cb ( Number ( match
[ 1 ]), val
);
1431 constructor : function () {
1433 Ext
. apply ( me
, me
. utilities
);