]> git.proxmox.com Git - pve-manager.git/blame - www/manager6/qemu/HDEdit.js
update shipped appliance info index
[pve-manager.git] / www / manager6 / qemu / HDEdit.js
CommitLineData
d5e771ce 1/* 'change' property is assigned a string and then a function */
df15b3da 2Ext.define('PVE.qemu.HDInputPanel', {
ef4ef788 3 extend: 'Proxmox.panel.InputPanel',
85806e47 4 alias: 'widget.pveQemuHDInputPanel',
c8802a60 5 onlineHelp: 'qm_hard_disk',
df15b3da
DM
6
7 insideWizard: false,
8
9 unused: false, // ADD usused disk imaged
10
11 vmconfig: {}, // used to select usused disks
12
3f543d7f
TL
13 viewModel: {
14 data: {
0fe712de 15 isSCSI: false,
3f543d7f 16 isVirtIO: false,
94b5e53a 17 isSCSISingle: false,
3f543d7f
TL
18 },
19 },
8e1df0ac 20
180d7ef5 21 controller: {
180d7ef5
DM
22 xclass: 'Ext.app.ViewController',
23
24 onControllerChange: function(field) {
ef82a0b1 25 let me = this;
3f543d7f 26 let vm = this.getViewModel();
f9261fde 27
3f543d7f
TL
28 let value = field.getValue();
29 vm.set('isSCSI', value.match(/^scsi/));
30 vm.set('isVirtIO', value.match(/^virtio/));
9d0fc155
DC
31
32 me.fireIdChange();
33 },
34
35 fireIdChange: function() {
36 let view = this.getView();
37 view.fireEvent('diskidchange', view, view.bussel.getConfId());
180d7ef5
DM
38 },
39
40 control: {
9cac6b75 41 'field[name=controller]': {
180d7ef5 42 change: 'onControllerChange',
f6710aac 43 afterrender: 'onControllerChange',
9cac6b75 44 },
9d0fc155
DC
45 'field[name=deviceid]': {
46 change: 'fireIdChange',
47 },
94b5e53a 48 'field[name=scsiController]': {
2414ef15 49 change: function(f, value) {
94b5e53a
MH
50 let vm = this.getViewModel();
51 vm.set('isSCSISingle', value === 'virtio-scsi-single');
f6710aac
TL
52 },
53 },
8e1df0ac
AL
54 },
55
56 init: function(view) {
57 var vm = this.getViewModel();
58 if (view.isCreate) {
59 vm.set('isIncludedInBackup', true);
60 }
3f543d7f
TL
61 if (view.confid) {
62 vm.set('isSCSI', view.confid.match(/^scsi/));
63 vm.set('isVirtIO', view.confid.match(/^virtio/));
64 }
f6710aac 65 },
180d7ef5
DM
66 },
67
df15b3da
DM
68 onGetValues: function(values) {
69 var me = this;
70
9a8a5735 71 var params = {};
53e3ea84 72 var confid = me.confid || values.controller + values.deviceid;
7a6e0635 73
df15b3da
DM
74 if (me.unused) {
75 me.drive.file = me.vmconfig[values.unusedId];
76 confid = values.controller + values.deviceid;
d5e771ce 77 } else if (me.isCreate) {
df15b3da
DM
78 if (values.hdimage) {
79 me.drive.file = values.hdimage;
80 } else {
81 me.drive.file = values.hdstorage + ":" + values.disksize;
82 }
83 me.drive.format = values.diskformat;
84 }
7a6e0635 85
87178934 86 PVE.Utils.propertyStringSet(me.drive, !values.backup, 'backup', '0');
e4e36020
DC
87 PVE.Utils.propertyStringSet(me.drive, values.noreplicate, 'replicate', 'no');
88 PVE.Utils.propertyStringSet(me.drive, values.discard, 'discard', 'on');
89 PVE.Utils.propertyStringSet(me.drive, values.ssd, 'ssd', 'on');
90 PVE.Utils.propertyStringSet(me.drive, values.iothread, 'iothread', 'on');
e4d84378 91 PVE.Utils.propertyStringSet(me.drive, values.readOnly, 'ro', 'on');
e4e36020 92 PVE.Utils.propertyStringSet(me.drive, values.cache, 'cache');
f68d8b2c 93 PVE.Utils.propertyStringSet(me.drive, values.aio, 'aio');
df15b3da 94
731c3253
TL
95 ['mbps_rd', 'mbps_wr', 'iops_rd', 'iops_wr'].forEach(name => {
96 let burst_name = `${name}_max`;
e4e36020
DC
97 PVE.Utils.propertyStringSet(me.drive, values[name], name);
98 PVE.Utils.propertyStringSet(me.drive, values[burst_name], burst_name);
731c3253 99 });
c2233c8f 100
df15b3da 101 params[confid] = PVE.Parser.printQemuDrive(me.drive);
7a6e0635
TL
102
103 return params;
df15b3da
DM
104 },
105
9dbc4dfa
DC
106 updateVMConfig: function(vmconfig) {
107 var me = this;
108 me.vmconfig = vmconfig;
109 me.bussel?.updateVMConfig(vmconfig);
110 },
111
df15b3da
DM
112 setVMConfig: function(vmconfig) {
113 var me = this;
114
115 me.vmconfig = vmconfig;
116
117 if (me.bussel) {
7206af4b 118 me.bussel.setVMConfig(vmconfig);
42bd6556 119 me.scsiController.setValue(vmconfig.scsihw);
df15b3da
DM
120 }
121 if (me.unusedDisks) {
7a6e0635 122 var disklist = [];
df15b3da
DM
123 Ext.Object.each(vmconfig, function(key, value) {
124 if (key.match(/^unused\d+$/)) {
125 disklist.push([key, value]);
126 }
127 });
128 me.unusedDisks.store.loadData(disklist);
129 me.unusedDisks.setValue(me.confid);
130 }
131 },
132
133 setDrive: function(drive) {
134 var me = this;
135
136 me.drive = drive;
137
138 var values = {};
139 var match = drive.file.match(/^([^:]+):/);
140 if (match) {
141 values.hdstorage = match[1];
142 }
143
144 values.hdimage = drive.file;
87178934 145 values.backup = PVE.Parser.parseBoolean(drive.backup, 1);
1b6f87ab 146 values.noreplicate = !PVE.Parser.parseBoolean(drive.replicate, 1);
df15b3da 147 values.diskformat = drive.format || 'raw';
ac7db8f7 148 values.cache = drive.cache || '__default__';
53e3ea84 149 values.discard = drive.discard === 'on';
f9261fde 150 values.ssd = PVE.Parser.parseBoolean(drive.ssd);
df15b3da 151 values.iothread = PVE.Parser.parseBoolean(drive.iothread);
e4d84378 152 values.readOnly = PVE.Parser.parseBoolean(drive.ro);
f68d8b2c 153 values.aio = drive.aio || '__default__';
df15b3da 154
c2233c8f
DC
155 values.mbps_rd = drive.mbps_rd;
156 values.mbps_wr = drive.mbps_wr;
157 values.iops_rd = drive.iops_rd;
158 values.iops_wr = drive.iops_wr;
159 values.mbps_rd_max = drive.mbps_rd_max;
160 values.mbps_wr_max = drive.mbps_wr_max;
161 values.iops_rd_max = drive.iops_rd_max;
162 values.iops_wr_max = drive.iops_wr_max;
163
df15b3da
DM
164 me.setValues(values);
165 },
166
167 setNodename: function(nodename) {
168 var me = this;
771aec96
DC
169 me.down('#hdstorage').setNodename(nodename);
170 me.down('#hdimage').setStorage(undefined, nodename);
df15b3da
DM
171 },
172
74c0b9a9
DC
173 hasAdvanced: true,
174
8058410f 175 initComponent: function() {
df15b3da
DM
176 var me = this;
177
178 me.drive = {};
179
74c0b9a9
DC
180 let column1 = [];
181 let column2 = [];
df15b3da 182
74c0b9a9
DC
183 let advancedColumn1 = [];
184 let advancedColumn2 = [];
546d09c2 185
df15b3da 186 if (!me.confid || me.unused) {
42902182 187 me.bussel = Ext.create('PVE.form.ControllerSelector', {
9dbc4dfa
DC
188 vmconfig: me.vmconfig,
189 selectFree: true,
df15b3da 190 });
74c0b9a9 191 column1.push(me.bussel);
2414ef15 192
42bd6556
EK
193 me.scsiController = Ext.create('Ext.form.field.Display', {
194 fieldLabel: gettext('SCSI Controller'),
195 reference: 'scsiController',
94b5e53a 196 name: 'scsiController',
471d03aa 197 bind: me.insideWizard ? {
f6710aac 198 value: '{current.scsihw}',
3f543d7f
TL
199 visible: '{isSCSI}',
200 } : {
201 visible: '{isSCSI}',
202 },
42bd6556 203 renderer: PVE.Utils.render_scsihw,
471d03aa 204 submitValue: false,
f6710aac 205 hidden: true,
42bd6556 206 });
74c0b9a9 207 column1.push(me.scsiController);
df15b3da
DM
208 }
209
210 if (me.unused) {
09cacce7 211 me.unusedDisks = Ext.create('Proxmox.form.KVComboBox', {
7a6e0635 212 name: 'unusedId',
df15b3da
DM
213 fieldLabel: gettext('Disk image'),
214 matchFieldWidth: false,
215 listConfig: {
f6710aac 216 width: 350,
df15b3da
DM
217 },
218 data: [],
f6710aac 219 allowBlank: false,
df15b3da 220 });
74c0b9a9 221 column1.push(me.unusedDisks);
d5e771ce 222 } else if (me.isCreate) {
74c0b9a9 223 column1.push({
771aec96 224 xtype: 'pveDiskStorageSelector',
df15b3da 225 storageContent: 'images',
771aec96 226 name: 'disk',
df15b3da 227 nodename: me.nodename,
f6710aac 228 autoSelect: me.insideWizard,
df15b3da 229 });
df15b3da 230 } else {
74c0b9a9 231 column1.push({
df15b3da
DM
232 xtype: 'textfield',
233 disabled: true,
234 submitValue: false,
235 fieldLabel: gettext('Disk image'),
f6710aac 236 name: 'hdimage',
df15b3da
DM
237 });
238 }
239
74c0b9a9 240 column2.push(
f9261fde
NC
241 {
242 xtype: 'CacheTypeSelector',
243 name: 'cache',
244 value: '__default__',
f6710aac 245 fieldLabel: gettext('Cache'),
f9261fde 246 },
546d09c2
DC
247 {
248 xtype: 'proxmoxcheckbox',
249 fieldLabel: gettext('Discard'),
546d09c2 250 reference: 'discard',
f6710aac
TL
251 name: 'discard',
252 },
f9261fde
NC
253 {
254 xtype: 'proxmoxcheckbox',
94b5e53a
MH
255 name: 'iothread',
256 fieldLabel: 'IO thread',
3f543d7f 257 clearOnDisable: true,
00e4bd2e 258 bind: me.insideWizard || me.isCreate ? {
94b5e53a
MH
259 disabled: '{!isVirtIO && !isSCSI}',
260 // Checkbox.setValue handles Arrays in a different way, therefore cast to bool
261 value: '{!!isVirtIO || (isSCSI && isSCSISingle)}',
00e4bd2e
DC
262 } : {
263 disabled: '{!isVirtIO && !isSCSI}',
3f543d7f 264 },
546d09c2 265 },
94b5e53a
MH
266 );
267
268 advancedColumn1.push(
546d09c2
DC
269 {
270 xtype: 'proxmoxcheckbox',
94b5e53a
MH
271 fieldLabel: gettext('SSD emulation'),
272 name: 'ssd',
3f543d7f
TL
273 clearOnDisable: true,
274 bind: {
94b5e53a 275 disabled: '{isVirtIO}',
3f543d7f 276 },
c2233c8f 277 },
e4d84378
TL
278 {
279 xtype: 'proxmoxcheckbox',
280 name: 'readOnly', // `ro` in the config, we map in get/set values
281 defaultValue: 0,
282 fieldLabel: gettext('Read-only'),
e4d84378
TL
283 clearOnDisable: true,
284 bind: {
285 disabled: '{!isVirtIO && !isSCSI}',
286 },
287 },
74c0b9a9
DC
288 );
289
290 advancedColumn2.push(
291 {
292 xtype: 'proxmoxcheckbox',
293 fieldLabel: gettext('Backup'),
294 autoEl: {
295 tag: 'div',
296 'data-qtip': gettext('Include volume in backup job'),
297 },
74c0b9a9
DC
298 name: 'backup',
299 bind: {
300 value: '{isIncludedInBackup}',
301 },
302 },
303 {
304 xtype: 'proxmoxcheckbox',
305 fieldLabel: gettext('Skip replication'),
74c0b9a9
DC
306 name: 'noreplicate',
307 },
f68d8b2c
DC
308 {
309 xtype: 'proxmoxKVComboBox',
310 name: 'aio',
311 fieldLabel: gettext('Async IO'),
312 allowBlank: false,
313 value: '__default__',
f68d8b2c
DC
314 comboItems: [
315 ['__default__', Proxmox.Utils.defaultText + ' (io_uring)'],
316 ['io_uring', 'io_uring'],
317 ['native', 'native'],
318 ['threads', 'threads'],
319 ],
320 },
74c0b9a9
DC
321 );
322
b48c6665
TL
323 let labelWidth = 140;
324
74c0b9a9 325 let bwColumn1 = [
c2233c8f
DC
326 {
327 xtype: 'numberfield',
328 name: 'mbps_rd',
329 minValue: 1,
330 step: 1,
331 fieldLabel: gettext('Read limit') + ' (MB/s)',
332 labelWidth: labelWidth,
f6710aac 333 emptyText: gettext('unlimited'),
c2233c8f
DC
334 },
335 {
336 xtype: 'numberfield',
337 name: 'mbps_wr',
338 minValue: 1,
339 step: 1,
340 fieldLabel: gettext('Write limit') + ' (MB/s)',
341 labelWidth: labelWidth,
f6710aac 342 emptyText: gettext('unlimited'),
c2233c8f
DC
343 },
344 {
345 xtype: 'proxmoxintegerfield',
346 name: 'iops_rd',
347 minValue: 10,
348 step: 10,
349 fieldLabel: gettext('Read limit') + ' (ops/s)',
350 labelWidth: labelWidth,
f6710aac 351 emptyText: gettext('unlimited'),
c2233c8f
DC
352 },
353 {
354 xtype: 'proxmoxintegerfield',
355 name: 'iops_wr',
356 minValue: 10,
357 step: 10,
358 fieldLabel: gettext('Write limit') + ' (ops/s)',
359 labelWidth: labelWidth,
f6710aac
TL
360 emptyText: gettext('unlimited'),
361 },
74c0b9a9 362 ];
546d09c2 363
74c0b9a9 364 let bwColumn2 = [
c2233c8f
DC
365 {
366 xtype: 'numberfield',
367 name: 'mbps_rd_max',
368 minValue: 1,
369 step: 1,
370 fieldLabel: gettext('Read max burst') + ' (MB)',
371 labelWidth: labelWidth,
f6710aac 372 emptyText: gettext('default'),
c2233c8f
DC
373 },
374 {
375 xtype: 'numberfield',
376 name: 'mbps_wr_max',
377 minValue: 1,
378 step: 1,
379 fieldLabel: gettext('Write max burst') + ' (MB)',
380 labelWidth: labelWidth,
f6710aac 381 emptyText: gettext('default'),
c2233c8f
DC
382 },
383 {
384 xtype: 'proxmoxintegerfield',
385 name: 'iops_rd_max',
386 minValue: 10,
387 step: 10,
388 fieldLabel: gettext('Read max burst') + ' (ops)',
389 labelWidth: labelWidth,
f6710aac 390 emptyText: gettext('default'),
c2233c8f
DC
391 },
392 {
393 xtype: 'proxmoxintegerfield',
394 name: 'iops_wr_max',
395 minValue: 10,
396 step: 10,
397 fieldLabel: gettext('Write max burst') + ' (ops)',
398 labelWidth: labelWidth,
f6710aac
TL
399 emptyText: gettext('default'),
400 },
74c0b9a9
DC
401 ];
402
403 me.items = [
404 {
405 xtype: 'tabpanel',
406 plain: true,
407 bodyPadding: 10,
408 border: 0,
409 items: [
410 {
411 title: gettext('Disk'),
412 xtype: 'inputpanel',
413 reference: 'diskpanel',
414 column1,
415 column2,
416 advancedColumn1,
417 advancedColumn2,
418 showAdvanced: me.showAdvanced,
419 getValues: () => ({}),
420 },
421 {
422 title: gettext('Bandwidth'),
423 xtype: 'inputpanel',
424 reference: 'bwpanel',
425 column1: bwColumn1,
426 column2: bwColumn2,
427 showAdvanced: me.showAdvanced,
428 getValues: () => ({}),
429 },
430 ],
431 },
432 ];
546d09c2 433
df15b3da 434 me.callParent();
f6710aac 435 },
74c0b9a9
DC
436
437 setAdvancedVisible: function(visible) {
438 this.lookup('diskpanel').setAdvancedVisible(visible);
439 this.lookup('bwpanel').setAdvancedVisible(visible);
440 },
df15b3da
DM
441});
442
443Ext.define('PVE.qemu.HDEdit', {
9fccc702 444 extend: 'Proxmox.window.Edit',
df15b3da
DM
445
446 isAdd: true,
447
7cb345b8
WL
448 backgroundDelay: 5,
449
74c0b9a9
DC
450 width: 600,
451 bodyPadding: 0,
452
8058410f 453 initComponent: function() {
df15b3da
DM
454 var me = this;
455
456 var nodename = me.pveSelNode.data.node;
7a6e0635
TL
457 if (!nodename) {
458 throw "no node name specified";
df15b3da
DM
459 }
460
461 var unused = me.confid && me.confid.match(/^unused\d+$/);
462
d5e771ce 463 me.isCreate = me.confid ? unused : true;
df15b3da
DM
464
465 var ipanel = Ext.create('PVE.qemu.HDInputPanel', {
466 confid: me.confid,
467 nodename: nodename,
468 unused: unused,
f6710aac 469 isCreate: me.isCreate,
df15b3da
DM
470 });
471
df15b3da
DM
472 if (unused) {
473 me.subject = gettext('Unused Disk');
d5e771ce 474 } else if (me.isCreate) {
df15b3da
DM
475 me.subject = gettext('Hard Disk');
476 } else {
477 me.subject = gettext('Hard Disk') + ' (' + me.confid + ')';
478 }
479
8058410f 480 me.items = [ipanel];
df15b3da
DM
481
482 me.callParent();
d5e771ce
EK
483 /* 'data' is assigned an empty array in same file, and here we
484 * use it like an object
485 */
df15b3da
DM
486 me.load({
487 success: function(response, options) {
488 ipanel.setVMConfig(response.result.data);
489 if (me.confid) {
490 var value = response.result.data[me.confid];
491 var drive = PVE.Parser.parseQemuDrive(me.confid, value);
492 if (!drive) {
185a77e5 493 Ext.Msg.alert(gettext('Error'), 'Unable to parse drive options');
df15b3da
DM
494 me.close();
495 return;
496 }
497 ipanel.setDrive(drive);
498 me.isValid(); // trigger validation
499 }
f6710aac 500 },
df15b3da 501 });
f6710aac 502 },
df15b3da 503});