Thomas Lamprecht a017d8aaa1 ui: make parsePropertyString less picky
simply return a empty object for cases we would get an exception
anyway, this is not wrong and allows easier usage for cases where
it's not sure if the value is set or not.

We could still do a Ext.isDebugEnabled() check and then throw up, but
this really should not matter much and I do not like if my debug mode
breaks and the non-debug not..

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2019-10-04 16:20:24 +02:00

700 lines
14 KiB
JavaScript

// Some configuration values are complex strings -
// so we need parsers/generators for them.
Ext.define('PVE.Parser', { statics: {
// this class only contains static functions
parseACME: function(value) {
if (!value) {
return;
}
var res = {};
var errors = false;
Ext.Array.each(value.split(','), function(p) {
if (!p || p.match(/^\s*$/)) {
return; //continue
}
var match_res;
if ((match_res = p.match(/^(?:domains=)?((?:[a-zA-Z0-9\-\.]+[;, ]?)+)$/)) !== null) {
res.domains = match_res[1].split(/[;, ]/);
} else {
errors = true;
return false;
}
});
if (errors || !res) {
return;
}
return res;
},
parseBoolean: function(value, default_value) {
if (!Ext.isDefined(value)) {
return default_value;
}
value = value.toLowerCase();
return value === '1' ||
value === 'on' ||
value === 'yes' ||
value === 'true';
},
parsePropertyString: function(value, defaultKey) {
var res = {},
error;
if (typeof value !== 'string' || value === '') {
return res;
}
Ext.Array.each(value.split(','), function(p) {
var kv = p.split('=', 2);
if (Ext.isDefined(kv[1])) {
res[kv[0]] = kv[1];
} else if (Ext.isDefined(defaultKey)) {
if (Ext.isDefined(res[defaultKey])) {
error = 'defaultKey may be only defined once in propertyString';
return false; // break
}
res[defaultKey] = kv[0];
} else {
error = 'invalid propertyString, not a key=value pair and no defaultKey defined';
return false; // break
}
});
if (error !== undefined) {
console.error(error);
return;
}
return res;
},
printPropertyString: function(data, defaultKey) {
var stringparts = [],
gotDefaultKeyVal = false,
defaultKeyVal;
Ext.Object.each(data, function(key, value) {
if (defaultKey !== undefined && key === defaultKey) {
gotDefaultKeyVal = true;
defaultKeyVal = value;
} else {
stringparts.push(key + '=' + value);
}
});
stringparts = stringparts.sort();
if (gotDefaultKeyVal) {
stringparts.unshift(defaultKeyVal);
}
return stringparts.join(',');
},
parseQemuNetwork: function(key, value) {
if (!(key && value)) {
return;
}
var res = {};
var errors = false;
Ext.Array.each(value.split(','), function(p) {
if (!p || p.match(/^\s*$/)) {
return; // continue
}
var match_res;
if ((match_res = p.match(/^(ne2k_pci|e1000|e1000-82540em|e1000-82544gc|e1000-82545em|vmxnet3|rtl8139|pcnet|virtio|ne2k_isa|i82551|i82557b|i82559er)(=([0-9a-f]{2}(:[0-9a-f]{2}){5}))?$/i)) !== null) {
res.model = match_res[1].toLowerCase();
if (match_res[3]) {
res.macaddr = match_res[3];
}
} else if ((match_res = p.match(/^bridge=(\S+)$/)) !== null) {
res.bridge = match_res[1];
} else if ((match_res = p.match(/^rate=(\d+(\.\d+)?)$/)) !== null) {
res.rate = match_res[1];
} else if ((match_res = p.match(/^tag=(\d+(\.\d+)?)$/)) !== null) {
res.tag = match_res[1];
} else if ((match_res = p.match(/^firewall=(\d+)$/)) !== null) {
res.firewall = match_res[1];
} else if ((match_res = p.match(/^link_down=(\d+)$/)) !== null) {
res.disconnect = match_res[1];
} else if ((match_res = p.match(/^queues=(\d+)$/)) !== null) {
res.queues = match_res[1];
} else if ((match_res = p.match(/^trunks=(\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*)$/)) !== null) {
res.trunks = match_res[1];
} else {
errors = true;
return false; // break
}
});
if (errors || !res.model) {
return;
}
return res;
},
printQemuNetwork: function(net) {
var netstr = net.model;
if (net.macaddr) {
netstr += "=" + net.macaddr;
}
if (net.bridge) {
netstr += ",bridge=" + net.bridge;
if (net.tag) {
netstr += ",tag=" + net.tag;
}
if (net.firewall) {
netstr += ",firewall=" + net.firewall;
}
}
if (net.rate) {
netstr += ",rate=" + net.rate;
}
if (net.queues) {
netstr += ",queues=" + net.queues;
}
if (net.disconnect) {
netstr += ",link_down=" + net.disconnect;
}
if (net.trunks) {
netstr += ",trunks=" + net.trunks;
}
return netstr;
},
parseQemuDrive: function(key, value) {
if (!(key && value)) {
return;
}
var res = {};
var match_res = key.match(/^([a-z]+)(\d+)$/);
if (!match_res) {
return;
}
res['interface'] = match_res[1];
res.index = match_res[2];
var errors = false;
Ext.Array.each(value.split(','), function(p) {
if (!p || p.match(/^\s*$/)) {
return; // continue
}
var match_res = p.match(/^([a-z_]+)=(\S+)$/);
if (!match_res) {
if (!p.match(/\=/)) {
res.file = p;
return; // continue
}
errors = true;
return false; // break
}
var k = match_res[1];
if (k === 'volume') {
k = 'file';
}
if (Ext.isDefined(res[k])) {
errors = true;
return false; // break
}
var v = match_res[2];
if (k === 'cache' && v === 'off') {
v = 'none';
}
res[k] = v;
});
if (errors || !res.file) {
return;
}
return res;
},
printQemuDrive: function(drive) {
var drivestr = drive.file;
Ext.Object.each(drive, function(key, value) {
if (!Ext.isDefined(value) || key === 'file' ||
key === 'index' || key === 'interface') {
return; // continue
}
drivestr += ',' + key + '=' + value;
});
return drivestr;
},
parseIPConfig: function(key, value) {
if (!(key && value)) {
return;
}
var res = {};
var errors = false;
Ext.Array.each(value.split(','), function(p) {
if (!p || p.match(/^\s*$/)) {
return; // continue
}
var match_res;
if ((match_res = p.match(/^ip=(\S+)$/)) !== null) {
res.ip = match_res[1];
} else if ((match_res = p.match(/^gw=(\S+)$/)) !== null) {
res.gw = match_res[1];
} else if ((match_res = p.match(/^ip6=(\S+)$/)) !== null) {
res.ip6 = match_res[1];
} else if ((match_res = p.match(/^gw6=(\S+)$/)) !== null) {
res.gw6 = match_res[1];
} else {
errors = true;
return false; // break
}
});
if (errors) {
return;
}
return res;
},
printIPConfig: function(cfg) {
var c = "";
var str = "";
if (cfg.ip) {
str += "ip=" + cfg.ip;
c = ",";
}
if (cfg.gw) {
str += c + "gw=" + cfg.gw;
c = ",";
}
if (cfg.ip6) {
str += c + "ip6=" + cfg.ip6;
c = ",";
}
if (cfg.gw6) {
str += c + "gw6=" + cfg.gw6;
c = ",";
}
return str;
},
parseOpenVZNetIf: function(value) {
if (!value) {
return;
}
var res = {};
var errors = false;
Ext.Array.each(value.split(';'), function(item) {
if (!item || item.match(/^\s*$/)) {
return; // continue
}
var data = {};
Ext.Array.each(item.split(','), function(p) {
if (!p || p.match(/^\s*$/)) {
return; // continue
}
var match_res = p.match(/^(ifname|mac|bridge|host_ifname|host_mac|mac_filter)=(\S+)$/);
if (!match_res) {
errors = true;
return false; // break
}
if (match_res[1] === 'bridge'){
var bridgevlanf = match_res[2];
var bridge_res = bridgevlanf.match(/^(vmbr(\d+))(v(\d+))?(f)?$/);
if (!bridge_res) {
errors = true;
return false; // break
}
data.bridge = bridge_res[1];
data.tag = bridge_res[4];
/*jslint confusion: true*/
data.firewall = bridge_res[5] ? 1 : 0;
/*jslint confusion: false*/
} else {
data[match_res[1]] = match_res[2];
}
});
if (errors || !data.ifname) {
errors = true;
return false; // break
}
data.raw = item;
res[data.ifname] = data;
});
return errors ? undefined: res;
},
printOpenVZNetIf: function(netif) {
var netarray = [];
Ext.Object.each(netif, function(iface, data) {
var tmparray = [];
Ext.Array.each(['ifname', 'mac', 'bridge', 'host_ifname' , 'host_mac', 'mac_filter', 'tag', 'firewall'], function(key) {
var value = data[key];
if (key === 'bridge'){
if(data.tag){
value = value + 'v' + data.tag;
}
if (data.firewall){
value = value + 'f';
}
}
if (value) {
tmparray.push(key + '=' + value);
}
});
netarray.push(tmparray.join(','));
});
return netarray.join(';');
},
parseLxcNetwork: function(value) {
if (!value) {
return;
}
var data = {};
Ext.Array.each(value.split(','), function(p) {
if (!p || p.match(/^\s*$/)) {
return; // continue
}
var match_res = p.match(/^(bridge|hwaddr|mtu|name|ip|ip6|gw|gw6|tag|rate)=(\S+)$/);
if (match_res) {
data[match_res[1]] = match_res[2];
} else if ((match_res = p.match(/^firewall=(\d+)$/)) !== null) {
data.firewall = PVE.Parser.parseBoolean(match_res[1]);
} else {
// todo: simply ignore errors ?
return; // continue
}
});
return data;
},
printLxcNetwork: function(data) {
var tmparray = [];
Ext.Array.each(['bridge', 'hwaddr', 'mtu', 'name', 'ip',
'gw', 'ip6', 'gw6', 'firewall', 'tag'], function(key) {
var value = data[key];
if (value) {
tmparray.push(key + '=' + value);
}
});
/*jslint confusion: true*/
if (data.rate > 0) {
tmparray.push('rate=' + data.rate);
}
/*jslint confusion: false*/
return tmparray.join(',');
},
parseLxcMountPoint: function(value) {
if (!value) {
return;
}
var res = {};
var errors = false;
Ext.Array.each(value.split(','), function(p) {
if (!p || p.match(/^\s*$/)) {
return; // continue
}
var match_res = p.match(/^([a-z_]+)=(.+)$/);
if (!match_res) {
if (!p.match(/\=/)) {
res.file = p;
return; // continue
}
errors = true;
return false; // break
}
var k = match_res[1];
if (k === 'volume') {
k = 'file';
}
if (Ext.isDefined(res[k])) {
errors = true;
return false; // break
}
var v = match_res[2];
res[k] = v;
});
if (errors || !res.file) {
return;
}
var m = res.file.match(/^([a-z][a-z0-9\-\_\.]*[a-z0-9]):/i);
if (m) {
res.storage = m[1];
res.type = 'volume';
} else if (res.file.match(/^\/dev\//)) {
res.type = 'device';
} else {
res.type = 'bind';
}
return res;
},
printLxcMountPoint: function(mp) {
var drivestr = mp.file;
Ext.Object.each(mp, function(key, value) {
if (!Ext.isDefined(value) || key === 'file' ||
key === 'type' || key === 'storage') {
return; // continue
}
drivestr += ',' + key + '=' + value;
});
return drivestr;
},
parseStartup: function(value) {
if (value === undefined) {
return;
}
var res = {};
var errors = false;
Ext.Array.each(value.split(','), function(p) {
if (!p || p.match(/^\s*$/)) {
return; // continue
}
var match_res;
if ((match_res = p.match(/^(order)?=(\d+)$/)) !== null) {
res.order = match_res[2];
} else if ((match_res = p.match(/^up=(\d+)$/)) !== null) {
res.up = match_res[1];
} else if ((match_res = p.match(/^down=(\d+)$/)) !== null) {
res.down = match_res[1];
} else {
errors = true;
return false; // break
}
});
if (errors) {
return;
}
return res;
},
printStartup: function(startup) {
var arr = [];
if (startup.order !== undefined && startup.order !== '') {
arr.push('order=' + startup.order);
}
if (startup.up !== undefined && startup.up !== '') {
arr.push('up=' + startup.up);
}
if (startup.down !== undefined && startup.down !== '') {
arr.push('down=' + startup.down);
}
return arr.join(',');
},
parseQemuSmbios1: function(value) {
var res = value.split(',').reduce(function (accumulator, currentValue) {
var splitted = currentValue.split(new RegExp("=(.+)"));
accumulator[splitted[0]] = splitted[1];
return accumulator;
}, {});
if (PVE.Parser.parseBoolean(res.base64, false)) {
Ext.Object.each(res, function(key, value) {
if (key === 'uuid') { return; }
res[key] = Ext.util.Base64.decode(value);
});
}
return res;
},
printQemuSmbios1: function(data) {
var datastr = '';
var base64 = false;
Ext.Object.each(data, function(key, value) {
if (value === '') { return; }
if (key === 'uuid') {
datastr += (datastr !== '' ? ',' : '') + key + '=' + value;
} else {
// values should be base64 encoded from now on, mark config strings correspondingly
if (!base64) {
base64 = true;
datastr += (datastr !== '' ? ',' : '') + 'base64=1';
}
datastr += (datastr !== '' ? ',' : '') + key + '=' + Ext.util.Base64.encode(value);
}
});
return datastr;
},
parseTfaConfig: function(value) {
var res = {};
Ext.Array.each(value.split(','), function(p) {
var kva = p.split('=', 2);
res[kva[0]] = kva[1];
});
return res;
},
parseTfaType: function(value) {
/*jslint confusion: true*/
var match;
if (!value || !value.length) {
return undefined;
} else if (value === 'x!oath') {
return 'totp';
} else if (!!(match = value.match(/^x!(.+)$/))) {
return match[1];
} else {
return 1;
}
},
parseQemuCpu: function(value) {
if (!value) {
return {};
}
var res = {};
var errors = false;
Ext.Array.each(value.split(','), function(p) {
if (!p || p.match(/^\s*$/)) {
return; // continue
}
if (!p.match(/\=/)) {
if (Ext.isDefined(res.cpu)) {
errors = true;
return false; // break
}
res.cputype = p;
return; // continue
}
var match_res = p.match(/^([a-z_]+)=(\S+)$/);
if (!match_res) {
errors = true;
return false; // break
}
var k = match_res[1];
if (Ext.isDefined(res[k])) {
errors = true;
return false; // break
}
res[k] = match_res[2];
});
if (errors || !res.cputype) {
return;
}
return res;
},
printQemuCpu: function(cpu) {
var cpustr = cpu.cputype;
var optstr = '';
Ext.Object.each(cpu, function(key, value) {
if (!Ext.isDefined(value) || key === 'cputype') {
return; // continue
}
optstr += ',' + key + '=' + value;
});
if (!cpustr) {
if (optstr) {
return 'kvm64' + optstr;
}
return;
}
return cpustr + optstr;
},
parseSSHKey: function(key) {
// |--- options can have quotes--| type key comment
var keyre = /^(?:((?:[^\s"]|\"(?:\\.|[^"\\])*")+)\s+)?(\S+)\s+(\S+)(?:\s+(.*))?$/;
var typere = /^(?:ssh-(?:dss|rsa|ed25519)|ecdsa-sha2-nistp\d+)$/;
var m = key.match(keyre);
if (!m) {
return null;
}
if (m.length < 3 || !m[2]) { // [2] is always either type or key
return null;
}
if (m[1] && m[1].match(typere)) {
return {
type: m[1],
key: m[2],
comment: m[3]
};
}
if (m[2].match(typere)) {
return {
options: m[1],
type: m[2],
key: m[3],
comment: m[4]
};
}
return null;
}
}});