// avoid errors when running without development tools
if (!Ext.isDefined(Ext.global.console)) {
var console = {
- log: function() {}
+ log: function() {},
};
}
console.log("Starting PVE Manager");
Ext.Ajax.defaultHeaders = {
- 'Accept': 'application/json'
+ 'Accept': 'application/json',
};
-Ext.define('PVE.Utils', { utilities: {
+Ext.define('PVE.Utils', {
+ utilities: {
// this singleton contains miscellaneous utilities
4: "warning",
5: "notice",
6: "info",
- 7: "debug"
+ 7: "debug",
},
support_level_hash: {
'c': gettext('Community'),
'b': gettext('Basic'),
's': gettext('Standard'),
- 'p': gettext('Premium')
+ 'p': gettext('Premium'),
},
- 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.',
+ 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.',
kvm_ostypes: {
'Linux': [
{ desc: '5.x - 2.6 Kernel', val: 'l26' },
- { desc: '2.4 Kernel', val: 'l24' }
+ { desc: '2.4 Kernel', val: 'l24' },
],
'Microsoft Windows': [
{ desc: '10/2016/2019', val: 'win10' },
{ desc: '7/2008r2', val: 'win7' },
{ desc: 'Vista/2008', val: 'w2k8' },
{ desc: 'XP/2003', val: 'wxp' },
- { desc: '2000', val: 'w2k' }
+ { desc: '2000', val: 'w2k' },
],
'Solaris Kernel': [
- { desc: '-', val: 'solaris'}
+ { desc: '-', val: 'solaris' },
],
'Other': [
- { desc: '-', val: 'other'}
- ]
+ { desc: '-', val: 'other' },
+ ],
+ },
+
+ is_windows: function(ostype) {
+ for (let entry of PVE.Utils.kvm_ostypes['Microsoft Windows']) {
+ if (entry.val === ostype) {
+ return true;
+ }
+ }
+ return false;
},
get_health_icon: function(state, circle) {
}
var icon = 'faded fa-question';
- switch(state) {
+ switch (state) {
case 'good':
icon = 'good fa-check';
break;
if (av === undefined && bv === undefined) {
return 0;
- } else if (av === undefined) {
+ } else if (av === undefined) {
return -1;
} else if (bv === undefined) {
return 1;
// else we need to look at the next parts
}
}
-
},
get_ceph_icon_html: function(health, fw) {
},
map_ceph_health: {
- 'HEALTH_OK':'good',
- 'HEALTH_UPGRADE':'upgrade',
- 'HEALTH_OLD':'old',
- 'HEALTH_WARN':'warning',
- 'HEALTH_ERR':'critical'
+ 'HEALTH_OK': 'good',
+ 'HEALTH_UPGRADE': 'upgrade',
+ 'HEALTH_OLD': 'old',
+ 'HEALTH_WARN': 'warning',
+ 'HEALTH_ERR': 'critical',
},
render_ceph_health: function(healthObj) {
var state = {
iconCls: PVE.Utils.get_health_icon(),
- text: ''
+ text: '',
};
if (!healthObj || !healthObj.status) {
},
render_zfs_health: function(value) {
- if (typeof value == 'undefined'){
+ if (typeof value == 'undefined') {
return "";
}
var iconCls = 'question-circle';
}
return '<i class="fa fa-' + iconCls + '"></i> ' + value;
+ },
+
+ render_pbs_fingerprint: fp => fp.substring(0, 23),
+ render_backup_encryption: function(v, meta, record) {
+ if (!v) {
+ return gettext('No');
+ }
+
+ let tip = '';
+ if (v.match(/^[a-fA-F0-9]{2}:/)) { // fingerprint
+ tip = `Key fingerprint ${PVE.Utils.render_pbs_fingerprint(v)}`;
+ }
+ let icon = `<i class="fa fa-fw fa-lock good"></i>`;
+ return `<span data-qtip="${tip}">${icon} ${gettext('Encrypted')}</span>`;
+ },
+
+ render_backup_verification: function(v, meta, record) {
+ let i = (cls, txt) => `<i class="fa fa-fw fa-${cls}"></i> ${txt}`;
+ if (v === undefined || v === null) {
+ return i('question-circle-o warning', gettext('None'));
+ }
+ let tip = "";
+ let txt = gettext('Failed');
+ let iconCls = 'times critical';
+ if (v.state === 'ok') {
+ txt = gettext('OK');
+ iconCls = 'check good';
+ let now = Date.now() / 1000;
+ let task = Proxmox.Utils.parse_task_upid(v.upid);
+ let verify_time = Proxmox.Utils.render_timestamp(task.starttime);
+ tip = `Last verify task started on ${verify_time}`;
+ if (now - v.starttime > 30 * 24 * 60 * 60) {
+ tip = `Last verify task over 30 days ago: ${verify_time}`;
+ iconCls = 'check warning';
+ }
+ }
+ return `<span data-qtip="${tip}"> ${i(iconCls, txt)} </span>`;
},
render_backup_status: function(value, meta, record) {
var dows = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
var selected = [];
var cur = -1;
- val.split(',').forEach(function(day){
+ val.split(',').forEach(function(day) {
cur++;
var dow = (dows.indexOf(day)+6)%7;
if (cur === dow) {
selected.forEach(function(item) {
cur++;
if (item > 2) {
- days.push(Ext.Date.dayNames[(cur+1)] + '-' + Ext.Date.dayNames[(cur+item)%7]);
+ days.push(Ext.Date.dayNames[cur+1] + '-' + Ext.Date.dayNames[(cur+item)%7]);
cur += item-1;
} else if (item == 2) {
days.push(Ext.Date.dayNames[cur+1]);
return info;
},
- render_kvm_ostype: function (value) {
+ render_kvm_ostype: function(value) {
var osinfo = PVE.Utils.get_kvm_osinfo(value);
if (osinfo.desc && osinfo.desc !== '-') {
return osinfo.base + ' ' + osinfo.desc;
}
},
- render_hotplug_features: function (value) {
+ render_hotplug_features: function(value) {
var fa = [];
- if (!value || (value === '0')) {
+ if (!value || value === '0') {
return gettext('Disabled');
}
render_qga_features: function(value) {
if (!value) {
- return Proxmox.Utils.defaultText + ' (' + Proxmox.Utils.disabledText + ')';
+ return Proxmox.Utils.defaultText + ' (' + Proxmox.Utils.disabledText + ')';
}
var props = PVE.Parser.parsePropertyString(value, 'enabled');
if (!PVE.Parser.parseBoolean(props.enabled)) {
var agentstring = Proxmox.Utils.enabledText;
Ext.Object.each(props, function(key, value) {
- var keystring = '' ;
+ var keystring = '';
agentstring += ', ' + key + ': ';
if (key === 'type') {
},
render_qemu_machine: function(value) {
- return value || (Proxmox.Utils.defaultText + ' (i440fx)');
+ return value || Proxmox.Utils.defaultText + ' (i440fx)';
},
render_qemu_bios: function(value) {
}
},
render_as_property_string: function(value) {
- return (!value) ? Proxmox.Utils.defaultText
+ return !value ? Proxmox.Utils.defaultText
: PVE.Parser.printPropertyString(value);
},
sl: 'Slovenian',
sv: 'Swedish',
//th: 'Thai',
- tr: 'Turkish'
+ tr: 'Turkish',
},
kvm_vga_drivers: {
serial2: gettext('Serial terminal') + ' 2',
serial3: gettext('Serial terminal') + ' 3',
virtio: 'VirtIO-GPU',
- none: Proxmox.Utils.noneText
+ none: Proxmox.Utils.noneText,
},
- render_kvm_language: function (value) {
+ render_kvm_language: function(value) {
if (!value || value === '__default__') {
return Proxmox.Utils.defaultText;
}
'__default__': Proxmox.Utils.defaultText + ' (xterm.js)',
'vv': 'SPICE (remote-viewer)',
'html5': 'HTML5 (noVNC)',
- 'xtermjs': 'xterm.js'
+ 'xtermjs': 'xterm.js',
},
render_console_viewer: function(value) {
});
},
- render_kvm_vga_driver: function (value) {
+ render_kvm_vga_driver: function(value) {
if (!value) {
return Proxmox.Utils.defaultText;
}
'vztmpl': gettext('Container template'),
'iso': gettext('ISO image'),
'rootdir': gettext('Container'),
- 'snippets': gettext('Snippets')
+ 'snippets': gettext('Snippets'),
},
volume_is_qemu_backup: function(volid, format) {
dir: {
name: Proxmox.Utils.directoryText,
ipanel: 'DirInputPanel',
- faIcon: 'folder'
+ faIcon: 'folder',
+ backups: true,
},
lvm: {
name: 'LVM',
ipanel: 'LVMInputPanel',
- faIcon: 'folder'
+ faIcon: 'folder',
+ backups: false,
},
lvmthin: {
name: 'LVM-Thin',
ipanel: 'LvmThinInputPanel',
- faIcon: 'folder'
+ faIcon: 'folder',
+ backups: false,
},
nfs: {
name: 'NFS',
ipanel: 'NFSInputPanel',
- faIcon: 'building'
+ faIcon: 'building',
+ backups: true,
},
cifs: {
name: 'CIFS',
ipanel: 'CIFSInputPanel',
- faIcon: 'building'
+ faIcon: 'building',
+ backups: true,
},
glusterfs: {
name: 'GlusterFS',
ipanel: 'GlusterFsInputPanel',
- faIcon: 'building'
+ faIcon: 'building',
+ backups: true,
},
iscsi: {
name: 'iSCSI',
ipanel: 'IScsiInputPanel',
- faIcon: 'building'
+ faIcon: 'building',
+ backups: false,
},
cephfs: {
name: 'CephFS',
ipanel: 'CephFSInputPanel',
- faIcon: 'building'
+ faIcon: 'building',
+ backups: true,
},
pvecephfs: {
name: 'CephFS (PVE)',
ipanel: 'CephFSInputPanel',
hideAdd: true,
- faIcon: 'building'
+ faIcon: 'building',
+ backups: true,
},
rbd: {
name: 'RBD',
ipanel: 'RBDInputPanel',
- faIcon: 'building'
+ faIcon: 'building',
+ backups: false,
},
pveceph: {
name: 'RBD (PVE)',
ipanel: 'RBDInputPanel',
hideAdd: true,
- faIcon: 'building'
+ faIcon: 'building',
+ backups: false,
},
zfs: {
name: 'ZFS over iSCSI',
ipanel: 'ZFSInputPanel',
- faIcon: 'building'
+ faIcon: 'building',
+ backups: false,
},
zfspool: {
name: 'ZFS',
ipanel: 'ZFSPoolInputPanel',
- faIcon: 'folder'
+ faIcon: 'folder',
+ backups: false,
},
pbs: {
name: 'Proxmox Backup Server',
ipanel: 'PBSInputPanel',
faIcon: 'floppy-o',
+ backups: true,
},
drbd: {
name: 'DRBD',
hideAdd: true,
+ backups: false,
},
},
sdnvnetSchema: {
vnet: {
name: 'vnet',
- faIcon: 'folder'
+ faIcon: 'folder',
},
},
sdnzoneSchema: {
zone: {
name: 'zone',
- hideAdd: true
+ hideAdd: true,
},
simple: {
name: 'Simple',
ipanel: 'SimpleInputPanel',
- faIcon: 'th'
+ faIcon: 'th',
},
vlan: {
name: 'VLAN',
ipanel: 'VlanInputPanel',
- faIcon: 'th'
+ faIcon: 'th',
},
qinq: {
name: 'QinQ',
ipanel: 'QinQInputPanel',
- faIcon: 'th'
+ faIcon: 'th',
},
vxlan: {
name: 'VXLAN',
ipanel: 'VxlanInputPanel',
- faIcon: 'th'
+ faIcon: 'th',
},
evpn: {
name: 'EVPN',
ipanel: 'EvpnInputPanel',
- faIcon: 'th'
+ faIcon: 'th',
},
},
sdncontrollerSchema: {
controller: {
name: 'controller',
- hideAdd: true
+ hideAdd: true,
},
evpn: {
name: 'evpn',
ipanel: 'EvpnInputPanel',
- faIcon: 'crosshairs'
+ faIcon: 'crosshairs',
},
},
format_storage_type: function(value, md, record) {
if (value === 'rbd') {
- value = (!record || record.get('monhost') ? 'rbd' : 'pveceph');
+ value = !record || record.get('monhost') ? 'rbd' : 'pveceph';
} else if (value === 'cephfs') {
- value = (!record || record.get('monhost') ? 'cephfs' : 'pvecephfs');
+ value = !record || record.get('monhost') ? 'cephfs' : 'pvecephfs';
}
var schema = PVE.Utils.storageSchema[value];
if (value.managed) {
text = value.state || Proxmox.Utils.noneText;
- text += ', ' + Proxmox.Utils.groupText + ': ';
+ text += ', ' + Proxmox.Utils.groupText + ': ';
text += value.group || Proxmox.Utils.noneText;
}
Ext.isNumber(data.id) &&
Ext.isNumber(data.lun)) {
return "CH " +
- Ext.String.leftPad(data.channel,2, '0') +
+ Ext.String.leftPad(data.channel, 2, '0') +
" ID " + data.id + " LUN " + data.lun;
}
- return data.volid.replace(/^.*?:(.*?\/)?/,'');
+ return data.volid.replace(/^.*?:(.*?\/)?/, '');
},
- render_serverity: function (value) {
+ render_serverity: function(value) {
return PVE.Utils.log_severity_hash[value] || value;
},
- render_cpu: function(value, metaData, record, rowIndex, colIndex, store) {
+ calculate_hostcpu: function(data) {
- if (!(record.data.uptime && Ext.isNumeric(value))) {
- return '';
+ if (!(data.uptime && Ext.isNumeric(data.cpu))) {
+ return -1;
}
- var maxcpu = record.data.maxcpu || 1;
+ if (data.type !== 'qemu' && data.type !== 'lxc') {
+ return -1;
+ }
- if (!Ext.isNumeric(maxcpu) && (maxcpu >= 1)) {
- return '';
+ var index = PVE.data.ResourceStore.findExact('id', 'node/' + data.node);
+ var node = PVE.data.ResourceStore.getAt(index);
+ if (!Ext.isDefined(node) || node === null) {
+ return -1;
}
+ var maxcpu = node.data.maxcpu || 1;
- var per = value * 100;
+ if (!Ext.isNumeric(maxcpu) && (maxcpu >= 1)) {
+ return -1;
+ }
- return per.toFixed(1) + '% of ' + maxcpu.toString() + (maxcpu > 1 ? 'CPUs' : 'CPU');
+ return ((data.cpu/maxcpu) * data.maxcpu);
},
- render_size: function(value, metaData, record, rowIndex, colIndex, store) {
+ render_hostcpu: function(value, metaData, record, rowIndex, colIndex, store) {
- if (!Ext.isNumeric(value)) {
+ if (!(record.data.uptime && Ext.isNumeric(record.data.cpu))) {
+ return '';
+ }
+
+ if (record.data.type !== 'qemu' && record.data.type !== 'lxc') {
return '';
}
- return Proxmox.Utils.format_size(value);
+ var index = PVE.data.ResourceStore.findExact('id', 'node/' + record.data.node);
+ var node = PVE.data.ResourceStore.getAt(index);
+ if (!Ext.isDefined(node) || node === null) {
+ return '';
+ }
+ var maxcpu = node.data.maxcpu || 1;
+
+ if (!Ext.isNumeric(maxcpu) && (maxcpu >= 1)) {
+ return '';
+ }
+
+ var per = (record.data.cpu/maxcpu) * record.data.maxcpu * 100;
+
+ return per.toFixed(1) + '% of ' + maxcpu.toString() + (maxcpu > 1 ? 'CPUs' : 'CPU');
},
render_bandwidth: function(value) {
return -1;
}
- return (data.mem / data.maxmem);
+ return data.mem / data.maxmem;
+ },
+
+ calculate_hostmem_usage: function(data) {
+
+ if (data.type !== 'qemu' && data.type !== 'lxc') {
+ return -1;
+ }
+
+ var index = PVE.data.ResourceStore.findExact('id', 'node/' + data.node);
+ var node = PVE.data.ResourceStore.getAt(index);
+
+ if (!Ext.isDefined(node) || node === null) {
+ return -1;
+ }
+ var maxmem = node.data.maxmem || 0;
+
+ if (!Ext.isNumeric(data.mem) ||
+ maxmem === 0 ||
+ data.uptime < 1) {
+ return -1;
+ }
+
+ return (data.mem / maxmem);
},
render_mem_usage_percent: function(value, metaData, record, rowIndex, colIndex, store) {
if (!Ext.isNumeric(value) || value === -1) {
return '';
}
- if (value > 1 ) {
+ if (value > 1) {
// we got no percentage but bytes
var mem = value;
var maxmem = record.data.maxmem;
return '';
}
+ return (mem*100/maxmem).toFixed(1) + " %";
+ }
+ return (value*100).toFixed(1) + " %";
+ },
+
+ render_hostmem_usage_percent: function(value, metaData, record, rowIndex, colIndex, store) {
+
+ if (!Ext.isNumeric(record.data.mem) || value === -1) {
+ return '';
+ }
+
+ if (record.data.type !== 'qemu' && record.data.type !== 'lxc') {
+ return '';
+ }
+
+ var index = PVE.data.ResourceStore.findExact('id', 'node/' + record.data.node);
+ var node = PVE.data.ResourceStore.getAt(index);
+ var maxmem = node.data.maxmem || 0;
+
+ if (record.data.mem > 1 ) {
+ // we got no percentage but bytes
+ var mem = record.data.mem;
+ if (!record.data.uptime ||
+ maxmem === 0 ||
+ !Ext.isNumeric(mem)) {
+ return '';
+ }
+
return ((mem*100)/maxmem).toFixed(1) + " %";
}
return (value*100).toFixed(1) + " %";
},
render_mem_usage: function(value, metaData, record, rowIndex, colIndex, store) {
-
var mem = value;
var maxmem = record.data.maxmem;
return '';
}
- return PVE.Utils.render_size(value);
+ return Proxmox.Utils.render_size(value);
},
calculate_disk_usage: function(data) {
-
if (!Ext.isNumeric(data.disk) ||
data.type === 'qemu' ||
- (data.type === 'lxc' && data.uptime === 0) ||
+ data.type === 'lxc' && data.uptime === 0 ||
data.maxdisk === 0) {
return -1;
}
- return (data.disk / data.maxdisk);
+ return data.disk / data.maxdisk;
},
render_disk_usage_percent: function(value, metaData, record, rowIndex, colIndex, store) {
},
render_disk_usage: function(value, metaData, record, rowIndex, colIndex, store) {
-
var disk = value;
var maxdisk = record.data.maxdisk;
var type = record.data.type;
if (!Ext.isNumeric(disk) ||
type === 'qemu' ||
maxdisk === 0 ||
- (type === 'lxc' && record.data.uptime === 0)) {
+ type === 'lxc' && record.data.uptime === 0) {
return '';
}
- return PVE.Utils.render_size(value);
+ return Proxmox.Utils.render_size(value);
},
get_object_icon_class: function(type, record) {
},
render_resource_type: function(value, metaData, record, rowIndex, colIndex, store) {
+ var cls = PVE.Utils.get_object_icon_class(value, record.data);
- var cls = PVE.Utils.get_object_icon_class(value,record.data);
-
- var fa = '<i class="fa-fw x-grid-icon-custom ' + cls + '"></i> ';
+ var fa = '<i class="fa-fw x-grid-icon-custom ' + cls + '"></i> ';
return fa + value;
},
return Proxmox.Utils.format_task_description(type, id);
},
- /* render functions for new status panel */
-
- render_usage: function(val) {
- return (val*100).toFixed(2) + '%';
- },
-
- render_cpu_usage: function(val, max) {
- return Ext.String.format(gettext('{0}% of {1}') +
- ' ' + gettext('CPU(s)'), (val*100).toFixed(2), max);
- },
-
- render_size_usage: function(val, max) {
- if (max === 0) {
- return gettext('N/A');
- }
- return (val*100/max).toFixed(2) + '% '+ '(' +
- Ext.String.format(gettext('{0} of {1}'),
- PVE.Utils.render_size(val), PVE.Utils.render_size(max)) + ')';
- },
-
- /* this is different for nodes */
- render_node_cpu_usage: function(value, record) {
- return PVE.Utils.render_cpu_usage(value, record.cpus);
- },
-
- /* this is different for nodes */
- render_node_size_usage: function(record) {
- return PVE.Utils.render_size_usage(record.used, record.total);
- },
-
render_optional_url: function(value) {
var match;
if (value && (match = value.match(/^https?:\/\//)) !== null) {
'2': gettext('Bad Request'),
'3': gettext('Configuration Unsupported'),
'4': gettext('Device Ineligible'),
- '5': gettext('Timeout')
+ '5': gettext('Timeout'),
};
- return "U2F Error: " + ErrorNames[error] || Proxmox.Utils.unknownText;
+ return "U2F Error: " + ErrorNames[error] || Proxmox.Utils.unknownText;
},
windowHostname: function() {
},
openDefaultConsoleWindow: function(consoles, consoleType, vmid, nodename, vmname, cmd) {
- var dv = PVE.Utils.defaultViewer(consoles);
+ var dv = PVE.Utils.defaultViewer(consoles, consoleType);
PVE.Utils.openConsoleWindow(dv, consoleType, vmid, nodename, vmname, cmd);
},
}
},
- defaultViewer: function(consoles) {
-
+ defaultViewer: function(consoles, type) {
var allowSpice, allowXtermjs;
if (consoles === true) {
allowSpice = consoles.spice;
allowXtermjs = !!consoles.xtermjs;
}
- var dv = PVE.VersionInfo.console || 'xtermjs';
+ let dv = PVE.VersionInfo.console || (type === 'kvm' ? 'vv' : 'xtermjs');
if (dv === 'vv' && !allowSpice) {
- dv = (allowXtermjs) ? 'xtermjs' : 'html5';
+ dv = allowXtermjs ? 'xtermjs' : 'html5';
} else if (dv === 'xtermjs' && !allowXtermjs) {
- dv = (allowSpice) ? 'vv' : 'html5';
+ dv = allowSpice ? 'vv' : 'html5';
}
return dv;
vmname: vmname,
node: nodename,
resize: scaling,
- cmd: cmd
+ cmd: cmd,
});
var nw = window.open("?" + url, '_blank', "innerWidth=745,innerheight=427");
if (nw) {
}
},
- openSpiceViewer: function(url, params){
-
+ openSpiceViewer: function(url, params) {
var downloadWithName = function(uri, name) {
var link = Ext.DomHelper.append(document.body, {
tag: 'a',
href: uri,
- css : 'display:none;visibility:hidden;height:0px;'
+ css: 'display:none;visibility:hidden;height:0px;',
});
- // Note: we need to tell android the correct file name extension
+ // Note: we need to tell Android and Chrome the correct file name extension
// but we do not set 'download' tag for other environments, because
// It can have strange side effects (additional user prompt on firefox)
- var andriod = navigator.userAgent.match(/Android/i) ? true : false;
- if (andriod) {
+ if (navigator.userAgent.match(/Android|Chrome/i)) {
link.download = name;
}
url: url,
params: params,
method: 'POST',
- failure: function(response, opts){
+ failure: function(response, opts) {
Ext.Msg.alert('Error', response.htmlStatus);
},
- success: function(response, opts){
+ success: function(response, opts) {
var raw = "[virt-viewer]\n";
Ext.Object.each(response.result.data, function(k, v) {
raw += k + "=" + v + "\n";
encodeURIComponent(raw);
downloadWithName(url, "pve-spice.vv");
- }
+ },
});
},
xtermjs: !!conf.serial,
};
PVE.Utils.openDefaultConsoleWindow(consoles, 'kvm', vmid, nodename, vmname);
- }
+ },
});
} else if (record.data.type === 'lxc' && !record.data.template) {
PVE.Utils.openDefaultConsoleWindow(true, 'lxc', vmid, nodename, vmname);
// test automation helper
call_menu_handler: function(menu, text) {
-
var list = menu.query('menuitem');
Ext.Array.each(list, function(item) {
if (template) {
if (type === 'qemu' || type == 'lxc') {
menu = Ext.create('PVE.menu.TemplateMenu', {
- pveSelNode: record
+ pveSelNode: record,
});
}
} else if (type === 'qemu' ||
type === 'node') {
menu = Ext.create('PVE.' + type + '.CmdMenu', {
pveSelNode: record,
- nodename: record.data.node
+ nodename: record.data.node,
});
} else {
return;
delete_if_default: function(values, fieldname, default_val, create) {
if (values[fieldname] === '' || values[fieldname] === default_val) {
if (!create) {
- if (values['delete']) {
- if (Ext.isArray(values['delete'])) {
- values['delete'].push(fieldname);
+ if (values.delete) {
+ if (Ext.isArray(values.delete)) {
+ values.delete.push(fieldname);
} else {
- values['delete'] += ',' + fieldname;
+ values.delete += ',' + fieldname;
}
} else {
- values['delete'] = fieldname;
+ values.delete = fieldname;
}
}
reader.readAsText(file);
},
+ loadTextFromFile: function(file, callback, maxBytes) {
+ let maxSize = maxBytes || 8192;
+ if (file.size > maxSize) {
+ Ext.Msg.alert(gettext('Error'), gettext("Invalid file size: ") + file.size);
+ return;
+ }
+ /*global
+ FileReader
+ */
+ let reader = new FileReader();
+ reader.onload = evt => callback(evt.target.result);
+ reader.readAsText(file);
+ },
+
diskControllerMaxIDs: {
ide: 4,
sata: 6,
if (Ext.isArray(types)) {
busses = types;
} else if (Ext.isDefined(types)) {
- busses = [ types ];
+ busses = [types];
}
// check if we only have valid busses
hardware_counts: { net: 32, usb: 5, hostpci: 16, audio: 1, efidisk: 1, serial: 4, rng: 1 },
- cleanEmptyObjectKeys: function (obj) {
+ cleanEmptyObjectKeys: function(obj) {
var propName;
for (propName in obj) {
if (obj.hasOwnProperty(propName)) {
acme.domains = [domain];
} else {
acme.domains.push(domain);
- acme.domains = acme.domains.filter((value, index, self) => {
- return self.indexOf(value) === index;
- });
+ acme.domains = acme.domains.filter((value, index, self) => self.indexOf(value) === index);
}
return acme;
},
remove_domain_from_acme: function(acme, domain) {
if (acme.domains !== undefined) {
- acme.domains = acme.domains.filter((value, index, self) => {
- return self.indexOf(value) === index && value !== domain;
- });
+ acme.domains = acme.domains.filter((value, index, self) => self.indexOf(value) === index && value !== domain);
}
return acme;
},
handleStoreErrorOrMask: function(me, store, regex, callback) {
-
- me.mon(store, 'load', function (proxy, response, success, operation) {
-
+ me.mon(store, 'load', function(proxy, response, success, operation) {
if (success) {
Proxmox.Utils.setErrorMask(me, false);
return;
});
},
- showCephInstallOrMask: function(container, msg, nodename, callback){
- var regex = new RegExp("not (installed|initialized)", "i");
- if (msg.match(regex)) {
+ showCephInstallOrMask: function(container, msg, nodename, callback) {
+ if (msg.match(/not (installed|initialized)/i)) {
if (Proxmox.UserName === 'root@pam') {
container.el.mask();
- if (!container.down('pveCephInstallWindow')){
- var isInstalled = msg.match(/not initialized/i) ? true : false;
+ if (!container.down('pveCephInstallWindow')) {
+ var isInstalled = !!msg.match(/not initialized/i);
var win = Ext.create('PVE.ceph.Install', {
- nodename: nodename
+ nodename: nodename,
});
win.getViewModel().set('isInstalled', isInstalled);
container.add(win);
}
},
+ monitor_ceph_installed: function(view, rstore, nodename, maskOwnerCt) {
+ PVE.Utils.handleStoreErrorOrMask(
+ view,
+ rstore,
+ /not (installed|initialized)/i,
+ (_, error) => {
+ nodename = nodename || 'localhost';
+ let maskTarget = maskOwnerCt ? view.ownerCt : view;
+ rstore.stopUpdate();
+ PVE.Utils.showCephInstallOrMask(maskTarget, error.statusText, nodename, win => {
+ view.mon(win, 'cephInstallWindowClosed', () => rstore.startUpdate());
+ });
+ },
+ );
+ },
+
+
propertyStringSet: function(target, source, name, value) {
if (source) {
if (value === undefined) {
}
},
- updateColumns: function(container) {
- let mode = Ext.state.Manager.get('summarycolumns') || 'auto';
- let factor;
- if (mode !== 'auto') {
- factor = parseInt(mode, 10);
- if (Number.isNaN(factor)) {
- factor = 1;
- }
- } else {
- factor = container.getSize().width < 1400 ? 1 : 2;
- }
-
- if (container.oldFactor === factor) {
- return;
- }
-
- let items = container.query('>'); // direct childs
- factor = Math.min(factor, items.length);
- container.oldFactor = factor;
-
- items.forEach((item) => {
- item.columnWidth = 1 / factor;
- });
-
- // we have to update the layout twice, since the first layout change
- // can trigger the scrollbar which reduces the amount of space left
- container.updateLayout();
- container.updateLayout();
- },
-
forEachCorosyncLink: function(nodeinfo, cb) {
let re = /(?:ring|link)(\d+)_addr/;
Ext.iterate(nodeinfo, (prop, val) => {
cpu_vendor_map: {
'default': 'QEMU',
'AuthenticAMD': 'AMD',
- 'GenuineIntel': 'Intel'
+ 'GenuineIntel': 'Intel',
},
cpu_vendor_order: {
"Host": 4,
"_default_": 5, // includes custom models
},
+
+ verify_ip64_address_list: function(value, with_suffix) {
+ for (let addr of value.split(/[ ,;]+/)) {
+ if (addr === '') {
+ continue;
+ }
+
+ if (with_suffix) {
+ let parts = addr.split('%');
+ addr = parts[0];
+
+ if (parts.length > 2) {
+ return false;
+ }
+
+ if (parts.length > 1 && !addr.startsWith('fe80:')) {
+ return false;
+ }
+ }
+
+ if (!Proxmox.Utils.IP64_match.test(addr)) {
+ return false;
+ }
+ }
+
+ return true;
+ },
},
singleton: true,
cephdestroyosd: ['Ceph OSD', gettext('Destroy')],
cephdestroypool: ['Ceph Pool', gettext('Destroy')],
cephfscreate: ['CephFS', gettext('Create')],
+ cephsetpool: ['Ceph Pool', gettext('Edit')],
+ cephsetflags: ['', gettext('Change global Ceph flags')],
clustercreate: ['', gettext('Create Cluster')],
clusterjoin: ['', gettext('Join Cluster')],
dircreate: [gettext('Directory Storage'), gettext('Create')],
lvmthincreate: [gettext('LVM-Thin Storage'), gettext('Create')],
migrateall: ['', gettext('Migrate all VMs and Containers')],
'move_volume': ['CT', gettext('Move Volume')],
+ 'pbs-download': ['VM/CT', gettext('File Restore Download')],
pull_file: ['CT', gettext('Pull file')],
push_file: ['CT', gettext('Push file')],
qmclone: ['VM', gettext('Clone')],
vzumount: ['CT', gettext('Unmount')],
zfscreate: [gettext('ZFS Storage'), gettext('Create')],
});
- }
+ },
});