]>
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, | |
5747fef3 | 197 | maxValue: PVE.Utils.mp_counts.mp - 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: [ | |
0ffa230e | 303 | ['lazytime', 'lazytime'], |
7b6c7881 TL |
304 | ['noatime', 'noatime'], |
305 | ['nodev', 'nodev'], | |
306 | ['noexec', 'noexec'], | |
f6710aac | 307 | ['nosuid', 'nosuid'], |
7b6c7881 TL |
308 | ], |
309 | multiSelect: true, | |
310 | value: [], | |
f6710aac | 311 | allowBlank: true, |
7b6c7881 | 312 | }, |
34c235be | 313 | ], |
342225bf | 314 | |
34c235be DC |
315 | advancedColumn2: [ |
316 | { | |
317 | xtype: 'proxmoxKVComboBox', | |
318 | name: 'acl', | |
319 | fieldLabel: 'ACLs', | |
320 | deleteEmpty: false, | |
321 | comboItems: [ | |
322 | ['__default__', Proxmox.Utils.defaultText], | |
323 | ['1', Proxmox.Utils.enabledText], | |
f6710aac | 324 | ['0', Proxmox.Utils.disabledText], |
34c235be DC |
325 | ], |
326 | value: '__default__', | |
327 | bind: { | |
f6710aac | 328 | disabled: '{isBind}', |
34c235be | 329 | }, |
f6710aac | 330 | allowBlank: true, |
34c235be DC |
331 | }, |
332 | { | |
333 | xtype: 'proxmoxcheckbox', | |
334 | inputValue: '0', // reverses the logic | |
335 | name: 'replicate', | |
f6710aac TL |
336 | fieldLabel: gettext('Skip replication'), |
337 | }, | |
338 | ], | |
342225bf DC |
339 | }); |
340 | ||
341 | Ext.define('PVE.lxc.MountPointEdit', { | |
9fccc702 | 342 | extend: 'Proxmox.window.Edit', |
342225bf DC |
343 | |
344 | unprivileged: false, | |
345 | ||
8058410f | 346 | initComponent: function() { |
7aaa492b | 347 | let me = this; |
342225bf | 348 | |
7aaa492b | 349 | let nodename = me.pveSelNode.data.node; |
342225bf DC |
350 | if (!nodename) { |
351 | throw "no node name specified"; | |
352 | } | |
353 | ||
7aaa492b | 354 | let unused = me.confid && me.confid.match(/^unused\d+$/); |
342225bf DC |
355 | |
356 | me.isCreate = me.confid ? unused : true; | |
357 | ||
7aaa492b | 358 | let ipanel = Ext.create('PVE.lxc.MountPointInputPanel', { |
342225bf DC |
359 | confid: me.confid, |
360 | nodename: nodename, | |
361 | unused: unused, | |
362 | unprivileged: me.unprivileged, | |
f6710aac | 363 | isCreate: me.isCreate, |
342225bf DC |
364 | }); |
365 | ||
7aaa492b | 366 | let subject; |
342225bf DC |
367 | if (unused) { |
368 | subject = gettext('Unused Disk'); | |
369 | } else if (me.isCreate) { | |
370 | subject = gettext('Mount Point'); | |
371 | } else { | |
372 | subject = gettext('Mount Point') + ' (' + me.confid + ')'; | |
373 | } | |
374 | ||
375 | Ext.apply(me, { | |
376 | subject: subject, | |
dc683ca0 | 377 | defaultFocus: me.confid !== 'rootfs' ? 'textfield[name=mp]' : 'tool', |
f6710aac | 378 | items: ipanel, |
342225bf DC |
379 | }); |
380 | ||
381 | me.callParent(); | |
382 | ||
383 | me.load({ | |
384 | success: function(response, options) { | |
385 | ipanel.setVMConfig(response.result.data); | |
342225bf | 386 | |
7aaa492b TL |
387 | if (me.confid) { |
388 | let value = response.result.data[me.confid]; | |
389 | let mp = PVE.Parser.parseLxcMountPoint(value); | |
342225bf DC |
390 | if (!mp) { |
391 | Ext.Msg.alert(gettext('Error'), 'Unable to parse mount point options'); | |
392 | me.close(); | |
393 | return; | |
394 | } | |
342225bf DC |
395 | ipanel.setMountPoint(mp); |
396 | me.isValid(); // trigger validation | |
397 | } | |
f6710aac | 398 | }, |
342225bf | 399 | }); |
f6710aac | 400 | }, |
342225bf | 401 | }); |