]> git.proxmox.com Git - pve-manager.git/blob - www/manager6/qemu/HardwareView.js
add efidisk to qemu hardwareview
[pve-manager.git] / www / manager6 / qemu / HardwareView.js
1 // fixme: howto avoid jslint type confusion?
2 /*jslint confusion: true */
3 Ext.define('PVE.qemu.HardwareView', {
4 extend: 'PVE.grid.PendingObjectGrid',
5 alias: ['widget.PVE.qemu.HardwareView'],
6
7 renderKey: function(key, metaData, rec, rowIndex, colIndex, store) {
8 var me = this;
9 var rows = me.rows;
10 var rowdef = rows[key] || {};
11
12 metaData.tdAttr = "valign=middle";
13
14 if (rowdef.tdCls) {
15 metaData.tdCls = rowdef.tdCls;
16 if (rowdef.tdCls == 'pve-itype-icon-storage') {
17 var value = me.getObjectValue(key, '', true);
18 if (value.match(/media=cdrom/)) {
19 metaData.tdCls = 'pve-itype-icon-cdrom';
20 return rowdef.cdheader;
21 }
22 }
23 }
24 return rowdef.header || key;
25 },
26
27 initComponent : function() {
28 var me = this;
29 var i, confid;
30
31 var nodename = me.pveSelNode.data.node;
32 if (!nodename) {
33 throw "no node name specified";
34 }
35
36 var vmid = me.pveSelNode.data.vmid;
37 if (!vmid) {
38 throw "no VM ID specified";
39 }
40
41 var caps = Ext.state.Manager.get('GuiCap');
42
43 var rows = {
44 memory: {
45 header: gettext('Memory'),
46 editor: caps.vms['VM.Config.Memory'] ? 'PVE.qemu.MemoryEdit' : undefined,
47 never_delete: true,
48 defaultValue: 512,
49 tdCls: 'pve-itype-icon-memory',
50 renderer: function(value, metaData, record) {
51 var balloon = me.getObjectValue('balloon');
52 if (balloon) {
53 return PVE.Utils.format_size(balloon*1024*1024) + "/" +
54 PVE.Utils.format_size(value*1024*1024);
55
56 }
57 return PVE.Utils.format_size(value*1024*1024);
58 }
59 },
60 sockets: {
61 header: gettext('Processors'),
62 never_delete: true,
63 editor: (caps.vms['VM.Config.CPU'] || caps.vms['VM.Config.HWType']) ?
64 'PVE.qemu.ProcessorEdit' : undefined,
65 tdCls: 'pve-itype-icon-processor',
66 defaultValue: 1,
67 multiKey: ['sockets', 'cpu', 'cores', 'numa', 'vcpus', 'cpulimit', 'cpuunits'],
68 renderer: function(value, metaData, record, rowIndex, colIndex, store, pending) {
69
70 var sockets = me.getObjectValue('sockets', 1, pending);
71 var model = me.getObjectValue('cpu', undefined, pending);
72 var cores = me.getObjectValue('cores', 1, pending);
73 var numa = me.getObjectValue('numa', undefined, pending);
74 var vcpus = me.getObjectValue('vcpus', undefined, pending);
75 var cpulimit = me.getObjectValue('cpulimit', undefined, pending);
76 var cpuunits = me.getObjectValue('cpuunits', undefined, pending);
77
78 var res = (sockets*cores) + ' (' + sockets + ' sockets, ' + cores + ' cores)';
79
80 if (model) {
81 res += ' [' + model + ']';
82 }
83
84 if (numa) {
85 res += ' [numa=' + numa +']';
86 }
87
88 if (vcpus) {
89 res += ' [vcpus=' + vcpus +']';
90 }
91
92 if (cpulimit) {
93 res += ' [cpulimit=' + cpulimit +']';
94 }
95
96 if (cpuunits) {
97 res += ' [cpuunits=' + cpuunits +']';
98 }
99
100 return res;
101 }
102 },
103 keyboard: {
104 header: gettext('Keyboard Layout'),
105 never_delete: true,
106 editor: caps.vms['VM.Config.Options'] ? 'PVE.qemu.KeyboardEdit' : undefined,
107 tdCls: 'pve-itype-icon-keyboard',
108 defaultValue: '',
109 renderer: PVE.Utils.render_kvm_language
110 },
111 vga: {
112 header: gettext('Display'),
113 editor: caps.vms['VM.Config.HWType'] ? 'PVE.qemu.DisplayEdit' : undefined,
114 never_delete: true,
115 tdCls: 'pve-itype-icon-display',
116 defaultValue: '',
117 renderer: PVE.Utils.render_kvm_vga_driver
118 },
119 cores: {
120 visible: false
121 },
122 cpu: {
123 visible: false
124 },
125 numa: {
126 visible: false
127 },
128 balloon: {
129 visible: false
130 },
131 hotplug: {
132 visible: false
133 },
134 vcpus: {
135 visible: false
136 },
137 cpuunits: {
138 visible: false
139 },
140 cpulimit: {
141 visible: false
142 }
143
144 };
145
146 for (i = 0; i < 4; i++) {
147 confid = "ide" + i;
148 rows[confid] = {
149 group: 1,
150 tdCls: 'pve-itype-icon-storage',
151 editor: 'PVE.qemu.HDEdit',
152 never_delete: caps.vms['VM.Config.Disk'] ? false : true,
153 header: gettext('Hard Disk') + ' (' + confid +')',
154 cdheader: gettext('CD/DVD Drive') + ' (' + confid +')'
155 };
156 }
157 for (i = 0; i < 6; i++) {
158 confid = "sata" + i;
159 rows[confid] = {
160 group: 1,
161 tdCls: 'pve-itype-icon-storage',
162 editor: 'PVE.qemu.HDEdit',
163 never_delete: caps.vms['VM.Config.Disk'] ? false : true,
164 header: gettext('Hard Disk') + ' (' + confid +')',
165 cdheader: gettext('CD/DVD Drive') + ' (' + confid +')'
166 };
167 }
168 for (i = 0; i < 16; i++) {
169 confid = "scsi" + i;
170 rows[confid] = {
171 group: 1,
172 tdCls: 'pve-itype-icon-storage',
173 editor: 'PVE.qemu.HDEdit',
174 never_delete: caps.vms['VM.Config.Disk'] ? false : true,
175 header: gettext('Hard Disk') + ' (' + confid +')',
176 cdheader: gettext('CD/DVD Drive') + ' (' + confid +')'
177 };
178 }
179 for (i = 0; i < 16; i++) {
180 confid = "virtio" + i;
181 rows[confid] = {
182 group: 1,
183 tdCls: 'pve-itype-icon-storage',
184 editor: 'PVE.qemu.HDEdit',
185 never_delete: caps.vms['VM.Config.Disk'] ? false : true,
186 header: gettext('Hard Disk') + ' (' + confid +')',
187 cdheader: gettext('CD/DVD Drive') + ' (' + confid +')'
188 };
189 }
190 for (i = 0; i < 32; i++) {
191 confid = "net" + i;
192 rows[confid] = {
193 group: 2,
194 tdCls: 'pve-itype-icon-network',
195 editor: caps.vms['VM.Config.Network'] ? 'PVE.qemu.NetworkEdit' : undefined,
196 never_delete: caps.vms['VM.Config.Network'] ? false : true,
197 header: gettext('Network Device') + ' (' + confid +')'
198 };
199 }
200 rows.efidisk0 = {
201 group: 3,
202 tdCls: 'pve-itype-icon-storage',
203 editor: null,
204 never_delete: caps.vms['VM.Config.Disk'] ? false : true,
205 header: gettext('EFI Disk')
206 };
207 for (i = 0; i < 8; i++) {
208 rows["unused" + i] = {
209 group: 4,
210 tdCls: 'pve-itype-icon-storage',
211 editor: caps.vms['VM.Config.Disk'] ? 'PVE.qemu.HDEdit' : undefined,
212 header: gettext('Unused Disk') + ' ' + i
213 };
214 }
215
216 var sorterFn = function(rec1, rec2) {
217 var v1 = rec1.data.key;
218 var v2 = rec2.data.key;
219 var g1 = rows[v1].group || 0;
220 var g2 = rows[v2].group || 0;
221
222 return (g1 !== g2) ?
223 (g1 > g2 ? 1 : -1) : (v1 > v2 ? 1 : (v1 < v2 ? -1 : 0));
224 };
225
226 var reload = function() {
227 me.rstore.load();
228 };
229
230 var baseurl = 'nodes/' + nodename + '/qemu/' + vmid + '/config';
231
232 var sm = Ext.create('Ext.selection.RowModel', {});
233
234 var run_editor = function() {
235 var rec = sm.getSelection()[0];
236 if (!rec) {
237 return;
238 }
239
240 var rowdef = rows[rec.data.key];
241 if (!rowdef.editor) {
242 return;
243 }
244
245 var editor = rowdef.editor;
246 if (rowdef.tdCls == 'pve-itype-icon-storage') {
247 var value = me.getObjectValue(rec.data.key, '', true);
248 if (value.match(/media=cdrom/)) {
249 editor = 'PVE.qemu.CDEdit';
250 }
251 }
252
253 var win;
254
255 if (Ext.isString(editor)) {
256 win = Ext.create(editor, {
257 pveSelNode: me.pveSelNode,
258 confid: rec.data.key,
259 url: '/api2/extjs/' + baseurl
260 });
261 } else {
262 var config = Ext.apply({
263 pveSelNode: me.pveSelNode,
264 confid: rec.data.key,
265 url: '/api2/extjs/' + baseurl
266 }, rowdef.editor);
267 win = Ext.createWidget(rowdef.editor.xtype, config);
268 win.load();
269 }
270
271 win.show();
272 win.on('destroy', reload);
273 };
274
275 var run_diskthrottle = function() {
276 var rec = sm.getSelection()[0];
277 if (!rec) {
278 return;
279 }
280
281 var win = Ext.create('PVE.qemu.HDThrottle', {
282 pveSelNode: me.pveSelNode,
283 confid: rec.data.key,
284 url: '/api2/extjs/' + baseurl
285 });
286
287 win.show();
288 win.on('destroy', reload);
289 };
290
291 var run_resize = function() {
292 var rec = sm.getSelection()[0];
293 if (!rec) {
294 return;
295 }
296
297 var win = Ext.create('PVE.window.HDResize', {
298 disk: rec.data.key,
299 nodename: nodename,
300 vmid: vmid
301 });
302
303 win.show();
304
305 win.on('destroy', reload);
306 };
307
308 var run_cpuoptions = function() {
309 var sockets = me.getObjectValue('sockets', 1);
310 var cores = me.getObjectValue('cores', 1);
311
312 var win = Ext.create('PVE.qemu.CPUOptions', {
313 maxvcpus: sockets * cores,
314 vmid: vmid,
315 pveSelNode: me.pveSelNode,
316 url: '/api2/extjs/' + baseurl
317 });
318
319 win.show();
320
321 win.on('destroy', reload);
322 };
323
324 var run_move = function() {
325 var rec = sm.getSelection()[0];
326 if (!rec) {
327 return;
328 }
329
330 var win = Ext.create('PVE.window.HDMove', {
331 disk: rec.data.key,
332 nodename: nodename,
333 vmid: vmid
334 });
335
336 win.show();
337
338 win.on('destroy', reload);
339 };
340
341 var edit_btn = new PVE.button.Button({
342 text: gettext('Edit'),
343 selModel: sm,
344 disabled: true,
345 handler: run_editor
346 });
347
348 var resize_btn = new PVE.button.Button({
349 text: gettext('Resize disk'),
350 selModel: sm,
351 disabled: true,
352 handler: run_resize
353 });
354
355 var move_btn = new PVE.button.Button({
356 text: gettext('Move disk'),
357 selModel: sm,
358 disabled: true,
359 handler: run_move
360 });
361
362 var diskthrottle_btn = new PVE.button.Button({
363 text: gettext('Disk Throttle'),
364 selModel: sm,
365 disabled: true,
366 handler: run_diskthrottle
367 });
368
369 var cpuoptions_btn = new Ext.Button({
370 text: gettext('CPU options'),
371 handler: run_cpuoptions
372 });
373
374 var remove_btn = new PVE.button.Button({
375 text: gettext('Remove'),
376 selModel: sm,
377 disabled: true,
378 dangerous: true,
379 confirmMsg: function(rec) {
380 var msg = Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
381 "'" + me.renderKey(rec.data.key, {}, rec) + "'");
382 if (rec.data.key.match(/^unused\d+$/)) {
383 msg += " " + gettext('This will permanently erase all data.');
384 }
385
386 return msg;
387 },
388 handler: function(b, e, rec) {
389 PVE.Utils.API2Request({
390 url: '/api2/extjs/' + baseurl,
391 waitMsgTarget: me,
392 method: 'PUT',
393 params: {
394 'delete': rec.data.key
395 },
396 callback: function() {
397 reload();
398 },
399 failure: function (response, opts) {
400 Ext.Msg.alert('Error', response.htmlStatus);
401 }
402 });
403 }
404 });
405
406 var revert_btn = new PVE.button.Button({
407 text: gettext('Revert'),
408 selModel: sm,
409 disabled: true,
410 handler: function(b, e, rec) {
411 var rowdef = me.rows[rec.data.key] || {};
412 var keys = rowdef.multiKey || [ rec.data.key ];
413 var revert = keys.join(',');
414 PVE.Utils.API2Request({
415 url: '/api2/extjs/' + baseurl,
416 waitMsgTarget: me,
417 method: 'PUT',
418 params: {
419 'revert': revert
420 },
421 callback: function() {
422 reload();
423 },
424 failure: function (response, opts) {
425 Ext.Msg.alert('Error',response.htmlStatus);
426 }
427 });
428 }
429 });
430
431 var set_button_status = function() {
432 var sm = me.getSelectionModel();
433 var rec = sm.getSelection()[0];
434
435 if (!rec) {
436 remove_btn.disable();
437 edit_btn.disable();
438 resize_btn.disable();
439 move_btn.disable();
440 diskthrottle_btn.disable();
441 revert_btn.disable();
442 return;
443 }
444 var key = rec.data.key;
445 var value = rec.data.value;
446 var rowdef = rows[key];
447
448 var pending = rec.data['delete'] || me.hasPendingChanges(key);
449 var isDisk = !key.match(/^unused\d+/) &&
450 rowdef.tdCls == 'pve-itype-icon-storage' &&
451 (value && !value.match(/media=cdrom/));
452
453 remove_btn.setDisabled(rec.data['delete'] || (rowdef.never_delete === true));
454
455 edit_btn.setDisabled(rec.data['delete'] || !rowdef.editor);
456
457 resize_btn.setDisabled(pending || !isDisk);
458
459 move_btn.setDisabled(pending || !isDisk);
460
461 diskthrottle_btn.setDisabled(pending || !isDisk);
462
463 revert_btn.setDisabled(!pending);
464
465 };
466
467 Ext.apply(me, {
468 url: '/api2/json/' + 'nodes/' + nodename + '/qemu/' + vmid + '/pending',
469 interval: 5000,
470 selModel: sm,
471 tbar: [
472 {
473 text: gettext('Add'),
474 menu: new Ext.menu.Menu({
475 items: [
476 {
477 text: gettext('Hard Disk'),
478 iconCls: 'pve-itype-icon-storage',
479 disabled: !caps.vms['VM.Config.Disk'],
480 handler: function() {
481 var win = Ext.create('PVE.qemu.HDEdit', {
482 url: '/api2/extjs/' + baseurl,
483 pveSelNode: me.pveSelNode
484 });
485 win.on('destroy', reload);
486 win.show();
487 }
488 },
489 {
490 text: gettext('CD/DVD Drive'),
491 iconCls: 'pve-itype-icon-cdrom',
492 disabled: !caps.vms['VM.Config.Disk'],
493 handler: function() {
494 var win = Ext.create('PVE.qemu.CDEdit', {
495 url: '/api2/extjs/' + baseurl,
496 pveSelNode: me.pveSelNode
497 });
498 win.on('destroy', reload);
499 win.show();
500 }
501 },
502 {
503 text: gettext('Network Device'),
504 iconCls: 'pve-itype-icon-network',
505 disabled: !caps.vms['VM.Config.Network'],
506 handler: function() {
507 var win = Ext.create('PVE.qemu.NetworkEdit', {
508 url: '/api2/extjs/' + baseurl,
509 pveSelNode: me.pveSelNode
510 });
511 win.on('destroy', reload);
512 win.show();
513 }
514 }
515 ]
516 })
517 },
518 remove_btn,
519 edit_btn,
520 resize_btn,
521 move_btn,
522 diskthrottle_btn,
523 cpuoptions_btn,
524 revert_btn
525 ],
526 rows: rows,
527 sorterFn: sorterFn,
528 listeners: {
529 itemdblclick: run_editor,
530 selectionchange: set_button_status
531 }
532 });
533
534 me.callParent();
535
536 me.on('activate', me.rstore.startUpdate);
537 me.on('destroy', me.rstore.stopUpdate);
538
539 me.mon(me.rstore, 'refresh', function() {
540 set_button_status();
541 });
542 }
543 });