]>
Commit | Line | Data |
---|---|---|
f5226cd9 DM |
1 | Ext.define('PVE.window.Clone', { |
2 | extend: 'Ext.window.Window', | |
3 | ||
4 | resizable: false, | |
5 | ||
6 | isTemplate: false, | |
7 | ||
ff79a116 DM |
8 | onlineHelp: 'qm_copy_and_clone', |
9 | ||
26693bb9 EK |
10 | controller: { |
11 | xclass: 'Ext.app.ViewController', | |
12 | control: { | |
13 | 'panel[reference=cloneform]': { | |
14 | validitychange: 'disableSubmit' | |
15 | } | |
16 | }, | |
17 | disableSubmit: function(form) { | |
18 | this.lookupReference('submitBtn').setDisabled(!form.isValid()); | |
19 | } | |
20 | }, | |
21 | ||
4e2b6cc8 EK |
22 | statics: { |
23 | // display a snapshot selector only if needed | |
24 | wrap: function(nodename, vmid, isTemplate) { | |
25 | PVE.Utils.API2Request({ | |
26 | url: '/nodes/' + nodename + '/qemu/' + vmid +'/snapshot', | |
27 | failure: function(response, opts) { | |
28 | Ext.Msg.alert('Error', response.htmlStatus); | |
29 | }, | |
30 | success: function(response, opts) { | |
31 | var snapshotList = response.result.data; | |
32 | var hasSnapshots = snapshotList.length === 1 && | |
33 | snapshotList[0].name === 'current' ? false : true; | |
34 | ||
35 | Ext.create('PVE.window.Clone', { | |
36 | nodename: nodename, | |
37 | vmid: vmid, | |
38 | isTemplate: isTemplate, | |
39 | hasSnapshots: hasSnapshots | |
40 | }).show(); | |
41 | } | |
42 | }); | |
43 | } | |
44 | }, | |
2f3c5c38 | 45 | |
f5226cd9 DM |
46 | create_clone: function(values) { |
47 | var me = this; | |
48 | ||
406ac585 | 49 | var params = { newid: values.newvmid }; |
f5226cd9 | 50 | |
406ac585 EK |
51 | if (values.snapname && values.snapname !== 'current') { |
52 | params.snapname = values.snapname; | |
53 | } | |
f5226cd9 DM |
54 | |
55 | if (values.pool) { | |
56 | params.pool = values.pool; | |
57 | } | |
58 | ||
59 | if (values.name) { | |
60 | params.name = values.name; | |
61 | } | |
62 | ||
63 | if (values.target) { | |
64 | params.target = values.target; | |
65 | } | |
66 | ||
67 | if (values.clonemode === 'copy') { | |
68 | params.full = 1; | |
69 | if (values.storage) { | |
70 | params.storage = values.storage; | |
71 | if (values.diskformat) { | |
72 | params.format = values.diskformat; | |
73 | } | |
74 | } | |
75 | } | |
76 | ||
77 | PVE.Utils.API2Request({ | |
78 | params: params, | |
79 | url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/clone', | |
80 | waitMsgTarget: me, | |
81 | method: 'POST', | |
82 | failure: function(response, opts) { | |
83 | Ext.Msg.alert('Error', response.htmlStatus); | |
84 | }, | |
85 | success: function(response, options) { | |
86 | me.close(); | |
87 | } | |
88 | }); | |
89 | ||
90 | }, | |
91 | ||
44494b4c EK |
92 | // disable the Storage selector when clone mode is linked clone |
93 | // disable the disk Format selector when | |
94 | // A) clone mode is linked clone | |
95 | // B) clone mode is full clone and storage is block device | |
f5226cd9 DM |
96 | updateVisibility: function() { |
97 | var me = this; | |
98 | ||
406ac585 EK |
99 | var storagesel = me.lookupReference('storagesel'); |
100 | var formatsel = me.lookupReference('formatsel'); | |
101 | ||
102 | var clonemode = me.lookupReference('clonemodesel').getValue(); | |
103 | var storage = storagesel.getValue(); | |
104 | var rec = storagesel.store.getById(storage); | |
f5226cd9 | 105 | |
406ac585 | 106 | storagesel.setDisabled(clonemode === 'clone'); |
f5226cd9 DM |
107 | |
108 | if (!rec || clonemode === 'clone') { | |
406ac585 | 109 | formatsel.setDisabled(true); |
f5226cd9 DM |
110 | return; |
111 | } | |
112 | ||
113 | if (rec.data.type === 'lvm' || | |
406ac585 EK |
114 | rec.data.type === 'lvmthin' || |
115 | rec.data.type === 'rbd' || | |
116 | rec.data.type === 'iscsi' || | |
117 | rec.data.type === 'sheepdog' || | |
118 | rec.data.type === 'zfs' || | |
119 | rec.data.type === 'zfspool' | |
120 | ) { | |
121 | formatsel.setValue('raw'); | |
122 | formatsel.setDisabled(true); | |
123 | } else { | |
124 | formatsel.setValue('qcow2'); | |
125 | formatsel.setDisabled(false); | |
126 | } | |
f5226cd9 DM |
127 | }, |
128 | ||
26693bb9 | 129 | // add to the list of valid nodes each node where |
44494b4c | 130 | // all the VM disks are available |
f5226cd9 DM |
131 | verifyFeature: function() { |
132 | var me = this; | |
406ac585 EK |
133 | |
134 | var snapname = me.lookupReference('snapshotsel').getValue(); | |
135 | var clonemode = me.lookupReference('clonemodesel').getValue(); | |
f5226cd9 DM |
136 | |
137 | var params = { feature: clonemode }; | |
138 | if (snapname !== 'current') { | |
139 | params.snapname = snapname; | |
140 | } | |
141 | ||
142 | PVE.Utils.API2Request({ | |
143 | waitMsgTarget: me, | |
144 | url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/feature', | |
145 | params: params, | |
146 | method: 'GET', | |
147 | failure: function(response, opts) { | |
0057ea5c | 148 | me.lookupReference('submitBtn').setDisabled(true); |
f5226cd9 DM |
149 | Ext.Msg.alert('Error', response.htmlStatus); |
150 | }, | |
151 | success: function(response, options) { | |
406ac585 | 152 | var res = response.result.data; |
f5226cd9 | 153 | |
406ac585 EK |
154 | me.lookupReference('targetsel').allowedNodes = res.nodes; |
155 | me.lookupReference('targetsel').validate(); | |
f5226cd9 DM |
156 | } |
157 | }); | |
158 | }, | |
159 | ||
160 | initComponent : function() { | |
f5226cd9 DM |
161 | var me = this; |
162 | ||
163 | if (!me.nodename) { | |
164 | throw "no node name specified"; | |
165 | } | |
166 | ||
167 | if (!me.vmid) { | |
168 | throw "no VM ID specified"; | |
169 | } | |
170 | ||
171 | if (!me.snapname) { | |
172 | me.snapname = 'current'; | |
173 | } | |
174 | ||
406ac585 EK |
175 | var titletext = me.isTemplate ? "Template" : "VM"; |
176 | me.title = "Clone " + titletext + " " + me.vmid; | |
177 | ||
f5226cd9 DM |
178 | var col1 = []; |
179 | var col2 = []; | |
180 | ||
406ac585 EK |
181 | col1.push({ |
182 | xtype: 'pveNodeSelector', | |
f5226cd9 | 183 | name: 'target', |
406ac585 | 184 | reference: 'targetsel', |
f5226cd9 DM |
185 | fieldLabel: gettext('Target node'), |
186 | selectCurNode: true, | |
187 | allowBlank: false, | |
406ac585 EK |
188 | onlineValidator: true, |
189 | listeners: { | |
190 | change: function(f, value) { | |
191 | me.lookupReference('storagesel').setTargetNode(value); | |
192 | } | |
193 | } | |
f5226cd9 DM |
194 | }); |
195 | ||
f5226cd9 DM |
196 | var modelist = [['copy', gettext('Full Clone')]]; |
197 | if (me.isTemplate) { | |
198 | modelist.push(['clone', gettext('Linked Clone')]); | |
199 | } | |
200 | ||
406ac585 EK |
201 | col1.push({ |
202 | xtype: 'pveGuestIDSelector', | |
203 | name: 'newvmid', | |
204 | guestType: 'qemu', | |
205 | value: '', | |
206 | loadNextFreeID: true, | |
207 | validateExists: false | |
208 | }, | |
209 | { | |
210 | xtype: 'textfield', | |
211 | name: 'name', | |
212 | allowBlank: true, | |
213 | fieldLabel: gettext('Name') | |
214 | }, | |
215 | { | |
216 | xtype: 'pvePoolSelector', | |
217 | fieldLabel: gettext('Resource Pool'), | |
218 | name: 'pool', | |
219 | value: '', | |
220 | allowBlank: true | |
221 | } | |
222 | ); | |
f5226cd9 | 223 | |
406ac585 EK |
224 | col2.push({ |
225 | xtype: 'pveKVComboBox', | |
226 | fieldLabel: gettext('Mode'), | |
227 | name: 'clonemode', | |
228 | reference: 'clonemodesel', | |
229 | allowBlank: false, | |
230 | hidden: !me.isTemplate, | |
231 | value: me.isTemplate ? 'clone' : 'copy', | |
232 | comboItems: modelist, | |
233 | listeners: { | |
234 | change: function(t, value) { | |
235 | me.updateVisibility(); | |
236 | me.verifyFeature(); | |
237 | } | |
238 | } | |
239 | }, | |
240 | { | |
241 | xtype: 'PVE.form.SnapshotSelector', | |
f5226cd9 | 242 | name: 'snapname', |
406ac585 | 243 | reference: 'snapshotsel', |
f5226cd9 | 244 | fieldLabel: gettext('Snapshot'), |
406ac585 EK |
245 | nodename: me.nodename, |
246 | vmid: me.vmid, | |
2f3c5c38 | 247 | hidden: me.isTemplate || !me.hasSnapshots ? true : false, |
406ac585 | 248 | disabled: false, |
f5226cd9 DM |
249 | allowBlank: false, |
250 | value : me.snapname, | |
251 | listeners: { | |
252 | change: function(f, value) { | |
253 | me.verifyFeature(); | |
254 | } | |
255 | } | |
406ac585 EK |
256 | }, |
257 | { | |
258 | xtype: 'pveStorageSelector', | |
259 | name: 'storage', | |
260 | reference: 'storagesel', | |
261 | nodename: me.nodename, | |
262 | fieldLabel: gettext('Target Storage'), | |
263 | storageContent: 'images', | |
22c01a44 | 264 | autoSelect: false, // will use for each disk the same storage as source |
406ac585 | 265 | allowBlank: true, |
f4f9e662 | 266 | emptyText: gettext('Same as source'), |
406ac585 | 267 | disabled: me.isTemplate ? true : false, // because default mode is clone for templates |
67cb91e4 EK |
268 | hidden: false, |
269 | listeners: { | |
270 | change: function(f, value) { | |
271 | me.updateVisibility(); | |
272 | } | |
273 | } | |
406ac585 EK |
274 | }, |
275 | { | |
276 | xtype: 'pveDiskFormatSelector', | |
f5226cd9 | 277 | name: 'diskformat', |
406ac585 | 278 | reference: 'formatsel', |
f5226cd9 DM |
279 | fieldLabel: gettext('Format'), |
280 | value: 'raw', | |
406ac585 EK |
281 | disabled: true, |
282 | hidden: false, | |
f5226cd9 DM |
283 | allowBlank: false |
284 | }); | |
285 | ||
406ac585 | 286 | var formPanel = Ext.create('Ext.form.Panel', { |
f5226cd9 | 287 | bodyPadding: 10, |
26693bb9 | 288 | reference: 'cloneform', |
f5226cd9 DM |
289 | border: false, |
290 | layout: 'column', | |
291 | defaultType: 'container', | |
292 | columns: 2, | |
293 | fieldDefaults: { | |
294 | labelWidth: 100, | |
295 | anchor: '100%' | |
296 | }, | |
297 | items: [ | |
298 | { | |
299 | columnWidth: 0.5, | |
300 | padding: '0 10 0 0', | |
301 | layout: 'anchor', | |
302 | items: col1 | |
303 | }, | |
304 | { | |
305 | columnWidth: 0.5, | |
306 | padding: '0 0 0 10', | |
307 | layout: 'anchor', | |
308 | items: col2 | |
309 | } | |
310 | ] | |
311 | }); | |
312 | ||
f5226cd9 DM |
313 | Ext.apply(me, { |
314 | modal: true, | |
315 | width: 600, | |
316 | height: 250, | |
317 | border: false, | |
318 | layout: 'fit', | |
406ac585 EK |
319 | buttons: [ { |
320 | xtype: 'pveHelpButton', | |
321 | listenToGlobalEvent: false, | |
322 | hidden: false, | |
323 | onlineHelp: me.onlineHelp | |
324 | }, | |
325 | '->', | |
326 | { | |
327 | reference: 'submitBtn', | |
328 | text: gettext('Clone'), | |
329 | disabled: true, | |
330 | handler: function() { | |
331 | var cloneForm = me.lookupReference('cloneform'); | |
332 | if (cloneForm.isValid()) { | |
333 | me.create_clone(cloneForm.getValues()); | |
334 | } | |
335 | } | |
336 | } ], | |
337 | items: [ formPanel ] | |
f5226cd9 DM |
338 | }); |
339 | ||
340 | me.callParent(); | |
341 | ||
342 | me.verifyFeature(); | |
343 | } | |
344 | }); |