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