]>
Commit | Line | Data |
---|---|---|
156095db DM |
1 | Ext.define('PVE.qemu.Config', { |
2 | extend: 'PVE.panel.Config', | |
3 | alias: 'widget.PVE.qemu.Config', | |
4 | ||
c8802a60 | 5 | onlineHelp: 'chapter_virtual_machines', |
3c724630 | 6 | |
156095db DM |
7 | initComponent: function() { |
8 | var me = this; | |
d6ba66e1 | 9 | var vm = me.pveSelNode.data; |
156095db | 10 | |
d6ba66e1 | 11 | var nodename = vm.node; |
156095db DM |
12 | if (!nodename) { |
13 | throw "no node name specified"; | |
14 | } | |
15 | ||
d6ba66e1 | 16 | var vmid = vm.vmid; |
156095db DM |
17 | if (!vmid) { |
18 | throw "no VM ID specified"; | |
19 | } | |
540fdc8b | 20 | |
d6ba66e1 | 21 | var template = !!vm.template; |
156095db | 22 | |
d6ba66e1 | 23 | var running = !!vm.uptime; |
9fe20b3f | 24 | |
156095db DM |
25 | var caps = Ext.state.Manager.get('GuiCap'); |
26 | ||
27 | var base_url = '/nodes/' + nodename + "/qemu/" + vmid; | |
540fdc8b | 28 | |
9cb193cf | 29 | me.statusStore = Ext.create('Proxmox.data.ObjectStore', { |
156095db DM |
30 | url: '/api2/json' + base_url + '/status/current', |
31 | interval: 1000 | |
32 | }); | |
33 | ||
34 | var vm_command = function(cmd, params) { | |
e7ade592 | 35 | Proxmox.Utils.API2Request({ |
156095db DM |
36 | params: params, |
37 | url: base_url + '/status/' + cmd, | |
38 | waitMsgTarget: me, | |
39 | method: 'POST', | |
40 | failure: function(response, opts) { | |
41 | Ext.Msg.alert('Error', response.htmlStatus); | |
42 | } | |
43 | }); | |
44 | }; | |
45 | ||
540fdc8b | 46 | var resumeBtn = Ext.create('Ext.Button', { |
156095db DM |
47 | text: gettext('Resume'), |
48 | disabled: !caps.vms['VM.PowerMgmt'], | |
394a9983 | 49 | hidden: true, |
156095db DM |
50 | handler: function() { |
51 | vm_command('resume'); | |
d4333933 DC |
52 | }, |
53 | iconCls: 'fa fa-play' | |
540fdc8b | 54 | }); |
156095db | 55 | |
540fdc8b | 56 | var startBtn = Ext.create('Ext.Button', { |
156095db | 57 | text: gettext('Start'), |
9fe20b3f | 58 | disabled: !caps.vms['VM.PowerMgmt'] || running, |
6ecdb340 | 59 | hidden: template, |
156095db DM |
60 | handler: function() { |
61 | vm_command('start'); | |
d4333933 | 62 | }, |
22f2f9d6 | 63 | iconCls: 'fa fa-play' |
540fdc8b DC |
64 | }); |
65 | ||
540fdc8b | 66 | var migrateBtn = Ext.create('Ext.Button', { |
156095db DM |
67 | text: gettext('Migrate'), |
68 | disabled: !caps.vms['VM.Migrate'], | |
6ecdb340 | 69 | hidden: PVE.data.ResourceStore.getNodes().length < 2, |
156095db DM |
70 | handler: function() { |
71 | var win = Ext.create('PVE.window.Migrate', { | |
72 | vmtype: 'qemu', | |
73 | nodename: nodename, | |
74 | vmid: vmid | |
75 | }); | |
76 | win.show(); | |
d4333933 DC |
77 | }, |
78 | iconCls: 'fa fa-send-o' | |
156095db | 79 | }); |
540fdc8b | 80 | |
5720fafa | 81 | var moreBtn = Ext.create('Proxmox.button.Button', { |
757f4362 TL |
82 | text: gettext('More'), |
83 | menu: { items: [ | |
84 | { | |
85 | text: gettext('Clone'), | |
86 | iconCls: 'fa fa-fw fa-clone', | |
87 | hidden: caps.vms['VM.Clone'] ? false : true, | |
88 | handler: function() { | |
0718aefc | 89 | PVE.window.Clone.wrap(nodename, vmid, template, 'qemu'); |
757f4362 TL |
90 | } |
91 | }, | |
92 | { | |
d6dab970 DC |
93 | text: gettext('Convert to template'), |
94 | disabled: template, | |
757f4362 | 95 | xtype: 'pveMenuItem', |
d6dab970 DC |
96 | iconCls: 'fa fa-fw fa-file-o', |
97 | hidden: caps.vms['VM.Allocate'] ? false : true, | |
e7ade592 | 98 | confirmMsg: Proxmox.Utils.format_task_description('qmtemplate', vmid), |
d6dab970 | 99 | handler: function() { |
e7ade592 | 100 | Proxmox.Utils.API2Request({ |
d6dab970 DC |
101 | url: base_url + '/template', |
102 | waitMsgTarget: me, | |
103 | method: 'POST', | |
104 | failure: function(response, opts) { | |
105 | Ext.Msg.alert('Error', response.htmlStatus); | |
106 | } | |
107 | }); | |
108 | } | |
757f4362 | 109 | }, |
11480a8c TL |
110 | { |
111 | iconCls: 'fa fa-heartbeat ', | |
112 | hidden: !caps.nodes['Sys.Console'], | |
113 | text: gettext('Manage HA'), | |
114 | handler: function() { | |
d6ba66e1 | 115 | var ha = vm.hastate; |
11480a8c TL |
116 | Ext.create('PVE.ha.VMResourceEdit', { |
117 | vmid: vmid, | |
118 | isCreate: (!ha || ha === 'unmanaged') | |
119 | }).show(); | |
120 | } | |
121 | }, | |
757f4362 TL |
122 | { |
123 | text: gettext('Remove'), | |
124 | itemId: 'removeBtn', | |
125 | disabled: !caps.vms['VM.Allocate'], | |
126 | handler: function() { | |
127 | Ext.create('PVE.window.SafeDestroy', { | |
128 | url: base_url, | |
129 | item: { type: 'VM', id: vmid } | |
130 | }).show(); | |
131 | }, | |
132 | iconCls: 'fa fa-trash-o' | |
133 | } | |
134 | ]} | |
c8fc7a4e EK |
135 | }); |
136 | ||
889c7083 | 137 | var shutdownBtn = Ext.create('PVE.button.Split', { |
156095db | 138 | text: gettext('Shutdown'), |
9fe20b3f | 139 | disabled: !caps.vms['VM.PowerMgmt'] || !running, |
6ecdb340 | 140 | hidden: template, |
e7ade592 | 141 | confirmMsg: Proxmox.Utils.format_task_description('qmshutdown', vmid), |
156095db DM |
142 | handler: function() { |
143 | vm_command('shutdown'); | |
889c7083 DC |
144 | }, |
145 | menu: { | |
146 | items: [{ | |
c48535b1 DC |
147 | text: gettext('Reboot'), |
148 | disabled: !caps.vms['VM.PowerMgmt'], | |
f07d8e60 | 149 | tooltip: Ext.String.format(gettext('Shutdown, apply pending changes and reboot {0}'), 'VM'), |
c48535b1 DC |
150 | confirmMsg: Proxmox.Utils.format_task_description('qmreboot', vmid), |
151 | handler: function() { | |
152 | vm_command("reboot"); | |
153 | }, | |
154 | iconCls: 'fa fa-refresh' | |
155 | },{ | |
af856c90 DC |
156 | text: gettext('Pause'), |
157 | disabled: !caps.vms['VM.PowerMgmt'], | |
158 | confirmMsg: Proxmox.Utils.format_task_description('qmpause', vmid), | |
159 | handler: function() { | |
160 | vm_command("suspend"); | |
161 | }, | |
162 | iconCls: 'fa fa-pause' | |
163 | },{ | |
164 | text: gettext('Hibernate'), | |
165 | disabled: !caps.vms['VM.PowerMgmt'], | |
166 | confirmMsg: Proxmox.Utils.format_task_description('qmsuspend', vmid), | |
833b048f | 167 | tooltip: gettext('Suspend to disk'), |
af856c90 DC |
168 | handler: function() { |
169 | vm_command("suspend", { todisk: 1 }); | |
170 | }, | |
af6390f0 | 171 | iconCls: 'fa fa-download' |
af856c90 | 172 | },{ |
889c7083 DC |
173 | text: gettext('Stop'), |
174 | disabled: !caps.vms['VM.PowerMgmt'], | |
175 | dangerous: true, | |
833b048f | 176 | tooltip: Ext.String.format(gettext('Stop {0} immediately'), 'VM'), |
e7ade592 | 177 | confirmMsg: Proxmox.Utils.format_task_description('qmstop', vmid), |
889c7083 DC |
178 | handler: function() { |
179 | vm_command("stop", { timeout: 30 }); | |
d4333933 | 180 | }, |
22f2f9d6 | 181 | iconCls: 'fa fa-stop' |
f2fa05d1 DC |
182 | },{ |
183 | text: gettext('Reset'), | |
184 | disabled: !caps.vms['VM.PowerMgmt'], | |
f07d8e60 | 185 | tooltip: Ext.String.format(gettext('Reset {0} immediately'), 'VM'), |
e7ade592 | 186 | confirmMsg: Proxmox.Utils.format_task_description('qmreset', vmid), |
f2fa05d1 DC |
187 | handler: function() { |
188 | vm_command("reset"); | |
189 | }, | |
190 | iconCls: 'fa fa-bolt' | |
889c7083 | 191 | }] |
d4333933 DC |
192 | }, |
193 | iconCls: 'fa fa-power-off' | |
156095db DM |
194 | }); |
195 | ||
156095db DM |
196 | var consoleBtn = Ext.create('PVE.button.ConsoleButton', { |
197 | disabled: !caps.vms['VM.Console'], | |
6ecdb340 | 198 | hidden: template, |
156095db | 199 | consoleType: 'kvm', |
4ad508ef | 200 | consoleName: vm.name, |
156095db | 201 | nodename: nodename, |
ea541321 | 202 | vmid: vmid |
156095db DM |
203 | }); |
204 | ||
375d2918 DC |
205 | var statusTxt = Ext.create('Ext.toolbar.TextItem', { |
206 | data: { | |
207 | lock: undefined | |
208 | }, | |
209 | tpl: [ | |
210 | '<tpl if="lock">', | |
211 | '<i class="fa fa-lg fa-lock"></i> ({lock})', | |
212 | '</tpl>' | |
213 | ] | |
214 | }); | |
215 | ||
156095db | 216 | Ext.apply(me, { |
4ad508ef | 217 | title: Ext.String.format(gettext("Virtual Machine {0} on node '{1}'"), vm.text, nodename), |
156095db | 218 | hstateid: 'kvmtab', |
375d2918 DC |
219 | tbarSpacing: false, |
220 | tbar: [ statusTxt, '->', resumeBtn, startBtn, shutdownBtn, migrateBtn, consoleBtn, moreBtn ], | |
156095db DM |
221 | defaults: { statusStore: me.statusStore }, |
222 | items: [ | |
223 | { | |
6f68dcbe | 224 | title: gettext('Summary'), |
df0875c2 | 225 | xtype: 'pveGuestSummary', |
c284be32 | 226 | iconCls: 'fa fa-book', |
156095db | 227 | itemId: 'summary' |
156095db DM |
228 | } |
229 | ] | |
230 | }); | |
c5ccc8d0 | 231 | |
1939a006 DC |
232 | if (caps.vms['VM.Console'] && !template) { |
233 | me.items.push({ | |
234 | title: gettext('Console'), | |
235 | itemId: 'console', | |
236 | iconCls: 'fa fa-terminal', | |
237 | xtype: 'pveNoVncConsole', | |
238 | vmid: vmid, | |
239 | consoleType: 'kvm', | |
240 | nodename: nodename | |
241 | }); | |
242 | } | |
243 | ||
244 | me.items.push( | |
245 | { | |
246 | title: gettext('Hardware'), | |
247 | itemId: 'hardware', | |
248 | iconCls: 'fa fa-desktop', | |
249 | xtype: 'PVE.qemu.HardwareView' | |
250 | }, | |
4c507192 DC |
251 | { |
252 | title: 'Cloud-Init', | |
253 | itemId: 'cloudinit', | |
254 | iconCls: 'fa fa-cloud', | |
255 | xtype: 'pveCiPanel' | |
256 | }, | |
1939a006 DC |
257 | { |
258 | title: gettext('Options'), | |
259 | iconCls: 'fa fa-gear', | |
260 | itemId: 'options', | |
261 | xtype: 'PVE.qemu.Options' | |
262 | }, | |
263 | { | |
264 | title: gettext('Task History'), | |
265 | itemId: 'tasks', | |
6c60ab5e | 266 | xtype: 'proxmoxNodeTasks', |
1939a006 | 267 | iconCls: 'fa fa-list', |
6c60ab5e | 268 | nodename: nodename, |
1939a006 DC |
269 | vmidFilter: vmid |
270 | } | |
271 | ); | |
272 | ||
156095db DM |
273 | if (caps.vms['VM.Monitor'] && !template) { |
274 | me.items.push({ | |
275 | title: gettext('Monitor'), | |
c284be32 | 276 | iconCls: 'fa fa-eye', |
156095db DM |
277 | itemId: 'monitor', |
278 | xtype: 'pveQemuMonitor' | |
279 | }); | |
280 | } | |
281 | ||
282 | if (caps.vms['VM.Backup']) { | |
283 | me.items.push({ | |
284 | title: gettext('Backup'), | |
c284be32 | 285 | iconCls: 'fa fa-floppy-o', |
156095db DM |
286 | xtype: 'pveBackupView', |
287 | itemId: 'backup' | |
cb6df20c DC |
288 | }, |
289 | { | |
290 | title: gettext('Replication'), | |
291 | iconCls: 'fa fa-retweet', | |
292 | xtype: 'pveReplicaView', | |
293 | itemId: 'replication' | |
156095db DM |
294 | }); |
295 | } | |
296 | ||
b06d011e DC |
297 | if ((caps.vms['VM.Snapshot'] || caps.vms['VM.Snapshot.Rollback'] || |
298 | caps.vms['VM.Audit']) && !template) { | |
156095db DM |
299 | me.items.push({ |
300 | title: gettext('Snapshots'), | |
c284be32 | 301 | iconCls: 'fa fa-history', |
5b1b9360 DC |
302 | type: 'qemu', |
303 | xtype: 'pveGuestSnapshotTree', | |
156095db DM |
304 | itemId: 'snapshot' |
305 | }); | |
306 | } | |
307 | ||
156095db | 308 | if (caps.vms['VM.Console']) { |
a2f35eb2 | 309 | me.items.push( |
156095db | 310 | { |
c284be32 | 311 | xtype: 'pveFirewallRules', |
156095db | 312 | title: gettext('Firewall'), |
c284be32 DC |
313 | iconCls: 'fa fa-shield', |
314 | allow_iface: true, | |
315 | base_url: base_url + '/firewall/rules', | |
816b62b0 | 316 | list_refs_url: base_url + '/firewall/refs', |
156095db | 317 | itemId: 'firewall' |
c284be32 DC |
318 | }, |
319 | { | |
320 | xtype: 'pveFirewallOptions', | |
321 | groups: ['firewall'], | |
322 | iconCls: 'fa fa-gear', | |
c8802a60 | 323 | onlineHelp: 'pve_firewall_vm_container_configuration', |
c284be32 DC |
324 | title: gettext('Options'), |
325 | base_url: base_url + '/firewall/options', | |
326 | fwtype: 'vm', | |
327 | itemId: 'firewall-options' | |
328 | }, | |
329 | { | |
330 | xtype: 'pveFirewallAliases', | |
331 | title: gettext('Alias'), | |
332 | groups: ['firewall'], | |
333 | iconCls: 'fa fa-external-link', | |
334 | base_url: base_url + '/firewall/aliases', | |
335 | itemId: 'firewall-aliases' | |
336 | }, | |
337 | { | |
338 | xtype: 'pveIPSet', | |
339 | title: gettext('IPSet'), | |
340 | groups: ['firewall'], | |
341 | iconCls: 'fa fa-list-ol', | |
342 | base_url: base_url + '/firewall/ipset', | |
816b62b0 | 343 | list_refs_url: base_url + '/firewall/refs', |
c284be32 DC |
344 | itemId: 'firewall-ipset' |
345 | }, | |
346 | { | |
347 | title: gettext('Log'), | |
348 | groups: ['firewall'], | |
349 | iconCls: 'fa fa-list', | |
c8802a60 | 350 | onlineHelp: 'chapter_pve_firewall', |
c284be32 | 351 | itemId: 'firewall-fwlog', |
0ee5a21e | 352 | xtype: 'proxmoxLogView', |
c284be32 | 353 | url: '/api2/extjs' + base_url + '/firewall/log' |
156095db | 354 | } |
a2f35eb2 | 355 | ); |
156095db DM |
356 | } |
357 | ||
358 | if (caps.vms['Permissions.Modify']) { | |
359 | me.items.push({ | |
360 | xtype: 'pveACLView', | |
361 | title: gettext('Permissions'), | |
c284be32 | 362 | iconCls: 'fa fa-unlock', |
156095db DM |
363 | itemId: 'permissions', |
364 | path: '/vms/' + vmid | |
365 | }); | |
366 | } | |
c5ccc8d0 | 367 | |
156095db DM |
368 | me.callParent(); |
369 | ||
5d7c0d97 | 370 | var prevQMPStatus = 'unknown'; |
540fdc8b | 371 | me.mon(me.statusStore, 'load', function(s, records, success) { |
156095db DM |
372 | var status; |
373 | var qmpstatus; | |
374 | var spice = false; | |
a71b4398 | 375 | var xtermjs = false; |
375d2918 | 376 | var lock; |
156095db DM |
377 | |
378 | if (!success) { | |
156095db DM |
379 | status = qmpstatus = 'unknown'; |
380 | } else { | |
381 | var rec = s.data.get('status'); | |
382 | status = rec ? rec.data.value : 'unknown'; | |
383 | rec = s.data.get('qmpstatus'); | |
384 | qmpstatus = rec ? rec.data.value : 'unknown'; | |
385 | rec = s.data.get('template'); | |
2a727273 | 386 | template = rec.data.value || false; |
375d2918 DC |
387 | rec = s.data.get('lock'); |
388 | lock = rec ? rec.data.value : undefined; | |
2a727273 | 389 | |
156095db | 390 | spice = s.data.get('spice') ? true : false; |
a71b4398 | 391 | xtermjs = s.data.get('serial') ? true : false; |
156095db DM |
392 | |
393 | } | |
394 | ||
6ecdb340 DC |
395 | if (template) { |
396 | return; | |
397 | } | |
398 | ||
38f75802 DC |
399 | var resume = (['prelaunch', 'paused', 'suspended'].indexOf(qmpstatus) !== -1); |
400 | ||
401 | if (resume || lock === 'suspended') { | |
156095db DM |
402 | startBtn.setVisible(false); |
403 | resumeBtn.setVisible(true); | |
404 | } else { | |
405 | startBtn.setVisible(true); | |
406 | resumeBtn.setVisible(false); | |
407 | } | |
408 | ||
409 | consoleBtn.setEnableSpice(spice); | |
a71b4398 | 410 | consoleBtn.setEnableXtermJS(xtermjs); |
156095db | 411 | |
375d2918 DC |
412 | statusTxt.update({ lock: lock }); |
413 | ||
156095db | 414 | startBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status === 'running' || template); |
156095db | 415 | shutdownBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status !== 'running'); |
757f4362 | 416 | me.down('#removeBtn').setDisabled(!caps.vms['VM.Allocate'] || status !== 'stopped'); |
4365549d | 417 | consoleBtn.setDisabled(template); |
c17ecca2 | 418 | |
5d7c0d97 TL |
419 | let wasStopped = ['prelaunch', 'stopped', 'suspended'].indexOf(prevQMPStatus) !== -1; |
420 | if (wasStopped && qmpstatus === 'running') { | |
421 | let con = me.down('#console'); | |
c17ecca2 | 422 | if (con) { |
5d7c0d97 | 423 | con.reload(); |
c17ecca2 SR |
424 | } |
425 | } | |
426 | ||
5d7c0d97 | 427 | prevQMPStatus = qmpstatus; |
156095db DM |
428 | }); |
429 | ||
430 | me.on('afterrender', function() { | |
431 | me.statusStore.startUpdate(); | |
432 | }); | |
433 | ||
434 | me.on('destroy', function() { | |
435 | me.statusStore.stopUpdate(); | |
436 | }); | |
437 | } | |
438 | }); |