]>
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 | ||
78 | setVMConfig: 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); |
34c235be | 83 | |
7aaa492b TL |
84 | PVE.Utils.forEachMP((bus, i) => { |
85 | let name = "mp" + i.toString(); | |
34c235be | 86 | if (!Ext.isDefined(vmconfig[name])) { |
85e6b368 | 87 | me.down('field[name=mpid]').setValue(i); |
34c235be | 88 | return false; |
342225bf | 89 | } |
7aaa492b | 90 | return undefined; |
34c235be | 91 | }); |
342225bf DC |
92 | }, |
93 | ||
94 | setNodename: function(nodename) { | |
7aaa492b TL |
95 | let me = this; |
96 | let vm = me.getViewModel(); | |
34c235be | 97 | vm.set('node', nodename); |
34c235be | 98 | me.down('#diskstorage').setNodename(nodename); |
342225bf DC |
99 | }, |
100 | ||
8058410f | 101 | controller: { |
34c235be | 102 | xclass: 'Ext.app.ViewController', |
342225bf | 103 | |
34c235be | 104 | control: { |
85e6b368 | 105 | 'field[name=mpid]': { |
34c235be DC |
106 | change: function(field, value) { |
107 | field.validate(); | |
f6710aac | 108 | }, |
34c235be DC |
109 | }, |
110 | '#hdstorage': { | |
111 | change: function(field, newValue) { | |
7aaa492b | 112 | let me = this; |
34c235be | 113 | if (!newValue) { |
342225bf DC |
114 | return; |
115 | } | |
34c235be | 116 | |
7aaa492b | 117 | let rec = field.store.getById(newValue); |
34c235be DC |
118 | if (!rec) { |
119 | return; | |
342225bf | 120 | } |
7aaa492b | 121 | me.getViewModel().set('type', rec.data.type); |
f6710aac TL |
122 | }, |
123 | }, | |
34c235be | 124 | }, |
34c235be | 125 | init: function(view) { |
7aaa492b TL |
126 | let me = this; |
127 | let vm = this.getViewModel(); | |
f9b63366 | 128 | view.mp = {}; |
34c235be DC |
129 | vm.set('confid', view.confid); |
130 | vm.set('unused', view.unused); | |
131 | vm.set('node', view.nodename); | |
132 | vm.set('unpriv', view.unprivileged); | |
133 | vm.set('hideStorSelector', view.unused || !view.isCreate); | |
2b4c02c0 | 134 | |
7aaa492b | 135 | if (view.isCreate) { // can be array if created from unused disk |
2b4c02c0 | 136 | vm.set('isIncludedInBackup', true); |
7aaa492b TL |
137 | if (view.insideWizard) { |
138 | view.filterMountOptions(); | |
139 | } | |
2b4c02c0 | 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 | 191 | validator: function(value) { |
46d9a35c DJ |
192 | let view = this.up('inputpanel'); |
193 | if (!view.rendered) { | |
7aaa492b | 194 | return undefined; |
34c235be | 195 | } |
46d9a35c | 196 | if (Ext.isDefined(view.vmconfig["mp"+value])) { |
34c235be DC |
197 | return "Mount point is already in use."; |
198 | } | |
34c235be | 199 | return true; |
f6710aac | 200 | }, |
34c235be DC |
201 | }, |
202 | { | |
234d2e37 | 203 | xtype: 'pveDiskStorageSelector', |
34c235be | 204 | itemId: 'diskstorage', |
342225bf | 205 | storageContent: 'rootdir', |
34c235be | 206 | hidden: true, |
342225bf | 207 | autoSelect: true, |
34c235be | 208 | selectformat: false, |
c6c8e2fc | 209 | defaultSize: 8, |
34c235be DC |
210 | bind: { |
211 | hidden: '{hideStorSelector}', | |
212 | disabled: '{hideStorSelector}', | |
f6710aac TL |
213 | nodename: '{node}', |
214 | }, | |
34c235be DC |
215 | }, |
216 | { | |
217 | xtype: 'textfield', | |
218 | disabled: true, | |
219 | submitValue: false, | |
220 | fieldLabel: gettext('Disk image'), | |
221 | name: 'file', | |
222 | bind: { | |
f6710aac TL |
223 | hidden: '{!hideStorSelector}', |
224 | }, | |
225 | }, | |
34c235be DC |
226 | ], |
227 | ||
228 | column2: [ | |
229 | { | |
230 | xtype: 'textfield', | |
231 | name: 'mp', | |
232 | value: '', | |
8058410f | 233 | emptyText: gettext('/some/path'), |
34c235be | 234 | allowBlank: false, |
6c442961 | 235 | disabled: true, |
34c235be DC |
236 | fieldLabel: gettext('Path'), |
237 | bind: { | |
238 | hidden: '{isRoot}', | |
f6710aac TL |
239 | disabled: '{isRoot}', |
240 | }, | |
34c235be DC |
241 | }, |
242 | { | |
243 | xtype: 'proxmoxcheckbox', | |
244 | name: 'backup', | |
0bead056 TL |
245 | fieldLabel: gettext('Backup'), |
246 | autoEl: { | |
247 | tag: 'div', | |
248 | 'data-qtip': gettext('Include volume in backup job'), | |
249 | }, | |
34c235be DC |
250 | bind: { |
251 | hidden: '{isRoot}', | |
2b4c02c0 | 252 | disabled: '{isBindOrRoot}', |
f6710aac TL |
253 | value: '{isIncludedInBackup}', |
254 | }, | |
255 | }, | |
34c235be | 256 | ], |
342225bf | 257 | |
34c235be DC |
258 | advancedColumn1: [ |
259 | { | |
260 | xtype: 'proxmoxcheckbox', | |
342225bf DC |
261 | name: 'quota', |
262 | defaultValue: 0, | |
34c235be | 263 | bind: { |
f6710aac | 264 | disabled: '{!quota}', |
34c235be | 265 | }, |
658bf725 TL |
266 | fieldLabel: gettext('Enable quota'), |
267 | listeners: { | |
268 | disable: function() { | |
269 | this.reset(); | |
f6710aac TL |
270 | }, |
271 | }, | |
34c235be DC |
272 | }, |
273 | { | |
274 | xtype: 'proxmoxcheckbox', | |
275 | name: 'ro', | |
276 | defaultValue: 0, | |
277 | bind: { | |
278 | hidden: '{isRoot}', | |
f6710aac | 279 | disabled: '{isRoot}', |
34c235be | 280 | }, |
f6710aac | 281 | fieldLabel: gettext('Read-only'), |
7b6c7881 TL |
282 | }, |
283 | { | |
284 | xtype: 'proxmoxKVComboBox', | |
285 | name: 'mountoptions', | |
286 | fieldLabel: gettext('Mount options'), | |
287 | deleteEmpty: false, | |
288 | comboItems: [ | |
289 | ['noatime', 'noatime'], | |
290 | ['nodev', 'nodev'], | |
291 | ['noexec', 'noexec'], | |
f6710aac | 292 | ['nosuid', 'nosuid'], |
7b6c7881 TL |
293 | ], |
294 | multiSelect: true, | |
295 | value: [], | |
f6710aac | 296 | allowBlank: true, |
7b6c7881 | 297 | }, |
34c235be | 298 | ], |
342225bf | 299 | |
34c235be DC |
300 | advancedColumn2: [ |
301 | { | |
302 | xtype: 'proxmoxKVComboBox', | |
303 | name: 'acl', | |
304 | fieldLabel: 'ACLs', | |
305 | deleteEmpty: false, | |
306 | comboItems: [ | |
307 | ['__default__', Proxmox.Utils.defaultText], | |
308 | ['1', Proxmox.Utils.enabledText], | |
f6710aac | 309 | ['0', Proxmox.Utils.disabledText], |
34c235be DC |
310 | ], |
311 | value: '__default__', | |
312 | bind: { | |
f6710aac | 313 | disabled: '{isBind}', |
34c235be | 314 | }, |
f6710aac | 315 | allowBlank: true, |
34c235be DC |
316 | }, |
317 | { | |
318 | xtype: 'proxmoxcheckbox', | |
319 | inputValue: '0', // reverses the logic | |
320 | name: 'replicate', | |
f6710aac TL |
321 | fieldLabel: gettext('Skip replication'), |
322 | }, | |
323 | ], | |
342225bf DC |
324 | }); |
325 | ||
326 | Ext.define('PVE.lxc.MountPointEdit', { | |
9fccc702 | 327 | extend: 'Proxmox.window.Edit', |
342225bf DC |
328 | |
329 | unprivileged: false, | |
330 | ||
8058410f | 331 | initComponent: function() { |
7aaa492b | 332 | let me = this; |
342225bf | 333 | |
7aaa492b | 334 | let nodename = me.pveSelNode.data.node; |
342225bf DC |
335 | if (!nodename) { |
336 | throw "no node name specified"; | |
337 | } | |
338 | ||
7aaa492b | 339 | let unused = me.confid && me.confid.match(/^unused\d+$/); |
342225bf DC |
340 | |
341 | me.isCreate = me.confid ? unused : true; | |
342 | ||
7aaa492b | 343 | let ipanel = Ext.create('PVE.lxc.MountPointInputPanel', { |
342225bf DC |
344 | confid: me.confid, |
345 | nodename: nodename, | |
346 | unused: unused, | |
347 | unprivileged: me.unprivileged, | |
f6710aac | 348 | isCreate: me.isCreate, |
342225bf DC |
349 | }); |
350 | ||
7aaa492b | 351 | let subject; |
342225bf DC |
352 | if (unused) { |
353 | subject = gettext('Unused Disk'); | |
354 | } else if (me.isCreate) { | |
355 | subject = gettext('Mount Point'); | |
356 | } else { | |
357 | subject = gettext('Mount Point') + ' (' + me.confid + ')'; | |
358 | } | |
359 | ||
360 | Ext.apply(me, { | |
361 | subject: subject, | |
dc683ca0 | 362 | defaultFocus: me.confid !== 'rootfs' ? 'textfield[name=mp]' : 'tool', |
f6710aac | 363 | items: ipanel, |
342225bf DC |
364 | }); |
365 | ||
366 | me.callParent(); | |
367 | ||
368 | me.load({ | |
369 | success: function(response, options) { | |
370 | ipanel.setVMConfig(response.result.data); | |
342225bf | 371 | |
7aaa492b TL |
372 | if (me.confid) { |
373 | let value = response.result.data[me.confid]; | |
374 | let mp = PVE.Parser.parseLxcMountPoint(value); | |
342225bf DC |
375 | if (!mp) { |
376 | Ext.Msg.alert(gettext('Error'), 'Unable to parse mount point options'); | |
377 | me.close(); | |
378 | return; | |
379 | } | |
342225bf DC |
380 | ipanel.setMountPoint(mp); |
381 | me.isValid(); // trigger validation | |
382 | } | |
f6710aac | 383 | }, |
342225bf | 384 | }); |
f6710aac | 385 | }, |
342225bf | 386 | }); |