Ext.define('PVE.window.Clone', { extend: 'Ext.window.Window', resizable: false, isTemplate: false, onlineHelp: 'qm_copy_and_clone', controller: { xclass: 'Ext.app.ViewController', control: { 'panel[reference=cloneform]': { validitychange: 'disableSubmit' } }, disableSubmit: function(form) { this.lookupReference('submitBtn').setDisabled(!form.isValid()); } }, statics: { // display a snapshot selector only if needed wrap: function(nodename, vmid, isTemplate) { PVE.Utils.API2Request({ url: '/nodes/' + nodename + '/qemu/' + vmid +'/snapshot', failure: function(response, opts) { Ext.Msg.alert('Error', response.htmlStatus); }, success: function(response, opts) { var snapshotList = response.result.data; var hasSnapshots = snapshotList.length === 1 && snapshotList[0].name === 'current' ? false : true; Ext.create('PVE.window.Clone', { nodename: nodename, vmid: vmid, isTemplate: isTemplate, hasSnapshots: hasSnapshots }).show(); } }); } }, create_clone: function(values) { var me = this; var params = { newid: values.newvmid }; if (values.snapname && values.snapname !== 'current') { params.snapname = values.snapname; } if (values.pool) { params.pool = values.pool; } if (values.name) { params.name = values.name; } if (values.target) { params.target = values.target; } if (values.clonemode === 'copy') { params.full = 1; if (values.storage) { params.storage = values.storage; if (values.diskformat) { params.format = values.diskformat; } } } PVE.Utils.API2Request({ params: params, url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/clone', waitMsgTarget: me, method: 'POST', failure: function(response, opts) { Ext.Msg.alert('Error', response.htmlStatus); }, success: function(response, options) { me.close(); } }); }, // disable the Storage selector when clone mode is linked clone // disable the disk Format selector when // A) clone mode is linked clone // B) clone mode is full clone and storage is block device updateVisibility: function() { var me = this; var storagesel = me.lookupReference('storagesel'); var formatsel = me.lookupReference('formatsel'); var clonemode = me.lookupReference('clonemodesel').getValue(); var storage = storagesel.getValue(); var rec = storagesel.store.getById(storage); storagesel.setDisabled(clonemode === 'clone'); if (!rec || clonemode === 'clone') { formatsel.setDisabled(true); return; } if (rec.data.type === 'lvm' || rec.data.type === 'lvmthin' || rec.data.type === 'rbd' || rec.data.type === 'iscsi' || rec.data.type === 'sheepdog' || rec.data.type === 'zfs' || rec.data.type === 'zfspool' ) { formatsel.setValue('raw'); formatsel.setDisabled(true); } else { formatsel.setValue('qcow2'); formatsel.setDisabled(false); } }, // add to the list of valid nodes each node where // all the VM disks are available verifyFeature: function() { var me = this; var snapname = me.lookupReference('snapshotsel').getValue(); var clonemode = me.lookupReference('clonemodesel').getValue(); var params = { feature: clonemode }; if (snapname !== 'current') { params.snapname = snapname; } PVE.Utils.API2Request({ waitMsgTarget: me, url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/feature', params: params, method: 'GET', failure: function(response, opts) { me.lookupReference('submitBtn').setDisabled(true); Ext.Msg.alert('Error', response.htmlStatus); }, success: function(response, options) { var res = response.result.data; me.lookupReference('targetsel').allowedNodes = res.nodes; me.lookupReference('targetsel').validate(); } }); }, initComponent : function() { var me = this; if (!me.nodename) { throw "no node name specified"; } if (!me.vmid) { throw "no VM ID specified"; } if (!me.snapname) { me.snapname = 'current'; } var titletext = me.isTemplate ? "Template" : "VM"; me.title = "Clone " + titletext + " " + me.vmid; var col1 = []; var col2 = []; col1.push({ xtype: 'pveNodeSelector', name: 'target', reference: 'targetsel', fieldLabel: gettext('Target node'), selectCurNode: true, allowBlank: false, onlineValidator: true, listeners: { change: function(f, value) { me.lookupReference('storagesel').setTargetNode(value); } } }); var modelist = [['copy', gettext('Full Clone')]]; if (me.isTemplate) { modelist.push(['clone', gettext('Linked Clone')]); } col1.push({ xtype: 'pveGuestIDSelector', name: 'newvmid', guestType: 'qemu', value: '', loadNextFreeID: true, validateExists: false }, { xtype: 'textfield', name: 'name', allowBlank: true, fieldLabel: gettext('Name') }, { xtype: 'pvePoolSelector', fieldLabel: gettext('Resource Pool'), name: 'pool', value: '', allowBlank: true } ); col2.push({ xtype: 'pveKVComboBox', fieldLabel: gettext('Mode'), name: 'clonemode', reference: 'clonemodesel', allowBlank: false, hidden: !me.isTemplate, value: me.isTemplate ? 'clone' : 'copy', comboItems: modelist, listeners: { change: function(t, value) { me.updateVisibility(); me.verifyFeature(); } } }, { xtype: 'PVE.form.SnapshotSelector', name: 'snapname', reference: 'snapshotsel', fieldLabel: gettext('Snapshot'), nodename: me.nodename, vmid: me.vmid, hidden: me.isTemplate || !me.hasSnapshots ? true : false, disabled: false, allowBlank: false, value : me.snapname, listeners: { change: function(f, value) { me.verifyFeature(); } } }, { xtype: 'pveStorageSelector', name: 'storage', reference: 'storagesel', nodename: me.nodename, fieldLabel: gettext('Target Storage'), storageContent: 'images', autoSelect: false, // will use for each disk the same storage as source allowBlank: true, emptyText: gettext('Same as source'), disabled: me.isTemplate ? true : false, // because default mode is clone for templates hidden: false, listeners: { change: function(f, value) { me.updateVisibility(); } } }, { xtype: 'pveDiskFormatSelector', name: 'diskformat', reference: 'formatsel', fieldLabel: gettext('Format'), value: 'raw', disabled: true, hidden: false, allowBlank: false }); var formPanel = Ext.create('Ext.form.Panel', { bodyPadding: 10, reference: 'cloneform', border: false, layout: 'column', defaultType: 'container', columns: 2, fieldDefaults: { labelWidth: 100, anchor: '100%' }, items: [ { columnWidth: 0.5, padding: '0 10 0 0', layout: 'anchor', items: col1 }, { columnWidth: 0.5, padding: '0 0 0 10', layout: 'anchor', items: col2 } ] }); Ext.apply(me, { modal: true, width: 600, height: 250, border: false, layout: 'fit', buttons: [ { xtype: 'pveHelpButton', listenToGlobalEvent: false, hidden: false, onlineHelp: me.onlineHelp }, '->', { reference: 'submitBtn', text: gettext('Clone'), disabled: true, handler: function() { var cloneForm = me.lookupReference('cloneform'); if (cloneForm.isValid()) { me.create_clone(cloneForm.getValues()); } } } ], items: [ formPanel ] }); me.callParent(); me.verifyFeature(); } });