]> git.proxmox.com Git - pve-manager.git/blame - www/manager6/Parser.js
backupview: add file restore button
[pve-manager.git] / www / manager6 / Parser.js
CommitLineData
fcb64fe4
DM
1// Some configuration values are complex strings -
2// so we need parsers/generators for them.
3
8058410f
TL
4Ext.define('PVE.Parser', {
5 statics: {
fcb64fe4
DM
6
7 // this class only contains static functions
8
899c4f45
DC
9 printACME: function(value) {
10 if (Ext.isArray(value.domains)) {
11 value.domains = value.domains.join(';');
12 }
13 return PVE.Parser.printPropertyString(value);
14 },
15
488be4c2
DC
16 parseACME: function(value) {
17 if (!value) {
6ac64c3a 18 return {};
488be4c2
DC
19 }
20
21 var res = {};
08a61c7b 22 var error;
488be4c2
DC
23
24 Ext.Array.each(value.split(','), function(p) {
08a61c7b
FG
25 var kv = p.split('=', 2);
26 if (Ext.isDefined(kv[1])) {
27 res[kv[0]] = kv[1];
488be4c2 28 } else {
08a61c7b 29 error = 'Failed to parse key-value pair: '+p;
488be4c2
DC
30 return false;
31 }
32 });
33
08a61c7b
FG
34 if (error !== undefined) {
35 console.error(error);
488be4c2
DC
36 return;
37 }
38
08a61c7b
FG
39 if (res.domains !== undefined) {
40 res.domains = res.domains.split(/;/);
41 }
42
488be4c2
DC
43 return res;
44 },
45
4c1c0d5d 46 parseBoolean: function(value, default_value) {
84de645d 47 if (!Ext.isDefined(value)) {
4c1c0d5d 48 return default_value;
84de645d 49 }
4c1c0d5d 50 value = value.toLowerCase();
ec0bd652 51 return value === '1' ||
4c1c0d5d
EK
52 value === 'on' ||
53 value === 'yes' ||
54 value === 'true';
55 },
56
3d6189d3
SI
57 parsePropertyString: function(value, defaultKey) {
58 var res = {},
9bbdcdff 59 error;
3d6189d3 60
4a7248d4
TL
61 if (typeof value !== 'string' || value === '') {
62 return res;
63 }
64
3d6189d3
SI
65 Ext.Array.each(value.split(','), function(p) {
66 var kv = p.split('=', 2);
67 if (Ext.isDefined(kv[1])) {
68 res[kv[0]] = kv[1];
69 } else if (Ext.isDefined(defaultKey)) {
70 if (Ext.isDefined(res[defaultKey])) {
9bbdcdff
TL
71 error = 'defaultKey may be only defined once in propertyString';
72 return false; // break
3d6189d3
SI
73 }
74 res[defaultKey] = kv[0];
75 } else {
9bbdcdff 76 error = 'invalid propertyString, not a key=value pair and no defaultKey defined';
3d6189d3
SI
77 return false; // break
78 }
79 });
80
9bbdcdff
TL
81 if (error !== undefined) {
82 console.error(error);
3d6189d3
SI
83 return;
84 }
85
86 return res;
87 },
88
89 printPropertyString: function(data, defaultKey) {
6de2baee
TL
90 var stringparts = [],
91 gotDefaultKeyVal = false,
92 defaultKeyVal;
3d6189d3
SI
93
94 Ext.Object.each(data, function(key, value) {
8007aaaf 95 if (defaultKey !== undefined && key === defaultKey) {
6de2baee
TL
96 gotDefaultKeyVal = true;
97 defaultKeyVal = value;
08e38f03 98 } else if (value !== '') {
8007aaaf 99 stringparts.push(key + '=' + value);
3d6189d3 100 }
3d6189d3
SI
101 });
102
6de2baee
TL
103 stringparts = stringparts.sort();
104 if (gotDefaultKeyVal) {
105 stringparts.unshift(defaultKeyVal);
106 }
107
3d6189d3
SI
108 return stringparts.join(',');
109 },
110
fcb64fe4
DM
111 parseQemuNetwork: function(key, value) {
112 if (!(key && value)) {
113 return;
114 }
115
116 var res = {};
117
118 var errors = false;
119 Ext.Array.each(value.split(','), function(p) {
120 if (!p || p.match(/^\s*$/)) {
121 return; // continue
122 }
123
124 var match_res;
125
126 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) {
127 res.model = match_res[1].toLowerCase();
128 if (match_res[3]) {
129 res.macaddr = match_res[3];
130 }
131 } else if ((match_res = p.match(/^bridge=(\S+)$/)) !== null) {
132 res.bridge = match_res[1];
133 } else if ((match_res = p.match(/^rate=(\d+(\.\d+)?)$/)) !== null) {
134 res.rate = match_res[1];
135 } else if ((match_res = p.match(/^tag=(\d+(\.\d+)?)$/)) !== null) {
63e62a6f 136 res.tag = match_res[1];
fcb64fe4 137 } else if ((match_res = p.match(/^firewall=(\d+)$/)) !== null) {
63e62a6f 138 res.firewall = match_res[1];
fcb64fe4 139 } else if ((match_res = p.match(/^link_down=(\d+)$/)) !== null) {
63e62a6f 140 res.disconnect = match_res[1];
fcb64fe4 141 } else if ((match_res = p.match(/^queues=(\d+)$/)) !== null) {
63e62a6f 142 res.queues = match_res[1];
a2ed0697
WB
143 } else if ((match_res = p.match(/^trunks=(\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*)$/)) !== null) {
144 res.trunks = match_res[1];
ced67201
DC
145 } else if ((match_res = p.match(/^mtu=(\d+)$/)) !== null) {
146 res.mtu = match_res[1];
fcb64fe4
DM
147 } else {
148 errors = true;
149 return false; // break
150 }
151 });
152
153 if (errors || !res.model) {
154 return;
155 }
156
157 return res;
158 },
159
160 printQemuNetwork: function(net) {
fcb64fe4
DM
161 var netstr = net.model;
162 if (net.macaddr) {
163 netstr += "=" + net.macaddr;
164 }
165 if (net.bridge) {
166 netstr += ",bridge=" + net.bridge;
167 if (net.tag) {
168 netstr += ",tag=" + net.tag;
169 }
170 if (net.firewall) {
171 netstr += ",firewall=" + net.firewall;
172 }
173 }
174 if (net.rate) {
175 netstr += ",rate=" + net.rate;
176 }
177 if (net.queues) {
178 netstr += ",queues=" + net.queues;
179 }
180 if (net.disconnect) {
181 netstr += ",link_down=" + net.disconnect;
182 }
a2ed0697
WB
183 if (net.trunks) {
184 netstr += ",trunks=" + net.trunks;
185 }
ced67201
DC
186 if (net.mtu) {
187 netstr += ",mtu=" + net.mtu;
188 }
fcb64fe4
DM
189 return netstr;
190 },
191
192 parseQemuDrive: function(key, value) {
193 if (!(key && value)) {
194 return;
195 }
196
197 var res = {};
198
199 var match_res = key.match(/^([a-z]+)(\d+)$/);
200 if (!match_res) {
201 return;
202 }
399ffa76 203 res.interface = match_res[1];
fcb64fe4
DM
204 res.index = match_res[2];
205
206 var errors = false;
207 Ext.Array.each(value.split(','), function(p) {
208 if (!p || p.match(/^\s*$/)) {
209 return; // continue
210 }
211 var match_res = p.match(/^([a-z_]+)=(\S+)$/);
212 if (!match_res) {
213 if (!p.match(/\=/)) {
214 res.file = p;
215 return; // continue
216 }
217 errors = true;
218 return false; // break
219 }
220 var k = match_res[1];
221 if (k === 'volume') {
222 k = 'file';
223 }
224
225 if (Ext.isDefined(res[k])) {
226 errors = true;
227 return false; // break
228 }
229
230 var v = match_res[2];
231
232 if (k === 'cache' && v === 'off') {
233 v = 'none';
234 }
235
236 res[k] = v;
237 });
238
239 if (errors || !res.file) {
240 return;
241 }
242
243 return res;
244 },
245
246 printQemuDrive: function(drive) {
fcb64fe4
DM
247 var drivestr = drive.file;
248
249 Ext.Object.each(drive, function(key, value) {
250 if (!Ext.isDefined(value) || key === 'file' ||
251 key === 'index' || key === 'interface') {
252 return; // continue
253 }
254 drivestr += ',' + key + '=' + value;
255 });
256
257 return drivestr;
258 },
259
01e02121
DC
260 parseIPConfig: function(key, value) {
261 if (!(key && value)) {
262 return;
263 }
264
265 var res = {};
266
267 var errors = false;
268 Ext.Array.each(value.split(','), function(p) {
269 if (!p || p.match(/^\s*$/)) {
270 return; // continue
271 }
272
273 var match_res;
274 if ((match_res = p.match(/^ip=(\S+)$/)) !== null) {
275 res.ip = match_res[1];
276 } else if ((match_res = p.match(/^gw=(\S+)$/)) !== null) {
277 res.gw = match_res[1];
278 } else if ((match_res = p.match(/^ip6=(\S+)$/)) !== null) {
279 res.ip6 = match_res[1];
280 } else if ((match_res = p.match(/^gw6=(\S+)$/)) !== null) {
281 res.gw6 = match_res[1];
282 } else {
283 errors = true;
284 return false; // break
285 }
286 });
287
288 if (errors) {
289 return;
290 }
291
292 return res;
293 },
294
295 printIPConfig: function(cfg) {
296 var c = "";
297 var str = "";
298 if (cfg.ip) {
299 str += "ip=" + cfg.ip;
300 c = ",";
301 }
302 if (cfg.gw) {
303 str += c + "gw=" + cfg.gw;
304 c = ",";
305 }
306 if (cfg.ip6) {
307 str += c + "ip6=" + cfg.ip6;
308 c = ",";
309 }
310 if (cfg.gw6) {
311 str += c + "gw6=" + cfg.gw6;
312 c = ",";
313 }
314 return str;
315 },
316
fcb64fe4
DM
317 parseOpenVZNetIf: function(value) {
318 if (!value) {
319 return;
320 }
321
322 var res = {};
323
324 var errors = false;
325 Ext.Array.each(value.split(';'), function(item) {
326 if (!item || item.match(/^\s*$/)) {
327 return; // continue
328 }
329
330 var data = {};
331 Ext.Array.each(item.split(','), function(p) {
332 if (!p || p.match(/^\s*$/)) {
333 return; // continue
334 }
335 var match_res = p.match(/^(ifname|mac|bridge|host_ifname|host_mac|mac_filter)=(\S+)$/);
336 if (!match_res) {
337 errors = true;
338 return false; // break
339 }
8058410f 340 if (match_res[1] === 'bridge') {
fcb64fe4
DM
341 var bridgevlanf = match_res[2];
342 var bridge_res = bridgevlanf.match(/^(vmbr(\d+))(v(\d+))?(f)?$/);
343 if (!bridge_res) {
344 errors = true;
345 return false; // break
346 }
ec0bd652
DC
347 data.bridge = bridge_res[1];
348 data.tag = bridge_res[4];
ec0bd652 349 data.firewall = bridge_res[5] ? 1 : 0;
fcb64fe4
DM
350 } else {
351 data[match_res[1]] = match_res[2];
352 }
353 });
354
355 if (errors || !data.ifname) {
356 errors = true;
357 return false; // break
358 }
359
360 data.raw = item;
361
362 res[data.ifname] = data;
363 });
364
365 return errors ? undefined: res;
366 },
367
368 printOpenVZNetIf: function(netif) {
369 var netarray = [];
370
371 Ext.Object.each(netif, function(iface, data) {
372 var tmparray = [];
f6710aac 373 Ext.Array.each(['ifname', 'mac', 'bridge', 'host_ifname', 'host_mac', 'mac_filter', 'tag', 'firewall'], function(key) {
fcb64fe4 374 var value = data[key];
8058410f
TL
375 if (key === 'bridge') {
376 if (data.tag) {
ec0bd652 377 value = value + 'v' + data.tag;
fcb64fe4 378 }
8058410f 379 if (data.firewall) {
fcb64fe4
DM
380 value = value + 'f';
381 }
382 }
383 if (value) {
384 tmparray.push(key + '=' + value);
385 }
fcb64fe4
DM
386 });
387 netarray.push(tmparray.join(','));
388 });
389
390 return netarray.join(';');
391 },
392
393 parseLxcNetwork: function(value) {
394 if (!value) {
395 return;
396 }
397
398 var data = {};
399 Ext.Array.each(value.split(','), function(p) {
400 if (!p || p.match(/^\s*$/)) {
401 return; // continue
402 }
95e77b22
TL
403 var match_res = p.match(/^(bridge|hwaddr|mtu|name|ip|ip6|gw|gw6|tag|rate)=(\S+)$/);
404 if (match_res) {
405 data[match_res[1]] = match_res[2];
406 } else if ((match_res = p.match(/^firewall=(\d+)$/)) !== null) {
805a7cb8 407 data.firewall = PVE.Parser.parseBoolean(match_res[1]);
95e77b22 408 } else {
fcb64fe4
DM
409 // todo: simply ignore errors ?
410 return; // continue
411 }
fcb64fe4
DM
412 });
413
414 return data;
415 },
416
417 printLxcNetwork: function(data) {
418 var tmparray = [];
419 Ext.Array.each(['bridge', 'hwaddr', 'mtu', 'name', 'ip',
420 'gw', 'ip6', 'gw6', 'firewall', 'tag'], function(key) {
421 var value = data[key];
422 if (value) {
423 tmparray.push(key + '=' + value);
424 }
425 });
519ca7fa 426
6efbc4cb 427 if (data.rate > 0) {
519ca7fa
DM
428 tmparray.push('rate=' + data.rate);
429 }
fcb64fe4
DM
430 return tmparray.join(',');
431 },
432
4c1c0d5d
EK
433 parseLxcMountPoint: function(value) {
434 if (!value) {
435 return;
436 }
437
438 var res = {};
439
440 var errors = false;
441 Ext.Array.each(value.split(','), function(p) {
442 if (!p || p.match(/^\s*$/)) {
443 return; // continue
444 }
a108c35a 445 var match_res = p.match(/^([a-z_]+)=(.+)$/);
4c1c0d5d
EK
446 if (!match_res) {
447 if (!p.match(/\=/)) {
448 res.file = p;
449 return; // continue
450 }
451 errors = true;
452 return false; // break
453 }
454 var k = match_res[1];
455 if (k === 'volume') {
456 k = 'file';
457 }
458
459 if (Ext.isDefined(res[k])) {
460 errors = true;
461 return false; // break
462 }
463
464 var v = match_res[2];
465
466 res[k] = v;
467 });
468
469 if (errors || !res.file) {
470 return;
471 }
472
283b450e 473 var m = res.file.match(/^([a-z][a-z0-9\-\_\.]*[a-z0-9]):/i);
4c1c0d5d
EK
474 if (m) {
475 res.storage = m[1];
476 res.type = 'volume';
477 } else if (res.file.match(/^\/dev\//)) {
478 res.type = 'device';
479 } else {
480 res.type = 'bind';
481 }
482
483 return res;
484 },
485
486 printLxcMountPoint: function(mp) {
487 var drivestr = mp.file;
488
489 Ext.Object.each(mp, function(key, value) {
490 if (!Ext.isDefined(value) || key === 'file' ||
491 key === 'type' || key === 'storage') {
492 return; // continue
493 }
494 drivestr += ',' + key + '=' + value;
495 });
496
497 return drivestr;
498 },
499
fcb64fe4
DM
500 parseStartup: function(value) {
501 if (value === undefined) {
502 return;
503 }
504
505 var res = {};
506
507 var errors = false;
508 Ext.Array.each(value.split(','), function(p) {
509 if (!p || p.match(/^\s*$/)) {
510 return; // continue
511 }
512
513 var match_res;
514
515 if ((match_res = p.match(/^(order)?=(\d+)$/)) !== null) {
516 res.order = match_res[2];
517 } else if ((match_res = p.match(/^up=(\d+)$/)) !== null) {
518 res.up = match_res[1];
519 } else if ((match_res = p.match(/^down=(\d+)$/)) !== null) {
520 res.down = match_res[1];
521 } else {
522 errors = true;
523 return false; // break
524 }
525 });
526
527 if (errors) {
528 return;
529 }
530
531 return res;
532 },
533
534 printStartup: function(startup) {
535 var arr = [];
536 if (startup.order !== undefined && startup.order !== '') {
537 arr.push('order=' + startup.order);
538 }
539 if (startup.up !== undefined && startup.up !== '') {
540 arr.push('up=' + startup.up);
541 }
542 if (startup.down !== undefined && startup.down !== '') {
543 arr.push('down=' + startup.down);
544 }
545
546 return arr.join(',');
547 },
548
549 parseQemuSmbios1: function(value) {
8058410f 550 var res = value.split(',').reduce(function(accumulator, currentValue) {
150ad74a
CE
551 var splitted = currentValue.split(new RegExp("=(.+)"));
552 accumulator[splitted[0]] = splitted[1];
553 return accumulator;
554 }, {});
555
556 if (PVE.Parser.parseBoolean(res.base64, false)) {
557 Ext.Object.each(res, function(key, value) {
558 if (key === 'uuid') { return; }
559 res[key] = Ext.util.Base64.decode(value);
560 });
561 }
fcb64fe4
DM
562
563 return res;
564 },
565
566 printQemuSmbios1: function(data) {
fcb64fe4 567 var datastr = '';
150ad74a 568 var base64 = false;
fcb64fe4 569 Ext.Object.each(data, function(key, value) {
84de645d 570 if (value === '') { return; }
150ad74a
CE
571 if (key === 'uuid') {
572 datastr += (datastr !== '' ? ',' : '') + key + '=' + value;
573 } else {
574 // values should be base64 encoded from now on, mark config strings correspondingly
575 if (!base64) {
576 base64 = true;
577 datastr += (datastr !== '' ? ',' : '') + 'base64=1';
578 }
579 datastr += (datastr !== '' ? ',' : '') + key + '=' + Ext.util.Base64.encode(value);
580 }
fcb64fe4
DM
581 });
582
583 return datastr;
584 },
585
586 parseTfaConfig: function(value) {
587 var res = {};
588
589 Ext.Array.each(value.split(','), function(p) {
ec0bd652 590 var kva = p.split('=', 2);
fcb64fe4
DM
591 res[kva[0]] = kva[1];
592 });
593
594 return res;
4c1c0d5d
EK
595 },
596
1cdb49c1
WB
597 parseTfaType: function(value) {
598 var match;
599 if (!value || !value.length) {
600 return undefined;
601 } else if (value === 'x!oath') {
602 return 'totp';
d2021707 603 } else if (match = value.match(/^x!(.+)$/)) {
1cdb49c1
WB
604 return match[1];
605 } else {
606 return 1;
607 }
608 },
609
4c1c0d5d
EK
610 parseQemuCpu: function(value) {
611 if (!value) {
612 return {};
613 }
614
615 var res = {};
616
617 var errors = false;
618 Ext.Array.each(value.split(','), function(p) {
619 if (!p || p.match(/^\s*$/)) {
620 return; // continue
621 }
fcb64fe4 622
ec0bd652
DC
623 if (!p.match(/\=/)) {
624 if (Ext.isDefined(res.cpu)) {
4c1c0d5d
EK
625 errors = true;
626 return false; // break
627 }
628 res.cputype = p;
629 return; // continue
630 }
631
632 var match_res = p.match(/^([a-z_]+)=(\S+)$/);
633 if (!match_res) {
634 errors = true;
635 return false; // break
636 }
637
638 var k = match_res[1];
639 if (Ext.isDefined(res[k])) {
640 errors = true;
641 return false; // break
642 }
643
644 res[k] = match_res[2];
645 });
646
647 if (errors || !res.cputype) {
648 return;
649 }
650
651 return res;
652 },
653
654 printQemuCpu: function(cpu) {
655 var cpustr = cpu.cputype;
656 var optstr = '';
657
658 Ext.Object.each(cpu, function(key, value) {
659 if (!Ext.isDefined(value) || key === 'cputype') {
660 return; // continue
661 }
662 optstr += ',' + key + '=' + value;
663 });
664
665 if (!cpustr) {
84de645d 666 if (optstr) {
4c1c0d5d 667 return 'kvm64' + optstr;
84de645d 668 }
4c1c0d5d
EK
669 return;
670 }
671
672 return cpustr + optstr;
b1339314
WB
673 },
674
675 parseSSHKey: function(key) {
676 // |--- options can have quotes--| type key comment
677 var keyre = /^(?:((?:[^\s"]|\"(?:\\.|[^"\\])*")+)\s+)?(\S+)\s+(\S+)(?:\s+(.*))?$/;
678 var typere = /^(?:ssh-(?:dss|rsa|ed25519)|ecdsa-sha2-nistp\d+)$/;
679
680 var m = key.match(keyre);
681 if (!m) {
682 return null;
683 }
684 if (m.length < 3 || !m[2]) { // [2] is always either type or key
685 return null;
686 }
687 if (m[1] && m[1].match(typere)) {
688 return {
689 type: m[1],
690 key: m[2],
f6710aac 691 comment: m[3],
b1339314
WB
692 };
693 }
694 if (m[2].match(typere)) {
695 return {
696 options: m[1],
697 type: m[2],
698 key: m[3],
f6710aac 699 comment: m[4],
b1339314
WB
700 };
701 }
702 return null;
45708891
DC
703 },
704
705 parseACMEPluginData: function(data) {
706 let res = {};
707 let extradata = [];
708 data.split('\n').forEach((line) => {
709 // capture everything after the first = as value
710 let [key, value] = line.split(/=(.+)/);
711 if (value !== undefined) {
712 res[key] = value;
713 } else {
714 extradata.push(line);
715 }
716 });
717 return [res, extradata];
718 },
fa8d3971 719},
8058410f 720});