]> git.proxmox.com Git - pve-manager.git/blob - www/manager6/lxc/Network.js
use Proxmox.Utils instead of PVE.Utils
[pve-manager.git] / www / manager6 / lxc / Network.js
1 Ext.define('PVE.lxc.NetworkInputPanel', {
2 extend: 'PVE.panel.InputPanel',
3 alias: 'widget.pveLxcNetworkInputPanel',
4
5 insideWizard: false,
6
7 onlineHelp: 'pct_container_network',
8
9 setNodename: function(nodename) {
10 var me = this;
11
12 if (!nodename || (me.nodename === nodename)) {
13 return;
14 }
15
16 me.nodename = nodename;
17
18 var bridgesel = me.query("[isFormField][name=bridge]")[0];
19 bridgesel.setNodename(nodename);
20 },
21
22 onGetValues: function(values) {
23 var me = this;
24
25 var id;
26 if (me.isCreate) {
27 id = values.id;
28 delete values.id;
29 } else {
30 id = me.ifname;
31 }
32
33 if (!id) {
34 return {};
35 }
36
37 var newdata = {};
38
39 if (values.ipv6mode !== 'static') {
40 values.ip6 = values.ipv6mode;
41 }
42 if (values.ipv4mode !== 'static') {
43 values.ip = values.ipv4mode;
44 }
45 newdata[id] = PVE.Parser.printLxcNetwork(values);
46 return newdata;
47 },
48
49 initComponent : function() {
50 var me = this;
51
52 if (!me.dataCache) {
53 throw "no dataCache specified";
54 }
55
56 var cdata = {};
57
58 if (me.insideWizard) {
59 me.ifname = 'net0';
60 cdata.name = 'eth0';
61 }
62
63 if (!me.isCreate) {
64 if (!me.ifname) {
65 throw "no interface name specified";
66 }
67 if (!me.dataCache[me.ifname]) {
68 throw "no such interface '" + me.ifname + "'";
69 }
70
71 cdata = PVE.Parser.parseLxcNetwork(me.dataCache[me.ifname]);
72 }
73
74 var i;
75 for (i = 0; i < 10; i++) {
76 if (me.isCreate && !me.dataCache['net'+i.toString()]) {
77 me.ifname = 'net' + i.toString();
78 break;
79 }
80 }
81
82 var idselector = {
83 xtype: 'hidden',
84 name: 'id',
85 value: me.ifname
86 };
87
88 me.column1 = [
89 idselector,
90 {
91 xtype: 'textfield',
92 name: 'name',
93 fieldLabel: gettext('Name') + ' (i.e. eth0)',
94 allowBlank: false,
95 value: cdata.name,
96 validator: function(value) {
97 var result = '';
98 Ext.Object.each(me.dataCache, function(key, netstr) {
99 if (!key.match(/^net\d+/) || key === me.ifname) {
100 return; // continue
101 }
102 var net = PVE.Parser.parseLxcNetwork(netstr);
103 if (net.name === value) {
104 result = "interface name already in use";
105 return false;
106 }
107 });
108 if (result !== '') {
109 return result;
110 }
111 // validator can return bool/string
112 /*jslint confusion:true*/
113 return true;
114 }
115 },
116 {
117 xtype: 'textfield',
118 name: 'hwaddr',
119 fieldLabel: gettext('MAC address'),
120 vtype: 'MacAddress',
121 value: cdata.hwaddr,
122 allowBlank: true,
123 emptyText: 'auto'
124 },
125 {
126 xtype: 'PVE.form.BridgeSelector',
127 name: 'bridge',
128 nodename: me.nodename,
129 fieldLabel: gettext('Bridge'),
130 value: cdata.bridge,
131 allowBlank: false
132 },
133 {
134 xtype: 'pveVlanField',
135 name: 'tag',
136 value: cdata.tag
137 },
138 {
139 xtype: 'numberfield',
140 name: 'rate',
141 fieldLabel: gettext('Rate limit') + ' (MB/s)',
142 minValue: 0,
143 maxValue: 10*1024,
144 value: cdata.rate,
145 emptyText: 'unlimited',
146 allowBlank: true
147 },
148 {
149 xtype: 'pvecheckbox',
150 fieldLabel: gettext('Firewall'),
151 name: 'firewall',
152 checked: cdata.firewall
153 }
154 ];
155
156 var dhcp4 = (cdata.ip === 'dhcp');
157 if (dhcp4) {
158 cdata.ip = '';
159 cdata.gw = '';
160 }
161
162 var auto6 = (cdata.ip6 === 'auto');
163 var dhcp6 = (cdata.ip6 === 'dhcp');
164 if (auto6 || dhcp6) {
165 cdata.ip6 = '';
166 cdata.gw6 = '';
167 }
168
169 me.column2 = [
170 {
171 layout: {
172 type: 'hbox',
173 align: 'middle'
174 },
175 border: false,
176 margin: '0 0 5 0',
177 items: [
178 {
179 xtype: 'label',
180 text: 'IPv4:' // do not localize
181 },
182 {
183 xtype: 'radiofield',
184 boxLabel: gettext('Static'),
185 name: 'ipv4mode',
186 inputValue: 'static',
187 checked: !dhcp4,
188 margin: '0 0 0 10',
189 listeners: {
190 change: function(cb, value) {
191 me.down('field[name=ip]').setDisabled(!value);
192 me.down('field[name=gw]').setDisabled(!value);
193 }
194 }
195 },
196 {
197 xtype: 'radiofield',
198 boxLabel: 'DHCP', // do not localize
199 name: 'ipv4mode',
200 inputValue: 'dhcp',
201 checked: dhcp4,
202 margin: '0 0 0 10'
203 }
204 ]
205 },
206 {
207 xtype: 'textfield',
208 name: 'ip',
209 vtype: 'IPCIDRAddress',
210 value: cdata.ip,
211 disabled: dhcp4,
212 fieldLabel: 'IPv4/CIDR' // do not localize
213 },
214 {
215 xtype: 'textfield',
216 name: 'gw',
217 value: cdata.gw,
218 vtype: 'IPAddress',
219 disabled: dhcp4,
220 fieldLabel: gettext('Gateway') + ' (IPv4)',
221 margin: '0 0 3 0' // override bottom margin to account for the menuseparator
222 },
223 {
224 xtype: 'menuseparator',
225 height: '3',
226 margin: '0'
227 },
228 {
229 layout: {
230 type: 'hbox',
231 align: 'middle'
232 },
233 border: false,
234 margin: '0 0 5 0',
235 items: [
236 {
237 xtype: 'label',
238 text: 'IPv6:' // do not localize
239 },
240 {
241 xtype: 'radiofield',
242 boxLabel: gettext('Static'),
243 name: 'ipv6mode',
244 inputValue: 'static',
245 checked: !(auto6 || dhcp6),
246 margin: '0 0 0 10',
247 listeners: {
248 change: function(cb, value) {
249 me.down('field[name=ip6]').setDisabled(!value);
250 me.down('field[name=gw6]').setDisabled(!value);
251 }
252 }
253 },
254 {
255 xtype: 'radiofield',
256 boxLabel: 'DHCP', // do not localize
257 name: 'ipv6mode',
258 inputValue: 'dhcp',
259 checked: dhcp6,
260 margin: '0 0 0 10'
261 },
262 {
263 xtype: 'radiofield',
264 boxLabel: 'SLAAC', // do not localize
265 name: 'ipv6mode',
266 inputValue: 'auto',
267 checked: auto6,
268 margin: '0 0 0 10'
269 }
270 ]
271 },
272 {
273 xtype: 'textfield',
274 name: 'ip6',
275 value: cdata.ip6,
276 vtype: 'IP6CIDRAddress',
277 disabled: (dhcp6 || auto6),
278 fieldLabel: 'IPv6/CIDR' // do not localize
279 },
280 {
281 xtype: 'textfield',
282 name: 'gw6',
283 vtype: 'IP6Address',
284 value: cdata.gw6,
285 disabled: (dhcp6 || auto6),
286 fieldLabel: gettext('Gateway') + ' (IPv6)'
287 }
288 ];
289
290 me.callParent();
291 }
292 });
293
294
295 Ext.define('PVE.lxc.NetworkEdit', {
296 extend: 'PVE.window.Edit',
297
298 isAdd: true,
299
300 initComponent : function() {
301 var me = this;
302
303 if (!me.dataCache) {
304 throw "no dataCache specified";
305 }
306
307 if (!me.nodename) {
308 throw "no node name specified";
309 }
310
311 var ipanel = Ext.create('PVE.lxc.NetworkInputPanel', {
312 ifname: me.ifname,
313 nodename: me.nodename,
314 dataCache: me.dataCache,
315 isCreate: me.isCreate
316 });
317
318 Ext.apply(me, {
319 subject: gettext('Network Device') + ' (veth)',
320 digest: me.dataCache.digest,
321 items: [ ipanel ]
322 });
323
324 me.callParent();
325 }
326 });
327
328 Ext.define('PVE.lxc.NetworkView', {
329 extend: 'Ext.grid.GridPanel',
330 alias: 'widget.pveLxcNetworkView',
331
332 onlineHelp: 'pct_container_network',
333
334 dataCache: {}, // used to store result of last load
335
336 stateful: true,
337 stateId: 'grid-lxc-network',
338
339 load: function() {
340 var me = this;
341
342 Proxmox.Utils.setErrorMask(me, true);
343
344 Proxmox.Utils.API2Request({
345 url: me.url,
346 failure: function(response, opts) {
347 Proxmox.Utils.setErrorMask(me, gettext('Error') + ': ' + response.htmlStatus);
348 },
349 success: function(response, opts) {
350 Proxmox.Utils.setErrorMask(me, false);
351 var result = Ext.decode(response.responseText);
352 var data = result.data || {};
353 me.dataCache = data;
354 var records = [];
355 Ext.Object.each(data, function(key, value) {
356 if (!key.match(/^net\d+/)) {
357 return; // continue
358 }
359 var net = PVE.Parser.parseLxcNetwork(value);
360 net.id = key;
361 records.push(net);
362 });
363 me.store.loadData(records);
364 me.down('button[name=addButton]').setDisabled((records.length >= 10));
365 }
366 });
367 },
368
369 initComponent : function() {
370 var me = this;
371
372 var nodename = me.pveSelNode.data.node;
373 if (!nodename) {
374 throw "no node name specified";
375 }
376
377 var vmid = me.pveSelNode.data.vmid;
378 if (!vmid) {
379 throw "no VM ID specified";
380 }
381
382 var caps = Ext.state.Manager.get('GuiCap');
383
384 me.url = '/nodes/' + nodename + '/lxc/' + vmid + '/config';
385
386 var store = new Ext.data.Store({
387 model: 'pve-lxc-network',
388 sorters: [
389 {
390 property : 'id',
391 direction: 'ASC'
392 }
393 ]
394 });
395
396 var sm = Ext.create('Ext.selection.RowModel', {});
397
398 var remove_btn = new Proxmox.button.Button({
399 text: gettext('Remove'),
400 disabled: true,
401 selModel: sm,
402 enableFn: function(rec) {
403 return !!caps.vms['VM.Config.Network'];
404 },
405 confirmMsg: function (rec) {
406 return Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
407 "'" + rec.data.id + "'");
408 },
409 handler: function(btn, event, rec) {
410 Proxmox.Utils.API2Request({
411 url: me.url,
412 waitMsgTarget: me,
413 method: 'PUT',
414 params: { 'delete': rec.data.id, digest: me.dataCache.digest },
415 callback: function() {
416 me.load();
417 },
418 failure: function (response, opts) {
419 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
420 }
421 });
422 }
423 });
424
425 var run_editor = function() {
426 var rec = sm.getSelection()[0];
427 if (!rec) {
428 return;
429 }
430
431 if (!caps.vms['VM.Config.Network']) {
432 return false;
433 }
434
435 var win = Ext.create('PVE.lxc.NetworkEdit', {
436 url: me.url,
437 nodename: nodename,
438 dataCache: me.dataCache,
439 ifname: rec.data.id
440 });
441 win.on('destroy', me.load, me);
442 win.show();
443 };
444
445 var edit_btn = new Proxmox.button.Button({
446 text: gettext('Edit'),
447 selModel: sm,
448 disabled: true,
449 enableFn: function(rec) {
450 if (!caps.vms['VM.Config.Network']) {
451 return false;
452 }
453 return true;
454 },
455 handler: run_editor
456 });
457
458 Ext.apply(me, {
459 store: store,
460 selModel: sm,
461 tbar: [
462 {
463 text: gettext('Add'),
464 name: 'addButton',
465 disabled: !caps.vms['VM.Config.Network'],
466 handler: function() {
467 var win = Ext.create('PVE.lxc.NetworkEdit', {
468 url: me.url,
469 nodename: nodename,
470 isCreate: true,
471 dataCache: me.dataCache
472 });
473 win.on('destroy', me.load, me);
474 win.show();
475 }
476 },
477 remove_btn,
478 edit_btn
479 ],
480 columns: [
481 {
482 header: 'ID',
483 width: 50,
484 dataIndex: 'id'
485 },
486 {
487 header: gettext('Name'),
488 width: 80,
489 dataIndex: 'name'
490 },
491 {
492 header: gettext('Bridge'),
493 width: 80,
494 dataIndex: 'bridge'
495 },
496 {
497 header: gettext('Firewall'),
498 width: 80,
499 dataIndex: 'firewall',
500 renderer: Proxmox.Utils.format_boolean
501 },
502 {
503 header: gettext('VLAN Tag'),
504 width: 80,
505 dataIndex: 'tag'
506 },
507 {
508 header: gettext('MAC address'),
509 width: 110,
510 dataIndex: 'hwaddr'
511 },
512 {
513 header: gettext('IP address'),
514 width: 150,
515 dataIndex: 'ip',
516 renderer: function(value, metaData, rec) {
517 if (rec.data.ip && rec.data.ip6) {
518 return rec.data.ip + "<br>" + rec.data.ip6;
519 } else if (rec.data.ip6) {
520 return rec.data.ip6;
521 } else {
522 return rec.data.ip;
523 }
524 }
525 },
526 {
527 header: gettext('Gateway'),
528 width: 150,
529 dataIndex: 'gw',
530 renderer: function(value, metaData, rec) {
531 if (rec.data.gw && rec.data.gw6) {
532 return rec.data.gw + "<br>" + rec.data.gw6;
533 } else if (rec.data.gw6) {
534 return rec.data.gw6;
535 } else {
536 return rec.data.gw;
537 }
538 }
539 }
540 ],
541 listeners: {
542 activate: me.load,
543 itemdblclick: run_editor
544 }
545 });
546
547 me.callParent();
548 }
549 }, function() {
550
551 Ext.define('pve-lxc-network', {
552 extend: "Ext.data.Model",
553 proxy: { type: 'memory' },
554 fields: [ 'id', 'name', 'hwaddr', 'bridge',
555 'ip', 'gw', 'ip6', 'gw6', 'tag', 'firewall' ]
556 });
557
558 });
559