[PATCH][Kimchi 1/2] Fix issue when clone a vm multiple times

When Kimchi clones a guest it uses the Wok function "get_next_clone_name", which adds an incremental number in the new clone name. This approach causes a race condiction if Kimchi tries to clone a guest multiple times, sending multiple request at once. To avoid this problem, it is better to use timestamps in the clones names instead of incremental numbers. Them it guarantees names will be unique. This patch requires timestamp support in "get_next_clone_name" wok funtion. Signed-off-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> --- model/vms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/model/vms.py b/model/vms.py index 195c879..e60bf51 100644 --- a/model/vms.py +++ b/model/vms.py @@ -318,7 +318,7 @@ class VMModel(object): vms_being_created.append(uri_name) current_vm_names = self.vms.get_list() + vms_being_created - new_name = get_next_clone_name(current_vm_names, name) + new_name = get_next_clone_name(current_vm_names, name, ts=True) # create a task with the actual clone function taskid = add_task(u'/plugins/kimchi/vms/%s/clone' % new_name, -- 2.1.0

This patch provides the support to clone a guest multiple times. User will be asked to provide the number of clone he/she wants, then UI is going to send that many requests to backend. Signed-off-by: Socorro Stoppler <socorro@linux.vnet.ibm.com> Signed-off-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> --- ui/js/src/kimchi.guest_main.js | 58 ++++++++++++++++++++++++++++++++---------- ui/pages/guest-clone.html.tmpl | 47 ++++++++++++++++++++++++++++++++++ ui/pages/i18n.json.tmpl | 4 ++- 3 files changed, 95 insertions(+), 14 deletions(-) create mode 100644 ui/pages/guest-clone.html.tmpl diff --git a/ui/js/src/kimchi.guest_main.js b/ui/js/src/kimchi.guest_main.js index 2542a63..e45f439 100644 --- a/ui/js/src/kimchi.guest_main.js +++ b/ui/js/src/kimchi.guest_main.js @@ -240,6 +240,14 @@ kimchi.vmmigrate = function(event) { wok.window.open('plugins/kimchi/guest-migration.html'); }; +kimchi.vmclone = function(event) { + var button = event.target; + var vm = $(button).closest('li[name=guest]'); + var vm_id = $(vm).attr("id"); + kimchi.selectedGuest = vm_id; + wok.window.open('plugins/kimchi/guest-clone.html'); +}; + kimchi.openVmSerialConsole = function(event) { var button = event.target; var vm = $(button).closest('li[name=guest]'); @@ -294,6 +302,18 @@ kimchi.resetGuestFilter = function() { } }; + +kimchi.initClone = function() { + var numTimesToClone = $('#numberClone').val(); + for (var i = 0; i < numTimesToClone; i++) { + kimchi.cloneGuest(kimchi.selectedGuest, function(data) { + kimchi.listVmsAuto(); + }); + } + wok.window.close(); +}; + + kimchi.listVmsAuto = function() { //Check if the actions button is opened or not, @@ -333,8 +353,8 @@ kimchi.listVmsAuto = function() { })); if (kimchi.trackingTasks.indexOf(tasks[i].id) == -1) kimchi.trackTask(tasks[i].id, null, function(err) { - wok.message.error(err.message); - }, null); + wok.message.error(err.message); + }, null); } }, null, true); return guests; @@ -752,17 +772,7 @@ kimchi.createGuestLi = function(vmObject, prevScreenImage, openMenu) { }); guestActions.find("[name=vm-clone]").on("click", function(event) { event.preventDefault(); - var guest = $(this).closest('li[name=guest]').attr("id"); - wok.confirm({ - title: i18n['KCHAPI6006M'], - content: i18n['KCHVM6010M'], - confirm: i18n['KCHAPI6002M'], - cancel: i18n['KCHAPI6003M'] - }, function() { - kimchi.cloneGuest(guest, function(data) { - kimchi.listVmsAuto(); - }); - }, null); + kimchi.vmclone(event); }); guestActions.find("[name=vm-migrate]").on('click', function(event) { event.preventDefault(); @@ -819,6 +829,28 @@ kimchi.guest_main = function() { kimchi.listVmsAuto(); }; + +kimchi.guest_clonevm_main = function() { + kimchi.initCloneDialog(); +}; + +kimchi.initCloneDialog = function(callback) { + $("#cloneFormOk").on("click", function() { + //Check if input is a number + var numClone = parseInt($('#numberClone').val()); + var err = ""; + if (isNaN(numClone)) { + err = i18n['KCHVM0001E']; + wok.message.error(err,'#alert-modal-container'); + } else { + $("#cloneFormOk").prop("disabled", true); + kimchi.initClone(); + } + }); +}; + + + kimchi.editTemplate = function(guestTemplate, oldPopStat) { if (oldPopStat) { return guestTemplate.replace("vm-action", "vm-action open"); diff --git a/ui/pages/guest-clone.html.tmpl b/ui/pages/guest-clone.html.tmpl new file mode 100644 index 0000000..7023dbc --- /dev/null +++ b/ui/pages/guest-clone.html.tmpl @@ -0,0 +1,47 @@ +#* + * Project Kimchi + * + * Copyright IBM, Corp. 2016 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *# +#unicode UTF-8 +#import gettext +#from wok.cachebust import href +#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) +#silent _ = t.gettext +#silent _t = t.gettext +<!DOCTYPE html> +<html> +<body> + <div id="clone-guest-window" class="window modal-content"> + <div class="modal-header"> + <h4 class="modal-title" id="cloneModalLabel">$_("Clone a Guest")</h4> + </div> + <div id="cloneInfo" class="modal-body"> + <span id="alert-modal-container"></span> + <div class="alert alert-warning" role="alert">$_("When the target guest has SCSI or iSCSI volumes, they will be cloned on the default storage pool. The same will happen when the target pool does not have enough space to clone the volumes. Do you want to continue?")</div> + <div class="form-group"> + <label for="numberClone">$_("Number of times to clone")</label> + <input type="number" class="form-control" id="numberClone" min="1" /> + </div> + <div class="modal-footer"> + <button type="submit" id="cloneFormOk" class="btn btn-default">$_("Continue")</button> + <button type="button" id="cloneFormCancel" data-dismiss="modal" class="btn btn-default">$_("Cancel")</button> + </div> + </div> + <script> + kimchi.guest_clonevm_main(); + </script> +</body> +</html> diff --git a/ui/pages/i18n.json.tmpl b/ui/pages/i18n.json.tmpl index 34a44ab..b88f725 100644 --- a/ui/pages/i18n.json.tmpl +++ b/ui/pages/i18n.json.tmpl @@ -64,7 +64,9 @@ "KCHVM6007M": "$_("Note the guest OS may ignore this request. Would you like to continue?")", "KCHVM6008M": "$_("Virtual Machine delete Confirmation")", "KCHVM6009M": "$_("This virtual machine is not persistent. Power Off will delete it. Continue?")", - "KCHVM6010M": "$_("When the target guest has SCSI or iSCSI volumes, they will be cloned on default storage pool. The same will happen when the target pool does not have enough space to clone the volumes. Do you want to continue?")", + "KCHVM6010M": "$_("When the target guest has SCSI or iSCSI volumes, they will be cloned on the default storage pool. The same will happen when the target pool does not have enough space to clone the volumes. Do you want to continue?")", + + "KCHVM0001E": "$_("Input is not a number")", "KCHVMCD6001M": "$_("This CDROM will be detached permanently and you can re-attach it. Continue to detach it?")", "KCHVMCD6003M": "$_("Attaching...")", -- 2.1.0

Tested-by: Socorro Stoppler <socorro@linux.vnet.ibm.com> On 03/14/2016 11:20 AM, Rodrigo Trujillo wrote:
This patch provides the support to clone a guest multiple times. User will be asked to provide the number of clone he/she wants, then UI is going to send that many requests to backend.
Signed-off-by: Socorro Stoppler <socorro@linux.vnet.ibm.com> Signed-off-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> --- ui/js/src/kimchi.guest_main.js | 58 ++++++++++++++++++++++++++++++++---------- ui/pages/guest-clone.html.tmpl | 47 ++++++++++++++++++++++++++++++++++ ui/pages/i18n.json.tmpl | 4 ++- 3 files changed, 95 insertions(+), 14 deletions(-) create mode 100644 ui/pages/guest-clone.html.tmpl
diff --git a/ui/js/src/kimchi.guest_main.js b/ui/js/src/kimchi.guest_main.js index 2542a63..e45f439 100644 --- a/ui/js/src/kimchi.guest_main.js +++ b/ui/js/src/kimchi.guest_main.js @@ -240,6 +240,14 @@ kimchi.vmmigrate = function(event) { wok.window.open('plugins/kimchi/guest-migration.html'); };
+kimchi.vmclone = function(event) { + var button = event.target; + var vm = $(button).closest('li[name=guest]'); + var vm_id = $(vm).attr("id"); + kimchi.selectedGuest = vm_id; + wok.window.open('plugins/kimchi/guest-clone.html'); +}; + kimchi.openVmSerialConsole = function(event) { var button = event.target; var vm = $(button).closest('li[name=guest]'); @@ -294,6 +302,18 @@ kimchi.resetGuestFilter = function() { } };
+ +kimchi.initClone = function() { + var numTimesToClone = $('#numberClone').val(); + for (var i = 0; i < numTimesToClone; i++) { + kimchi.cloneGuest(kimchi.selectedGuest, function(data) { + kimchi.listVmsAuto(); + }); + } + wok.window.close(); +}; + + kimchi.listVmsAuto = function() {
//Check if the actions button is opened or not, @@ -333,8 +353,8 @@ kimchi.listVmsAuto = function() { })); if (kimchi.trackingTasks.indexOf(tasks[i].id) == -1) kimchi.trackTask(tasks[i].id, null, function(err) { - wok.message.error(err.message); - }, null); + wok.message.error(err.message); + }, null); } }, null, true); return guests; @@ -752,17 +772,7 @@ kimchi.createGuestLi = function(vmObject, prevScreenImage, openMenu) { }); guestActions.find("[name=vm-clone]").on("click", function(event) { event.preventDefault(); - var guest = $(this).closest('li[name=guest]').attr("id"); - wok.confirm({ - title: i18n['KCHAPI6006M'], - content: i18n['KCHVM6010M'], - confirm: i18n['KCHAPI6002M'], - cancel: i18n['KCHAPI6003M'] - }, function() { - kimchi.cloneGuest(guest, function(data) { - kimchi.listVmsAuto(); - }); - }, null); + kimchi.vmclone(event); }); guestActions.find("[name=vm-migrate]").on('click', function(event) { event.preventDefault(); @@ -819,6 +829,28 @@ kimchi.guest_main = function() { kimchi.listVmsAuto(); };
+ +kimchi.guest_clonevm_main = function() { + kimchi.initCloneDialog(); +}; + +kimchi.initCloneDialog = function(callback) { + $("#cloneFormOk").on("click", function() { + //Check if input is a number + var numClone = parseInt($('#numberClone').val()); + var err = ""; + if (isNaN(numClone)) { + err = i18n['KCHVM0001E']; + wok.message.error(err,'#alert-modal-container'); + } else { + $("#cloneFormOk").prop("disabled", true); + kimchi.initClone(); + } + }); +}; + + + kimchi.editTemplate = function(guestTemplate, oldPopStat) { if (oldPopStat) { return guestTemplate.replace("vm-action", "vm-action open"); diff --git a/ui/pages/guest-clone.html.tmpl b/ui/pages/guest-clone.html.tmpl new file mode 100644 index 0000000..7023dbc --- /dev/null +++ b/ui/pages/guest-clone.html.tmpl @@ -0,0 +1,47 @@ +#* + * Project Kimchi + * + * Copyright IBM, Corp. 2016 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *# +#unicode UTF-8 +#import gettext +#from wok.cachebust import href +#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) +#silent _ = t.gettext +#silent _t = t.gettext +<!DOCTYPE html> +<html> +<body> + <div id="clone-guest-window" class="window modal-content"> + <div class="modal-header"> + <h4 class="modal-title" id="cloneModalLabel">$_("Clone a Guest")</h4> + </div> + <div id="cloneInfo" class="modal-body"> + <span id="alert-modal-container"></span> + <div class="alert alert-warning" role="alert">$_("When the target guest has SCSI or iSCSI volumes, they will be cloned on the default storage pool. The same will happen when the target pool does not have enough space to clone the volumes. Do you want to continue?")</div> + <div class="form-group"> + <label for="numberClone">$_("Number of times to clone")</label> + <input type="number" class="form-control" id="numberClone" min="1" /> + </div> + <div class="modal-footer"> + <button type="submit" id="cloneFormOk" class="btn btn-default">$_("Continue")</button> + <button type="button" id="cloneFormCancel" data-dismiss="modal" class="btn btn-default">$_("Cancel")</button> + </div> + </div> + <script> + kimchi.guest_clonevm_main(); + </script> +</body> +</html> diff --git a/ui/pages/i18n.json.tmpl b/ui/pages/i18n.json.tmpl index 34a44ab..b88f725 100644 --- a/ui/pages/i18n.json.tmpl +++ b/ui/pages/i18n.json.tmpl @@ -64,7 +64,9 @@ "KCHVM6007M": "$_("Note the guest OS may ignore this request. Would you like to continue?")", "KCHVM6008M": "$_("Virtual Machine delete Confirmation")", "KCHVM6009M": "$_("This virtual machine is not persistent. Power Off will delete it. Continue?")", - "KCHVM6010M": "$_("When the target guest has SCSI or iSCSI volumes, they will be cloned on default storage pool. The same will happen when the target pool does not have enough space to clone the volumes. Do you want to continue?")", + "KCHVM6010M": "$_("When the target guest has SCSI or iSCSI volumes, they will be cloned on the default storage pool. The same will happen when the target pool does not have enough space to clone the volumes. Do you want to continue?")", + + "KCHVM0001E": "$_("Input is not a number")",
"KCHVMCD6001M": "$_("This CDROM will be detached permanently and you can re-attach it. Continue to detach it?")", "KCHVMCD6003M": "$_("Attaching...")",

Please ignore, will send a V2 On 03/14/2016 03:20 PM, Rodrigo Trujillo wrote:
When Kimchi clones a guest it uses the Wok function "get_next_clone_name", which adds an incremental number in the new clone name. This approach causes a race condiction if Kimchi tries to clone a guest multiple times, sending multiple request at once. To avoid this problem, it is better to use timestamps in the clones names instead of incremental numbers. Them it guarantees names will be unique.
This patch requires timestamp support in "get_next_clone_name" wok funtion.
Signed-off-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> --- model/vms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/model/vms.py b/model/vms.py index 195c879..e60bf51 100644 --- a/model/vms.py +++ b/model/vms.py @@ -318,7 +318,7 @@ class VMModel(object): vms_being_created.append(uri_name)
current_vm_names = self.vms.get_list() + vms_being_created - new_name = get_next_clone_name(current_vm_names, name) + new_name = get_next_clone_name(current_vm_names, name, ts=True)
# create a task with the actual clone function taskid = add_task(u'/plugins/kimchi/vms/%s/clone' % new_name,
participants (2)
-
Rodrigo Trujillo
-
Socorro Stoppler