]>
Commit | Line | Data |
---|---|---|
09358a73 DM |
1 | Ext.define('PVE.lxc.CreateWizard', { |
2 | extend: 'PVE.window.Wizard', | |
7adbc4a4 | 3 | mixins: ['Proxmox.Mixin.CBind'], |
09358a73 | 4 | |
7adbc4a4 TL |
5 | viewModel: { |
6 | data: { | |
7 | nodename: '', | |
8 | storage: '', | |
f6710aac TL |
9 | unprivileged: true, |
10 | }, | |
7adbc4a4 | 11 | }, |
b1339314 | 12 | |
7adbc4a4 | 13 | cbindData: { |
f6710aac | 14 | nodename: undefined, |
7adbc4a4 | 15 | }, |
b1339314 | 16 | |
7adbc4a4 | 17 | subject: gettext('LXC Container'), |
b1339314 | 18 | |
7adbc4a4 TL |
19 | items: [ |
20 | { | |
21 | xtype: 'inputpanel', | |
22 | title: gettext('General'), | |
23 | onlineHelp: 'pct_general', | |
24 | column1: [ | |
09358a73 | 25 | { |
7adbc4a4 TL |
26 | xtype: 'pveNodeSelector', |
27 | name: 'nodename', | |
28 | cbind: { | |
29 | selectCurNode: '{!nodename}', | |
f6710aac | 30 | preferredValue: '{nodename}', |
7adbc4a4 TL |
31 | }, |
32 | bind: { | |
f6710aac | 33 | value: '{nodename}', |
7adbc4a4 TL |
34 | }, |
35 | fieldLabel: gettext('Node'), | |
36 | allowBlank: false, | |
f6710aac | 37 | onlineValidator: true, |
7adbc4a4 TL |
38 | }, |
39 | { | |
40 | xtype: 'pveGuestIDSelector', | |
41 | name: 'vmid', // backend only knows vmid | |
42 | guestType: 'lxc', | |
43 | value: '', | |
44 | loadNextFreeID: true, | |
f6710aac | 45 | validateExists: false, |
09358a73 DM |
46 | }, |
47 | { | |
7adbc4a4 TL |
48 | xtype: 'proxmoxtextfield', |
49 | name: 'hostname', | |
50 | vtype: 'DnsName', | |
51 | value: '', | |
52 | fieldLabel: gettext('Hostname'), | |
53 | skipEmptyText: true, | |
f6710aac | 54 | allowBlank: true, |
09358a73 | 55 | }, |
09358a73 | 56 | { |
7adbc4a4 TL |
57 | xtype: 'proxmoxcheckbox', |
58 | name: 'unprivileged', | |
02307282 | 59 | value: true, |
7adbc4a4 | 60 | bind: { |
f6710aac | 61 | value: '{unprivileged}', |
7adbc4a4 | 62 | }, |
f6710aac TL |
63 | fieldLabel: gettext('Unprivileged container'), |
64 | }, | |
75b0b132 DC |
65 | { |
66 | xtype: 'proxmoxcheckbox', | |
67 | name: 'features', | |
68 | inputValue: 'nesting=1', | |
69 | value: true, | |
70 | bind: { | |
71 | disabled: '{!unprivileged}', | |
72 | }, | |
73 | fieldLabel: gettext('Nesting'), | |
74 | }, | |
7adbc4a4 TL |
75 | ], |
76 | column2: [ | |
77 | { | |
78 | xtype: 'pvePoolSelector', | |
79 | fieldLabel: gettext('Resource Pool'), | |
80 | name: 'pool', | |
7adbc4a4 | 81 | value: '', |
f6710aac | 82 | allowBlank: true, |
09358a73 DM |
83 | }, |
84 | { | |
7adbc4a4 TL |
85 | xtype: 'textfield', |
86 | inputType: 'password', | |
87 | name: 'password', | |
88 | value: '', | |
89 | fieldLabel: gettext('Password'), | |
90 | allowBlank: false, | |
91 | minLength: 5, | |
92 | change: function(f, value) { | |
93 | if (f.rendered) { | |
94 | f.up().down('field[name=confirmpw]').validate(); | |
95 | } | |
f6710aac | 96 | }, |
09358a73 | 97 | }, |
09358a73 | 98 | { |
7adbc4a4 TL |
99 | xtype: 'textfield', |
100 | inputType: 'password', | |
101 | name: 'confirmpw', | |
102 | value: '', | |
103 | fieldLabel: gettext('Confirm password'), | |
104 | allowBlank: true, | |
105 | submitValue: false, | |
106 | validator: function(value) { | |
107 | var pw = this.up().down('field[name=password]').getValue(); | |
108 | if (pw !== value) { | |
109 | return "Passwords do not match!"; | |
110 | } | |
111 | return true; | |
f6710aac | 112 | }, |
09358a73 DM |
113 | }, |
114 | { | |
7adbc4a4 TL |
115 | xtype: 'proxmoxtextfield', |
116 | name: 'ssh-public-keys', | |
117 | value: '', | |
118 | fieldLabel: gettext('SSH public key'), | |
119 | allowBlank: true, | |
120 | validator: function(value) { | |
4fd034b1 | 121 | let pwfield = this.up().down('field[name=password]'); |
7adbc4a4 | 122 | if (value.length) { |
4fd034b1 | 123 | let key = PVE.Parser.parseSSHKey(value); |
7adbc4a4 TL |
124 | if (!key) { |
125 | return "Failed to recognize ssh key"; | |
126 | } | |
127 | pwfield.allowBlank = true; | |
128 | } else { | |
129 | pwfield.allowBlank = false; | |
130 | } | |
131 | pwfield.validate(); | |
132 | return true; | |
133 | }, | |
134 | afterRender: function() { | |
135 | if (!window.FileReader) { | |
4fd034b1 | 136 | return; // No FileReader support in this browser |
09358a73 | 137 | } |
4fd034b1 | 138 | let cancelEvent = ev => { |
7adbc4a4 TL |
139 | ev = ev.event; |
140 | if (ev.preventDefault) { | |
141 | ev.preventDefault(); | |
142 | } | |
143 | }; | |
4fd034b1 TL |
144 | this.inputEl.on('dragover', cancelEvent); |
145 | this.inputEl.on('dragenter', cancelEvent); | |
146 | this.inputEl.on('drop', ev => { | |
147 | cancelEvent(ev); | |
148 | let files = ev.event.dataTransfer.files; | |
149 | PVE.Utils.loadSSHKeyFromFile(files[0], v => this.setValue(v)); | |
7adbc4a4 | 150 | }); |
f6710aac | 151 | }, |
7adbc4a4 TL |
152 | }, |
153 | { | |
154 | xtype: 'filebutton', | |
155 | name: 'file', | |
156 | hidden: !window.FileReader, | |
157 | text: gettext('Load SSH Key File'), | |
09358a73 | 158 | listeners: { |
7adbc4a4 TL |
159 | change: function(btn, e, value) { |
160 | e = e.event; | |
4fd034b1 TL |
161 | let field = this.up().down('proxmoxtextfield[name=ssh-public-keys]'); |
162 | PVE.Utils.loadSSHKeyFromFile(e.target.files[0], v => field.setValue(v)); | |
7adbc4a4 | 163 | btn.reset(); |
f6710aac TL |
164 | }, |
165 | }, | |
166 | }, | |
167 | ], | |
7adbc4a4 TL |
168 | }, |
169 | { | |
170 | xtype: 'inputpanel', | |
171 | title: gettext('Template'), | |
172 | onlineHelp: 'pct_container_images', | |
173 | column1: [ | |
174 | { | |
175 | xtype: 'pveStorageSelector', | |
176 | name: 'tmplstorage', | |
177 | fieldLabel: gettext('Storage'), | |
178 | storageContent: 'vztmpl', | |
179 | autoSelect: true, | |
180 | allowBlank: false, | |
181 | bind: { | |
182 | value: '{storage}', | |
f6710aac TL |
183 | nodename: '{nodename}', |
184 | }, | |
7adbc4a4 TL |
185 | }, |
186 | { | |
187 | xtype: 'pveFileSelector', | |
188 | name: 'ostemplate', | |
189 | storageContent: 'vztmpl', | |
190 | fieldLabel: gettext('Template'), | |
191 | bind: { | |
192 | storage: '{storage}', | |
f6710aac | 193 | nodename: '{nodename}', |
7adbc4a4 | 194 | }, |
f6710aac TL |
195 | allowBlank: false, |
196 | }, | |
197 | ], | |
7adbc4a4 TL |
198 | }, |
199 | { | |
af07d3d3 DC |
200 | xtype: 'pveMultiMPPanel', |
201 | title: gettext('Disks'), | |
7adbc4a4 TL |
202 | insideWizard: true, |
203 | isCreate: true, | |
204 | unused: false, | |
f6710aac | 205 | confid: 'rootfs', |
7adbc4a4 TL |
206 | }, |
207 | { | |
208 | xtype: 'pveLxcCPUInputPanel', | |
209 | title: gettext('CPU'), | |
f6710aac | 210 | insideWizard: true, |
7adbc4a4 TL |
211 | }, |
212 | { | |
213 | xtype: 'pveLxcMemoryInputPanel', | |
214 | title: gettext('Memory'), | |
f6710aac | 215 | insideWizard: true, |
7adbc4a4 TL |
216 | }, |
217 | { | |
218 | xtype: 'pveLxcNetworkInputPanel', | |
219 | title: gettext('Network'), | |
220 | insideWizard: true, | |
221 | bind: { | |
f6710aac | 222 | nodename: '{nodename}', |
7adbc4a4 | 223 | }, |
f6710aac | 224 | isCreate: true, |
7adbc4a4 TL |
225 | }, |
226 | { | |
227 | xtype: 'pveLxcDNSInputPanel', | |
228 | title: gettext('DNS'), | |
f6710aac | 229 | insideWizard: true, |
7adbc4a4 TL |
230 | }, |
231 | { | |
232 | title: gettext('Confirm'), | |
233 | layout: 'fit', | |
234 | items: [ | |
235 | { | |
236 | xtype: 'grid', | |
237 | store: { | |
238 | model: 'KeyValue', | |
239 | sorters: [{ | |
8058410f | 240 | property: 'key', |
f6710aac TL |
241 | direction: 'ASC', |
242 | }], | |
09358a73 | 243 | }, |
7adbc4a4 | 244 | columns: [ |
8058410f TL |
245 | { header: 'Key', width: 150, dataIndex: 'key' }, |
246 | { header: 'Value', flex: 1, dataIndex: 'value' }, | |
f6710aac TL |
247 | ], |
248 | }, | |
7adbc4a4 | 249 | ], |
fe3d3afc TL |
250 | dockedItems: [ |
251 | { | |
252 | xtype: 'proxmoxcheckbox', | |
253 | name: 'start', | |
254 | dock: 'bottom', | |
255 | margin: '5 0 0 0', | |
f6710aac TL |
256 | boxLabel: gettext('Start after created'), |
257 | }, | |
fe3d3afc | 258 | ], |
7adbc4a4 TL |
259 | listeners: { |
260 | show: function(panel) { | |
4fd034b1 TL |
261 | let wizard = this.up('window'); |
262 | let kv = wizard.getValues(); | |
263 | let data = []; | |
7adbc4a4 TL |
264 | Ext.Object.each(kv, function(key, value) { |
265 | if (key === 'delete' || key === 'tmplstorage') { // ignore | |
266 | return; | |
267 | } | |
268 | if (key === 'password') { // don't show pw | |
269 | return; | |
270 | } | |
7adbc4a4 TL |
271 | data.push({ key: key, value: value }); |
272 | }); | |
09358a73 | 273 | |
4fd034b1 TL |
274 | let summaryStore = panel.down('grid').getStore(); |
275 | summaryStore.suspendEvents(); | |
276 | summaryStore.removeAll(); | |
277 | summaryStore.add(data); | |
278 | summaryStore.sort(); | |
279 | summaryStore.resumeEvents(); | |
280 | summaryStore.fireEvent('refresh'); | |
f6710aac | 281 | }, |
7adbc4a4 TL |
282 | }, |
283 | onSubmit: function() { | |
4fd034b1 TL |
284 | let wizard = this.up('window'); |
285 | let kv = wizard.getValues(); | |
399ffa76 | 286 | delete kv.delete; |
09358a73 | 287 | |
4fd034b1 | 288 | let nodename = kv.nodename; |
7adbc4a4 TL |
289 | delete kv.nodename; |
290 | delete kv.tmplstorage; | |
b1339314 | 291 | |
4998ae6f AN |
292 | if (!kv.pool.length) { |
293 | delete kv.pool; | |
294 | } | |
7adbc4a4 TL |
295 | if (!kv.password.length && kv['ssh-public-keys']) { |
296 | delete kv.password; | |
297 | } | |
fd776fca | 298 | |
7adbc4a4 | 299 | Proxmox.Utils.API2Request({ |
4fd034b1 | 300 | url: `/nodes/${nodename}/lxc`, |
7adbc4a4 TL |
301 | waitMsgTarget: wizard, |
302 | method: 'POST', | |
303 | params: kv, | |
8058410f | 304 | success: function(response, opts) { |
4fd034b1 TL |
305 | Ext.create('Proxmox.window.TaskViewer', { |
306 | autoShow: true, | |
307 | upid: response.result.data, | |
09358a73 | 308 | }); |
7adbc4a4 TL |
309 | wizard.close(); |
310 | }, | |
4fd034b1 | 311 | failure: (response, opts) => Ext.Msg.alert(gettext('Error'), response.htmlStatus), |
7adbc4a4 | 312 | }); |
f6710aac TL |
313 | }, |
314 | }, | |
315 | ], | |
09358a73 | 316 | }); |