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