]>
Commit | Line | Data |
---|---|---|
342225bf | 1 | Ext.define('PVE.lxc.MountPointInputPanel', { |
ef4ef788 | 2 | extend: 'Proxmox.panel.InputPanel', |
34c235be | 3 | xtype: 'pveLxcMountPointInputPanel', |
342225bf | 4 | |
342225bf DC |
5 | onlineHelp: 'pct_container_storage', |
6 | ||
7aaa492b | 7 | insideWizard: false, |
342225bf | 8 | |
7aaa492b | 9 | unused: false, // add unused disk imaged |
342225bf DC |
10 | unprivileged: false, |
11 | ||
12 | vmconfig: {}, // used to select unused disks | |
13 | ||
658bf725 | 14 | setUnprivileged: function(unprivileged) { |
34c235be DC |
15 | var me = this; |
16 | var vm = me.getViewModel(); | |
17 | me.unprivileged = unprivileged; | |
18 | vm.set('unpriv', unprivileged); | |
658bf725 TL |
19 | }, |
20 | ||
342225bf DC |
21 | onGetValues: function(values) { |
22 | var me = this; | |
23 | ||
85e6b368 | 24 | var confid = me.confid || "mp"+values.mpid; |
f9b63366 | 25 | me.mp.file = me.down('field[name=file]').getValue(); |
342225bf DC |
26 | |
27 | if (me.unused) { | |
85e6b368 | 28 | confid = "mp"+values.mpid; |
342225bf | 29 | } else if (me.isCreate) { |
f9b63366 | 30 | me.mp.file = values.hdstorage + ':' + values.disksize; |
342225bf DC |
31 | } |
32 | ||
34c235be | 33 | // delete unnecessary fields |
85e6b368 | 34 | delete values.mpid; |
34c235be DC |
35 | delete values.hdstorage; |
36 | delete values.disksize; | |
37 | delete values.diskformat; | |
342225bf | 38 | |
7aaa492b TL |
39 | let setMPOpt = (k, src, v) => PVE.Utils.propertyStringSet(me.mp, src, k, v); |
40 | ||
41 | setMPOpt('mp', values.mp); | |
42 | let mountOpts = (values.mountoptions || []).join(';'); | |
43 | setMPOpt('mountoptions', values.mountoptions, mountOpts); | |
44 | setMPOpt('mp', values.mp); | |
45 | setMPOpt('backup', values.backup); | |
46 | setMPOpt('quota', values.quota); | |
47 | setMPOpt('ro', values.ro); | |
48 | setMPOpt('acl', values.acl); | |
49 | setMPOpt('replicate', values.replicate); | |
f9b63366 | 50 | |
7aaa492b | 51 | let res = {}; |
f9b63366 | 52 | res[confid] = PVE.Parser.printLxcMountPoint(me.mp); |
342225bf DC |
53 | return res; |
54 | }, | |
55 | ||
56 | setMountPoint: function(mp) { | |
7aaa492b TL |
57 | let me = this; |
58 | let vm = me.getViewModel(); | |
34c235be | 59 | vm.set('mptype', mp.type); |
c115473d OB |
60 | if (mp.mountoptions) { |
61 | mp.mountoptions = mp.mountoptions.split(';'); | |
62 | } | |
f9b63366 | 63 | me.mp = mp; |
7aaa492b TL |
64 | me.filterMountOptions(); |
65 | me.setValues(mp); | |
66 | }, | |
1780a644 | 67 | |
7aaa492b TL |
68 | filterMountOptions: function() { |
69 | let me = this; | |
70 | if (me.confid === 'rootfs') { | |
71 | let field = me.down('field[name=mountoptions]'); | |
72 | let exclude = ['nodev', 'noexec']; | |
73 | let filtered = field.comboItems.filter(v => !exclude.includes(v[0])); | |
1780a644 OB |
74 | field.setComboItems(filtered); |
75 | } | |
342225bf DC |
76 | }, |
77 | ||
09e7ac8b | 78 | updateVMConfig: function(vmconfig) { |
7aaa492b TL |
79 | let me = this; |
80 | let vm = me.getViewModel(); | |
342225bf | 81 | me.vmconfig = vmconfig; |
34c235be | 82 | vm.set('unpriv', vmconfig.unprivileged); |
09e7ac8b DC |
83 | me.down('field[name=mpid]').validate(); |
84 | }, | |
85 | ||
86 | setVMConfig: function(vmconfig) { | |
87 | let me = this; | |
34c235be | 88 | |
09e7ac8b | 89 | me.updateVMConfig(vmconfig); |
7aaa492b TL |
90 | PVE.Utils.forEachMP((bus, i) => { |
91 | let name = "mp" + i.toString(); | |
34c235be | 92 | if (!Ext.isDefined(vmconfig[name])) { |
85e6b368 | 93 | me.down('field[name=mpid]').setValue(i); |
34c235be | 94 | return false; |
342225bf | 95 | } |
7aaa492b | 96 | return undefined; |
34c235be | 97 | }); |
342225bf DC |
98 | }, |
99 | ||
100 | setNodename: function(nodename) { | |
7aaa492b TL |
101 | let me = this; |
102 | let vm = me.getViewModel(); | |
34c235be | 103 | vm.set('node', nodename); |
34c235be | 104 | me.down('#diskstorage').setNodename(nodename); |
342225bf DC |
105 | }, |
106 | ||
8058410f | 107 | controller: { |
34c235be | 108 | xclass: 'Ext.app.ViewController', |
342225bf | 109 | |
34c235be | 110 | control: { |
85e6b368 | 111 | 'field[name=mpid]': { |
34c235be | 112 | change: function(field, value) { |
143a5071 DC |
113 | let me = this; |
114 | let view = this.getView(); | |
115 | if (view.confid !== 'rootfs') { | |
116 | view.fireEvent('diskidchange', view, `mp${value}`); | |
117 | } | |
34c235be | 118 | field.validate(); |
f6710aac | 119 | }, |
34c235be DC |
120 | }, |
121 | '#hdstorage': { | |
122 | change: function(field, newValue) { | |
7aaa492b | 123 | let me = this; |
34c235be | 124 | if (!newValue) { |
342225bf DC |
125 | return; |
126 | } | |
34c235be | 127 | |
7aaa492b | 128 | let rec = field.store.getById(newValue); |
34c235be DC |
129 | if (!rec) { |
130 | return; | |
342225bf | 131 | } |
7aaa492b | 132 | me.getViewModel().set('type', rec.data.type); |
f6710aac TL |
133 | }, |
134 | }, | |
34c235be | 135 | }, |
34c235be | 136 | init: function(view) { |
7aaa492b TL |
137 | let me = this; |
138 | let vm = this.getViewModel(); | |
f9b63366 | 139 | view.mp = {}; |
34c235be DC |
140 | vm.set('confid', view.confid); |
141 | vm.set('unused', view.unused); | |
142 | vm.set('node', view.nodename); | |
143 | vm.set('unpriv', view.unprivileged); | |
144 | vm.set('hideStorSelector', view.unused || !view.isCreate); | |
2b4c02c0 | 145 | |
7aaa492b | 146 | if (view.isCreate) { // can be array if created from unused disk |
2b4c02c0 | 147 | vm.set('isIncludedInBackup', true); |
7aaa492b TL |
148 | if (view.insideWizard) { |
149 | view.filterMountOptions(); | |
150 | } | |
2b4c02c0 | 151 | } |
87161abf DC |
152 | if (view.selectFree) { |
153 | view.setVMConfig(view.vmconfig); | |
154 | } | |
f6710aac | 155 | }, |
34c235be DC |
156 | }, |
157 | ||
158 | viewModel: { | |
159 | data: { | |
160 | unpriv: false, | |
161 | unused: false, | |
162 | showStorageSelector: false, | |
163 | mptype: '', | |
164 | type: '', | |
165 | confid: '', | |
f6710aac | 166 | node: '', |
34c235be DC |
167 | }, |
168 | ||
169 | formulas: { | |
170 | quota: function(get) { | |
171 | return !(get('type') === 'zfs' || | |
172 | get('type') === 'zfspool' || | |
173 | get('unpriv') || | |
174 | get('isBind')); | |
175 | }, | |
176 | hasMP: function(get) { | |
177 | return !!get('confid') && !get('unused'); | |
178 | }, | |
179 | isRoot: function(get) { | |
180 | return get('confid') === 'rootfs'; | |
181 | }, | |
182 | isBind: function(get) { | |
183 | return get('mptype') === 'bind'; | |
184 | }, | |
185 | isBindOrRoot: function(get) { | |
186 | return get('isBind') || get('isRoot'); | |
f6710aac TL |
187 | }, |
188 | }, | |
34c235be | 189 | }, |
342225bf | 190 | |
34c235be DC |
191 | column1: [ |
192 | { | |
85e6b368 FG |
193 | xtype: 'proxmoxintegerfield', |
194 | name: 'mpid', | |
195 | fieldLabel: gettext('Mount Point ID'), | |
196 | minValue: 0, | |
197 | maxValue: PVE.Utils.mp_counts.mps - 1, | |
34c235be DC |
198 | hidden: true, |
199 | allowBlank: false, | |
6c442961 | 200 | disabled: true, |
34c235be DC |
201 | bind: { |
202 | hidden: '{hasMP}', | |
f6710aac | 203 | disabled: '{hasMP}', |
34c235be | 204 | }, |
34c235be | 205 | validator: function(value) { |
46d9a35c DJ |
206 | let view = this.up('inputpanel'); |
207 | if (!view.rendered) { | |
7aaa492b | 208 | return undefined; |
34c235be | 209 | } |
46d9a35c | 210 | if (Ext.isDefined(view.vmconfig["mp"+value])) { |
34c235be DC |
211 | return "Mount point is already in use."; |
212 | } | |
34c235be | 213 | return true; |
f6710aac | 214 | }, |
34c235be DC |
215 | }, |
216 | { | |
234d2e37 | 217 | xtype: 'pveDiskStorageSelector', |
34c235be | 218 | itemId: 'diskstorage', |
342225bf | 219 | storageContent: 'rootdir', |
34c235be | 220 | hidden: true, |
342225bf | 221 | autoSelect: true, |
34c235be | 222 | selectformat: false, |
c6c8e2fc | 223 | defaultSize: 8, |
34c235be DC |
224 | bind: { |
225 | hidden: '{hideStorSelector}', | |
226 | disabled: '{hideStorSelector}', | |
f6710aac TL |
227 | nodename: '{node}', |
228 | }, | |
34c235be DC |
229 | }, |
230 | { | |
231 | xtype: 'textfield', | |
232 | disabled: true, | |
233 | submitValue: false, | |
234 | fieldLabel: gettext('Disk image'), | |
235 | name: 'file', | |
236 | bind: { | |
f6710aac TL |
237 | hidden: '{!hideStorSelector}', |
238 | }, | |
239 | }, | |
34c235be DC |
240 | ], |
241 | ||
242 | column2: [ | |
243 | { | |
244 | xtype: 'textfield', | |
245 | name: 'mp', | |
246 | value: '', | |
8058410f | 247 | emptyText: gettext('/some/path'), |
34c235be | 248 | allowBlank: false, |
6c442961 | 249 | disabled: true, |
34c235be DC |
250 | fieldLabel: gettext('Path'), |
251 | bind: { | |
252 | hidden: '{isRoot}', | |
f6710aac TL |
253 | disabled: '{isRoot}', |
254 | }, | |
34c235be DC |
255 | }, |
256 | { | |
257 | xtype: 'proxmoxcheckbox', | |
258 | name: 'backup', | |
0bead056 TL |
259 | fieldLabel: gettext('Backup'), |
260 | autoEl: { | |
261 | tag: 'div', | |
262 | 'data-qtip': gettext('Include volume in backup job'), | |
263 | }, | |
34c235be DC |
264 | bind: { |
265 | hidden: '{isRoot}', | |
2b4c02c0 | 266 | disabled: '{isBindOrRoot}', |
f6710aac TL |
267 | value: '{isIncludedInBackup}', |
268 | }, | |
269 | }, | |
34c235be | 270 | ], |
342225bf | 271 | |
34c235be DC |
272 | advancedColumn1: [ |
273 | { | |
274 | xtype: 'proxmoxcheckbox', | |
342225bf DC |
275 | name: 'quota', |
276 | defaultValue: 0, | |
34c235be | 277 | bind: { |
f6710aac | 278 | disabled: '{!quota}', |
34c235be | 279 | }, |
658bf725 TL |
280 | fieldLabel: gettext('Enable quota'), |
281 | listeners: { | |
282 | disable: function() { | |
283 | this.reset(); | |
f6710aac TL |
284 | }, |
285 | }, | |
34c235be DC |
286 | }, |
287 | { | |
288 | xtype: 'proxmoxcheckbox', | |
289 | name: 'ro', | |
290 | defaultValue: 0, | |
291 | bind: { | |
292 | hidden: '{isRoot}', | |
f6710aac | 293 | disabled: '{isRoot}', |
34c235be | 294 | }, |
f6710aac | 295 | fieldLabel: gettext('Read-only'), |
7b6c7881 TL |
296 | }, |
297 | { | |
298 | xtype: 'proxmoxKVComboBox', | |
299 | name: 'mountoptions', | |
300 | fieldLabel: gettext('Mount options'), | |
301 | deleteEmpty: false, | |
302 | comboItems: [ | |
303 | ['noatime', 'noatime'], | |
304 | ['nodev', 'nodev'], | |
305 | ['noexec', 'noexec'], | |
f6710aac | 306 | ['nosuid', 'nosuid'], |
7b6c7881 TL |
307 | ], |
308 | multiSelect: true, | |
309 | value: [], | |
f6710aac | 310 | allowBlank: true, |
7b6c7881 | 311 | }, |
34c235be | 312 | ], |
342225bf | 313 | |
34c235be DC |
314 | advancedColumn2: [ |
315 | { | |
316 | xtype: 'proxmoxKVComboBox', | |
317 | name: 'acl', | |
318 | fieldLabel: 'ACLs', | |
319 | deleteEmpty: false, | |
320 | comboItems: [ | |
321 | ['__default__', Proxmox.Utils.defaultText], | |
322 | ['1', Proxmox.Utils.enabledText], | |
f6710aac | 323 | ['0', Proxmox.Utils.disabledText], |
34c235be DC |
324 | ], |
325 | value: '__default__', | |
326 | bind: { | |
f6710aac | 327 | disabled: '{isBind}', |
34c235be | 328 | }, |
f6710aac | 329 | allowBlank: true, |
34c235be DC |
330 | }, |
331 | { | |
332 | xtype: 'proxmoxcheckbox', | |
333 | inputValue: '0', // reverses the logic | |
334 | name: 'replicate', | |
f6710aac TL |
335 | fieldLabel: gettext('Skip replication'), |
336 | }, | |
337 | ], | |
342225bf DC |
338 | }); |
339 | ||
340 | Ext.define('PVE.lxc.MountPointEdit', { | |
9fccc702 | 341 | extend: 'Proxmox.window.Edit', |
342225bf DC |
342 | |
343 | unprivileged: false, | |
344 | ||
8058410f | 345 | initComponent: function() { |
7aaa492b | 346 | let me = this; |
342225bf | 347 | |
7aaa492b | 348 | let nodename = me.pveSelNode.data.node; |
342225bf DC |
349 | if (!nodename) { |
350 | throw "no node name specified"; | |
351 | } | |
352 | ||
7aaa492b | 353 | let unused = me.confid && me.confid.match(/^unused\d+$/); |
342225bf DC |
354 | |
355 | me.isCreate = me.confid ? unused : true; | |
356 | ||
7aaa492b | 357 | let ipanel = Ext.create('PVE.lxc.MountPointInputPanel', { |
342225bf DC |
358 | confid: me.confid, |
359 | nodename: nodename, | |
360 | unused: unused, | |
361 | unprivileged: me.unprivileged, | |
f6710aac | 362 | isCreate: me.isCreate, |
342225bf DC |
363 | }); |
364 | ||
7aaa492b | 365 | let subject; |
342225bf DC |
366 | if (unused) { |
367 | subject = gettext('Unused Disk'); | |
368 | } else if (me.isCreate) { | |
369 | subject = gettext('Mount Point'); | |
370 | } else { | |
371 | subject = gettext('Mount Point') + ' (' + me.confid + ')'; | |
372 | } | |
373 | ||
374 | Ext.apply(me, { | |
375 | subject: subject, | |
dc683ca0 | 376 | defaultFocus: me.confid !== 'rootfs' ? 'textfield[name=mp]' : 'tool', |
f6710aac | 377 | items: ipanel, |
342225bf DC |
378 | }); |
379 | ||
380 | me.callParent(); | |
381 | ||
382 | me.load({ | |
383 | success: function(response, options) { | |
384 | ipanel.setVMConfig(response.result.data); | |
342225bf | 385 | |
7aaa492b TL |
386 | if (me.confid) { |
387 | let value = response.result.data[me.confid]; | |
388 | let mp = PVE.Parser.parseLxcMountPoint(value); | |
342225bf DC |
389 | if (!mp) { |
390 | Ext.Msg.alert(gettext('Error'), 'Unable to parse mount point options'); | |
391 | me.close(); | |
392 | return; | |
393 | } | |
342225bf DC |
394 | ipanel.setMountPoint(mp); |
395 | me.isValid(); // trigger validation | |
396 | } | |
f6710aac | 397 | }, |
342225bf | 398 | }); |
f6710aac | 399 | }, |
342225bf | 400 | }); |