]> git.proxmox.com Git - pve-manager.git/blob - www/manager6/lxc/Config.js
8ef66f399c9882acc3cdfd7f558820ece540b9f1
[pve-manager.git] / www / manager6 / lxc / Config.js
1 Ext.define('PVE.lxc.Config', {
2 extend: 'PVE.panel.Config',
3 alias: 'widget.pveLXCConfig',
4
5 onlineHelp: 'chapter_pct',
6
7 userCls: 'proxmox-tags-full',
8
9 initComponent: function() {
10 var me = this;
11 var vm = me.pveSelNode.data;
12
13 var nodename = vm.node;
14 if (!nodename) {
15 throw "no node name specified";
16 }
17
18 var vmid = vm.vmid;
19 if (!vmid) {
20 throw "no VM ID specified";
21 }
22
23 var template = !!vm.template;
24
25 var running = !!vm.uptime;
26
27 var caps = Ext.state.Manager.get('GuiCap');
28
29 var base_url = '/nodes/' + nodename + '/lxc/' + vmid;
30
31 me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
32 url: '/api2/json' + base_url + '/status/current',
33 interval: 1000,
34 });
35
36 var vm_command = function(cmd, params) {
37 Proxmox.Utils.API2Request({
38 params: params,
39 url: base_url + "/status/" + cmd,
40 waitMsgTarget: me,
41 method: 'POST',
42 failure: function(response, opts) {
43 Ext.Msg.alert('Error', response.htmlStatus);
44 },
45 });
46 };
47
48 var startBtn = Ext.create('Ext.Button', {
49 text: gettext('Start'),
50 disabled: !caps.vms['VM.PowerMgmt'] || running,
51 hidden: template,
52 handler: function() {
53 vm_command('start');
54 },
55 iconCls: 'fa fa-play',
56 });
57
58 var shutdownBtn = Ext.create('PVE.button.Split', {
59 text: gettext('Shutdown'),
60 disabled: !caps.vms['VM.PowerMgmt'] || !running,
61 hidden: template,
62 confirmMsg: Proxmox.Utils.format_task_description('vzshutdown', vmid),
63 handler: function() {
64 vm_command('shutdown');
65 },
66 menu: {
67 items: [{
68 text: gettext('Reboot'),
69 disabled: !caps.vms['VM.PowerMgmt'],
70 confirmMsg: Proxmox.Utils.format_task_description('vzreboot', vmid),
71 tooltip: Ext.String.format(gettext('Reboot {0}'), 'CT'),
72 handler: function() {
73 vm_command("reboot");
74 },
75 iconCls: 'fa fa-refresh',
76 },
77 {
78 text: gettext('Stop'),
79 disabled: !caps.vms['VM.PowerMgmt'],
80 confirmMsg: Proxmox.Utils.format_task_description('vzstop', vmid),
81 tooltip: Ext.String.format(gettext('Stop {0} immediately'), 'CT'),
82 dangerous: true,
83 handler: function() {
84 vm_command("stop");
85 },
86 iconCls: 'fa fa-stop',
87 }],
88 },
89 iconCls: 'fa fa-power-off',
90 });
91
92 var migrateBtn = Ext.create('Ext.Button', {
93 text: gettext('Migrate'),
94 disabled: !caps.vms['VM.Migrate'],
95 hidden: PVE.Utils.isStandaloneNode(),
96 handler: function() {
97 var win = Ext.create('PVE.window.Migrate', {
98 vmtype: 'lxc',
99 nodename: nodename,
100 vmid: vmid,
101 });
102 win.show();
103 },
104 iconCls: 'fa fa-send-o',
105 });
106
107 var moreBtn = Ext.create('Proxmox.button.Button', {
108 text: gettext('More'),
109 menu: {
110 items: [
111 {
112 text: gettext('Clone'),
113 iconCls: 'fa fa-fw fa-clone',
114 hidden: !caps.vms['VM.Clone'],
115 handler: function() {
116 PVE.window.Clone.wrap(nodename, vmid, template, 'lxc');
117 },
118 },
119 {
120 text: gettext('Convert to template'),
121 disabled: template,
122 xtype: 'pveMenuItem',
123 iconCls: 'fa fa-fw fa-file-o',
124 hidden: !caps.vms['VM.Allocate'],
125 confirmMsg: Proxmox.Utils.format_task_description('vztemplate', vmid),
126 handler: function() {
127 Proxmox.Utils.API2Request({
128 url: base_url + '/template',
129 waitMsgTarget: me,
130 method: 'POST',
131 failure: function(response, opts) {
132 Ext.Msg.alert('Error', response.htmlStatus);
133 },
134 });
135 },
136 },
137 {
138 iconCls: 'fa fa-heartbeat ',
139 hidden: !caps.nodes['Sys.Console'],
140 text: gettext('Manage HA'),
141 handler: function() {
142 var ha = vm.hastate;
143 Ext.create('PVE.ha.VMResourceEdit', {
144 vmid: vmid,
145 guestType: 'ct',
146 isCreate: !ha || ha === 'unmanaged',
147 }).show();
148 },
149 },
150 {
151 text: gettext('Remove'),
152 disabled: !caps.vms['VM.Allocate'],
153 itemId: 'removeBtn',
154 handler: function() {
155 Ext.create('PVE.window.SafeDestroyGuest', {
156 url: base_url,
157 item: { type: 'CT', id: vmid },
158 taskName: 'vzdestroy',
159 }).show();
160 },
161 iconCls: 'fa fa-trash-o',
162 },
163 ],
164 },
165 });
166
167 var consoleBtn = Ext.create('PVE.button.ConsoleButton', {
168 disabled: !caps.vms['VM.Console'],
169 consoleType: 'lxc',
170 consoleName: vm.name,
171 hidden: template,
172 nodename: nodename,
173 vmid: vmid,
174 });
175
176 var statusTxt = Ext.create('Ext.toolbar.TextItem', {
177 data: {
178 lock: undefined,
179 },
180 tpl: [
181 '<tpl if="lock">',
182 '<i class="fa fa-lg fa-lock"></i> ({lock})',
183 '</tpl>',
184 ],
185 });
186
187 let tagsContainer = Ext.create('PVE.panel.TagEditContainer', {
188 tags: vm.tags,
189 canEdit: !!caps.vms['VM.Config.Options'],
190 listeners: {
191 change: function(tags) {
192 Proxmox.Utils.API2Request({
193 url: base_url + '/config',
194 method: 'PUT',
195 params: {
196 tags,
197 },
198 success: function() {
199 me.statusStore.load();
200 },
201 failure: function(response) {
202 Ext.Msg.alert('Error', response.htmlStatus);
203 me.statusStore.load();
204 },
205 });
206 },
207 },
208 });
209
210 let vm_text = `${vm.vmid} (${vm.name})`;
211
212 Ext.apply(me, {
213 title: Ext.String.format(gettext("Container {0} on node '{1}'"), vm_text, nodename),
214 hstateid: 'lxctab',
215 tbarSpacing: false,
216 tbar: [statusTxt, tagsContainer, '->', startBtn, shutdownBtn, migrateBtn, consoleBtn, moreBtn],
217 defaults: { statusStore: me.statusStore },
218 items: [
219 {
220 title: gettext('Summary'),
221 xtype: 'pveGuestSummary',
222 iconCls: 'fa fa-book',
223 itemId: 'summary',
224 },
225 ],
226 });
227
228 if (caps.vms['VM.Console'] && !template) {
229 me.items.push(
230 {
231 title: gettext('Console'),
232 itemId: 'consolejs',
233 iconCls: 'fa fa-terminal',
234 xtype: 'pveNoVncConsole',
235 vmid: vmid,
236 consoleType: 'lxc',
237 xtermjs: true,
238 nodename: nodename,
239 },
240 );
241 }
242
243 me.items.push(
244 {
245 title: gettext('Resources'),
246 itemId: 'resources',
247 expandedOnInit: true,
248 iconCls: 'fa fa-cube',
249 xtype: 'pveLxcRessourceView',
250 },
251 {
252 title: gettext('Network'),
253 iconCls: 'fa fa-exchange',
254 itemId: 'network',
255 xtype: 'pveLxcNetworkView',
256 },
257 {
258 title: gettext('DNS'),
259 iconCls: 'fa fa-globe',
260 itemId: 'dns',
261 xtype: 'pveLxcDNS',
262 },
263 {
264 title: gettext('Options'),
265 itemId: 'options',
266 iconCls: 'fa fa-gear',
267 xtype: 'pveLxcOptions',
268 },
269 {
270 title: gettext('Task History'),
271 itemId: 'tasks',
272 iconCls: 'fa fa-list-alt',
273 xtype: 'proxmoxNodeTasks',
274 nodename: nodename,
275 preFilter: {
276 vmid,
277 },
278 },
279 );
280
281 if (caps.vms['VM.Backup']) {
282 me.items.push({
283 title: gettext('Backup'),
284 iconCls: 'fa fa-floppy-o',
285 xtype: 'pveBackupView',
286 itemId: 'backup',
287 },
288 {
289 title: gettext('Replication'),
290 iconCls: 'fa fa-retweet',
291 xtype: 'pveReplicaView',
292 itemId: 'replication',
293 });
294 }
295
296 if ((caps.vms['VM.Snapshot'] || caps.vms['VM.Snapshot.Rollback'] ||
297 caps.vms['VM.Audit']) && !template) {
298 me.items.push({
299 title: gettext('Snapshots'),
300 iconCls: 'fa fa-history',
301 xtype: 'pveGuestSnapshotTree',
302 type: 'lxc',
303 itemId: 'snapshot',
304 });
305 }
306
307 if (caps.vms['VM.Audit']) {
308 me.items.push(
309 {
310 xtype: 'pveFirewallRules',
311 title: gettext('Firewall'),
312 iconCls: 'fa fa-shield',
313 allow_iface: true,
314 base_url: base_url + '/firewall/rules',
315 list_refs_url: base_url + '/firewall/refs',
316 itemId: 'firewall',
317 },
318 {
319 xtype: 'pveFirewallOptions',
320 groups: ['firewall'],
321 iconCls: 'fa fa-gear',
322 onlineHelp: 'pve_firewall_vm_container_configuration',
323 title: gettext('Options'),
324 base_url: base_url + '/firewall/options',
325 fwtype: 'vm',
326 itemId: 'firewall-options',
327 },
328 {
329 xtype: 'pveFirewallAliases',
330 title: gettext('Alias'),
331 groups: ['firewall'],
332 iconCls: 'fa fa-external-link',
333 base_url: base_url + '/firewall/aliases',
334 itemId: 'firewall-aliases',
335 },
336 {
337 xtype: 'pveIPSet',
338 title: gettext('IPSet'),
339 groups: ['firewall'],
340 iconCls: 'fa fa-list-ol',
341 base_url: base_url + '/firewall/ipset',
342 list_refs_url: base_url + '/firewall/refs',
343 itemId: 'firewall-ipset',
344 },
345 );
346 }
347
348 if (caps.vms['VM.Console']) {
349 me.items.push(
350 {
351 title: gettext('Log'),
352 groups: ['firewall'],
353 iconCls: 'fa fa-list',
354 onlineHelp: 'chapter_pve_firewall',
355 itemId: 'firewall-fwlog',
356 xtype: 'proxmoxLogView',
357 url: '/api2/extjs' + base_url + '/firewall/log',
358 log_select_timespan: true,
359 submitFormat: 'U',
360 },
361 );
362 }
363
364 if (caps.vms['Permissions.Modify']) {
365 me.items.push({
366 xtype: 'pveACLView',
367 title: gettext('Permissions'),
368 itemId: 'permissions',
369 iconCls: 'fa fa-unlock',
370 path: '/vms/' + vmid,
371 });
372 }
373
374 me.callParent();
375
376 var prevStatus = 'unknown';
377 me.mon(me.statusStore, 'load', function(s, records, success) {
378 var status;
379 var lock;
380 var rec;
381
382 if (!success) {
383 status = 'unknown';
384 } else {
385 rec = s.data.get('status');
386 status = rec ? rec.data.value : 'unknown';
387 rec = s.data.get('template');
388 template = rec ? rec.data.value : false;
389 rec = s.data.get('lock');
390 lock = rec ? rec.data.value : undefined;
391 }
392
393 statusTxt.update({ lock: lock });
394
395 rec = s.data.get('tags');
396 tagsContainer.loadTags(rec?.data?.value);
397
398 startBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status === 'running' || template);
399 shutdownBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status !== 'running');
400 me.down('#removeBtn').setDisabled(!caps.vms['VM.Allocate'] || status !== 'stopped');
401 consoleBtn.setDisabled(template);
402
403 if (prevStatus === 'stopped' && status === 'running') {
404 let con = me.down('#consolejs');
405 if (con) {
406 con.reload();
407 }
408 }
409
410 prevStatus = status;
411 });
412
413 me.on('afterrender', function() {
414 me.statusStore.startUpdate();
415 });
416
417 me.on('destroy', function() {
418 me.statusStore.stopUpdate();
419 });
420 },
421 });