[PATCH] [Kimchi 0/2] Live Migration v5

From: samhenri <samuel.guimaraes@eldorado.org.br> - Rebased initial checkin for live migration to new-ui; - Added form validation to optional fields (e.g. disable submit button if username is filled but password is empty, added warn classes to form fields); - Fixed error messages in modal window; - Delete VM once Live Migration is finished checkbox is working; Socorro Stoppler (1): Initial checkin for live migration UI support samhenri (1): Live Migration front-end ui/js/src/kimchi.api.js | 3 +- ui/js/src/kimchi.guest_livemigration.js | 145 ++++++++++++++++++++++++++++++++ ui/js/src/kimchi.guest_main.js | 47 +++++++++-- ui/pages/guest-migration.html.tmpl | 67 +++++++++++++++ ui/pages/guest.html.tmpl | 7 +- ui/pages/i18n.json.tmpl | 2 + ui/pages/tabs/guests.html.tmpl | 4 +- 7 files changed, 261 insertions(+), 14 deletions(-) create mode 100644 ui/js/src/kimchi.guest_livemigration.js create mode 100644 ui/pages/guest-migration.html.tmpl -- 1.9.3

From: Socorro Stoppler <socorro@linux.vnet.ibm.com> Signed-off-by: Socorro Stoppler <socorro@linux.vnet.ibm.com> Signed-off-by: samhenri <samuel.guimaraes@eldorado.org.br> --- ui/js/src/kimchi.api.js | 3 +- ui/js/src/kimchi.guest_main.js | 46 +++++++++++++++++++++++++-- ui/pages/guest-migration.html.tmpl | 65 ++++++++++++++++++++++++++++++++++++++ ui/pages/guest.html.tmpl | 7 ++-- 4 files changed, 114 insertions(+), 7 deletions(-) create mode 100644 ui/pages/guest-migration.html.tmpl diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js index 40f9f4f..8f54b28 100644 --- a/ui/js/src/kimchi.api.js +++ b/ui/js/src/kimchi.api.js @@ -1047,12 +1047,13 @@ var kimchi = { }); }, - migrateGuest: function(vm, suc, err) { + migrateGuest: function(vm, data, suc, err) { wok.requestJSON({ url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + "/migrate", type : 'POST', contentType : 'application/json', dataType : 'json', + data : JSON.stringify(data), success : suc, error : err ? err : function(data) { wok.message.error(data.responseJSON.reason); diff --git a/ui/js/src/kimchi.guest_main.js b/ui/js/src/kimchi.guest_main.js index 257d76e..2d3ccf3 100644 --- a/ui/js/src/kimchi.guest_main.js +++ b/ui/js/src/kimchi.guest_main.js @@ -326,8 +326,24 @@ kimchi.listVmsAuto = function() { }, null, true); return guests; }; + var getMigratingGuests = function(){ + var guests = []; + kimchi.getTasksByFilter('status=running&target_uri='+encodeURIComponent('^/vms/.+/migrate'), function(tasks) { + for(var i=0;i<tasks.length;i++){ + var guestUri = tasks[i].target_uri; + var guestName = guestUri.split('/')[4] + guests.push($.extend({}, kimchi.sampleGuestObject, {name: guestName, isMigrating: true})); + if(kimchi.trackingTasks.indexOf(tasks[i].id)==-1) + kimchi.trackTask(tasks[i].id, null, function(err){ + wok.message.error(err.message); + }, null); + } + }, null, true); + return guests; + }; kimchi.listVMs(function(result, textStatus, jqXHR) { if (result && textStatus == "success") { + result = getMigratingGuests().concat(result); result = getCloningGuests().concat(result); result = getCreatingGuests().concat(result); if (result.length) { @@ -385,6 +401,26 @@ kimchi.listVmsAuto = function() { kimchi.createGuestLi = function(vmObject, prevScreenImage, openMenu) { var result = kimchi.guestElem.clone(); + var initializeMigratePanel = function() { + $("#migrateFormOk").on("click", function() { + //TODO: Get values from UI for remote_host, user, password + var data = { + "remote_host" : "ltc-hab1.aus.stglabs.ibm.com", + "user" : "root", + "password" : "passw0rd" + }; + //TODO: Need to get guest to be passed in here + kimchi.migrateGuest(guest, data, function(){ + kimchi.listVmsAuto(); + wok.window.close(); + }, function(err) { + wok.message.error(err.responseJSON.reason); + }); + }); + } + + initializeMigratePanel(); + //Setup the VM list entry var currentState = result.find('.guest-state'); var vmRunningBool = (vmObject.state == "running"); @@ -595,7 +631,7 @@ kimchi.createGuestLi = function(vmObject, prevScreenImage, openMenu) { result.addClass('inactive'); result.find('.distro-icon').addClass('inactive'); result.find('.vnc-link').css("display", "none"); - result.find('.column-vnc').html('--'); + result.find('.column-vnc').html('--'); //Hide PowerOff guestActions.find(".shutoff-hidden").hide(); //Hide Pause @@ -630,7 +666,7 @@ kimchi.createGuestLi = function(vmObject, prevScreenImage, openMenu) { } //Setup action event handlers - if (!(vmObject.isCloning || vmObject.isCreating)) { + if(!(vmObject.isCloning || vmObject.isCreating || vmObject.isMigrating)){ guestActions.find("[name=vm-start]").on("click", function(event) { event.preventDefault(); @@ -689,12 +725,18 @@ kimchi.createGuestLi = function(vmObject, prevScreenImage, openMenu) { }); }, null); }); + guestActions.find("[name=vm-migrate]").click(function(){ + var guest = $(this).closest('li[name=guest]').attr("id"); + wok.window.open('plugins/kimchi/guest-migration.html'); + }); } else { guestActions.find('.btn').attr('disabled', true); result.find('.guest-pending').removeClass('hide-content'); pendingText = result.find('.guest-pending .text') if (vmObject.isCloning) pendingText.text(i18n['KCHAPI6009M']); + else if(vmObject.isMigrating) + pendingText.text("Migrating"); else pendingText.text(i18n['KCHAPI6008M']); } diff --git a/ui/pages/guest-migration.html.tmpl b/ui/pages/guest-migration.html.tmpl new file mode 100644 index 0000000..278d22c --- /dev/null +++ b/ui/pages/guest-migration.html.tmpl @@ -0,0 +1,65 @@ +#* + * Project Kimchi + * + * Copyright IBM, Corp. 2015 + * + * 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 +<div id="migrate-guest-window" class="window modal-content"> + <div class="modal-header"> + <h4 class="modal-title" id="migrateModalLabel">$_("Migrate a Guest")</h4> + </div> + <div id="migrateInfo" class="modal-body"> + <div class="alert alert-warning" role="alert">Disclaimer: This process cannot be stopped after started, + can take a long time to complete and will turn off the VM on this Hypervisor when it is successfully + migrated to the remote destination. + </div> + <div class="form-group"> + <label for="remoteHostName">$_("Remote Server")</label> + <input type="text" class="form-control" id="remoteHostName" /> + <p class="help-block"> + <i class="fa fa-info-circle"></i> $_("IP Address or Hostname")</p> + </div> + <div class="alert alert-info" role="alert">The following fields are optional. Fill them if you want Kimchi to + setup a password-less ssh session between the localhost and the remote host. The setup process will only + be successful if the user has 'SUDO ALL' permission in the remote machine. + </div> + <div class="form-group"> + <label for="user">$_("User")</label> + <input type="text" class="form-control" id="user" /> + <p class="help-block"> + <i class="fa fa-info-circle"></i> $_("Username of the remote host")</p> + </div> + <div class="form-group"> + <label for="password">$_("Password")</label> + <input type="password" class="form-control" id="password" /> + <p class="help-block"> + <i class="fa fa-info-circle"></i> $_("Password of the user in the remote host")</p> + </div> + <div class="form-group"> + <input id="deleteVM" class="wok-checkbox" type="checkbox" value="" /> + <label for="deleteVM" id="labelDeleteVM">$_("Delete this VM when the migration is completed") </label> + </div> + </div> + <div class="modal-footer"> + <button type="submit" id="migrateFormOk" class="btn btn-default">$_("Start")</button> + <button type="button" id="migrateFormCancel" data-dismiss="modal" class="btn btn-default">$_("Cancel")</button> + </div> +</div> + diff --git a/ui/pages/guest.html.tmpl b/ui/pages/guest.html.tmpl index c2d9ba8..080d918 100644 --- a/ui/pages/guest.html.tmpl +++ b/ui/pages/guest.html.tmpl @@ -40,7 +40,8 @@ <li role="presentation"><a nwAct="connect-vnc" class='shutoff-disabled' name="vm-console" href="#"><i class="fa fa-list-alt"></i>$_("Connect VNC")</a></li> <!-- <li role="presentation"><a nwAct="view-vnc" class='shutoff-disabled' name="vm-view-vnc" href="#"><i class="fa fa-eye"></i>$_("View VNC Console")</a></li> --> <li role="presentation"><a nwAct="edit" name="vm-edit" href="#"><i class="fa fa-pencil"></i>$_("Edit")</a></li> - <li role="presentation"><a href="#" nwAct="clone" class='running-disabled' name="vm-clone"><i class="fa fa-copy"></i>$_("Clone")</a></li> + <li role="presentation"><a nwAct="clone" class='running-disabled' name="vm-clone" href="#"><i class="fa fa-copy"></i>$_("Clone")</a></li> + <li role="presentation"><a nwAct="migrate" name="vm-migrate" href="#"><i class="fa fa-exchange"></i>$_("Migrate")</a></li> <li role="presentation"><a nwAct="reset" class='shutoff-hidden non-persistent-disabled' name="vm-reset" href="#"><i class="fa fa-refresh"></i>$_("Reset")</a></li> <li role="presentation"><a nwAct="pause" class='pause-hidden non-persistent-disabled' name="vm-pause" href="#"><i class="fa fa-pause"></i>$_("Pause")</a></li> <li role="presentation"><a nwAct="resume" class='resume-hidden' name="vm-resume" href="#"><i class="fa fa-play-circle"></i>$_("Resume")</a></li> @@ -95,6 +96,4 @@ </div> </span><!-- --><span class="item-hidden">$_("Network I/O")</span> - </li> - - + </li> \ No newline at end of file -- 1.9.3

From: samhenri <samuel.guimaraes@eldorado.org.br> Signed-off-by: samhenri <samuel.guimaraes@eldorado.org.br> --- ui/js/src/kimchi.guest_livemigration.js | 145 ++++++++++++++++++++++++++++++++ ui/js/src/kimchi.guest_main.js | 83 ++++++++---------- ui/pages/guest-migration.html.tmpl | 78 ++++++++--------- ui/pages/i18n.json.tmpl | 2 + ui/pages/tabs/guests.html.tmpl | 4 +- 5 files changed, 226 insertions(+), 86 deletions(-) create mode 100644 ui/js/src/kimchi.guest_livemigration.js diff --git a/ui/js/src/kimchi.guest_livemigration.js b/ui/js/src/kimchi.guest_livemigration.js new file mode 100644 index 0000000..136b7a7 --- /dev/null +++ b/ui/js/src/kimchi.guest_livemigration.js @@ -0,0 +1,145 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-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. + */ + +kimchi.guest_livemigration_main = function() { + kimchi.setupLiveMigrationFormEvent(); + kimchi.initLiveMigrationDialog(); +}; + +kimchi.startLiveMigration = function() { + var guests = []; + var getOngoingMigration = function(guestName) { + kimchi.getTasksByFilter('status=running&target_uri=' + encodeURIComponent('^/plugins/kimchi/vms/' + guestName + '/migrate'), function(tasks) { + for (var i = 0; i < tasks.length; i++) { + var guestUri = tasks[i].target_uri; + var guestName = guestUri.split('/')[2]; + guests[guestName] = tasks[i]; + + if (kimchi.trackingTasks.indexOf(tasks[i].id) >= 0) { + continue; + } + + kimchi.trackTask(tasks[i].id, function(guests) { + // On success + kimchi.listVmsAuto(); + if ($("#deleteVM").prop("checked")) { + kimchi.deleteVM(guestName, function(result) { + kimchi.listVmsAuto(); + }); + } + wok.window.close(); + }, function(guests) { + errorCallback(); + }, function(guests) { + // Progress callback + }); + } + }, null, true); + return guests; + }; + var errorCallback = function() { + $("#migrateFormOk").prop("disabled", false); + $("#remote_host").removeAttr("readonly"); + $("#user").removeAttr("readonly"); + $("#password").removeAttr("readonly"); + $("#deleteVM").removeAttr("readonly"); + $("#deleteVM").prop("checked", false); + $("#migrateFormOk").text(i18n.KCHAPI6011M); + }; + var values = kimchi.getLiveMigrationDialogValues(); + if (values.user && values.password) { + data = { + 'remote_host': values.remote_host, + 'user': values.user, + 'password': values.password + }; + } else { + data = { + 'remote_host': values.remote_host + }; + }; + kimchi.migrateGuest(kimchi.selectedGuest, data, function() { + getOngoingMigration(kimchi.selectedGuest); + }, function(err) { + wok.message.error(err.responseJSON.reason, "#alert-modal-container"); + errorCallback(); + }); +}; + +kimchi.initLiveMigrationDialog = function(okCallback) { + $("#migrateFormOk").on("click", function() { + $("#migrateFormOk").prop("disabled", true); + $("#remote_host").prop("readonly", "readonly"); + $("#user").prop("readonly", "readonly"); + $("#password").prop("readonly", "readonly"); + $("#deleteVM").prop("readonly", "readonly"); + $("#migrateFormOk").text(i18n.KCHAPI6012M); + kimchi.startLiveMigration(); + }); +}; + + +kimchi.getLiveMigrationDialogValues = function() { + var data = { + remote_host: $("#remote_host").val(), + user: $("#user").val(), + password: $("#password").val() + }; + return data; +}; + +kimchi.setupLiveMigrationFormEvent = function() { + $("#migrateFormOk").prop("disabled", true); + $("#remote_host").on("change keyup", function(event) { + if (!this.value) { + $(this).parent().addClass('has-error'); + } else { + $(this).parent().removeClass('has-error'); + } + kimchi.updateLiveMigrationButton(); + }); + $("#user").on("change keyup", function(event) { + if (this.value && !$("#password").val()) { + $("#user").parent().removeClass('has-warning'); + $("#password").parent().addClass('has-warning'); + } else { + $("#user").parent().removeClass('has-warning'); + $("#password").parent().removeClass('has-warning'); + } + kimchi.updateLiveMigrationButton(); + }); + $("#password").on("change keyup", function(event) { + if (this.value && !$("#user").val()) { + $("#user").parent().addClass('has-warning'); + } else { + $("#user").parent().removeClass('has-warning'); + $("#password").parent().removeClass('has-warning'); + kimchi.updateLiveMigrationButton(); + } + }); +}; + +kimchi.updateLiveMigrationButton = function() { + if ($("#remote_host").val()) { + if ($("input[type='text']").parent().hasClass("has-error") || $("input[type='text']").parent().hasClass("has-warning")) { + $("#migrateFormOk").prop("disabled", true); + } else { + $("#migrateFormOk").prop("disabled", false); + } + }; +}; \ No newline at end of file diff --git a/ui/js/src/kimchi.guest_main.js b/ui/js/src/kimchi.guest_main.js index 2d3ccf3..1d7e4ef 100644 --- a/ui/js/src/kimchi.guest_main.js +++ b/ui/js/src/kimchi.guest_main.js @@ -233,6 +233,14 @@ kimchi.vmedit = function(event) { }); }; +kimchi.vmmigrate = 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-migration.html'); +}; + kimchi.openVmConsole = function(event) { var button = event.target; var vm = $(button).closest('li[name=guest]'); @@ -275,7 +283,7 @@ kimchi.initGuestFilter = function() { }; kimchi.resetGuestFilter = function() { - if(guestFilterList){ + if (guestFilterList) { $('#search_input').val(); listFiltered = false; } @@ -326,26 +334,31 @@ kimchi.listVmsAuto = function() { }, null, true); return guests; }; - var getMigratingGuests = function(){ - var guests = []; - kimchi.getTasksByFilter('status=running&target_uri='+encodeURIComponent('^/vms/.+/migrate'), function(tasks) { - for(var i=0;i<tasks.length;i++){ - var guestUri = tasks[i].target_uri; - var guestName = guestUri.split('/')[4] - guests.push($.extend({}, kimchi.sampleGuestObject, {name: guestName, isMigrating: true})); - if(kimchi.trackingTasks.indexOf(tasks[i].id)==-1) - kimchi.trackTask(tasks[i].id, null, function(err){ - wok.message.error(err.message); - }, null); - } - }, null, true); - return guests; - }; + + var getMigratingGuests = function() { + var guests = []; + kimchi.getTasksByFilter('status=running&target_uri=' + encodeURIComponent('^/plugins/kimchi/vms/.+/migrate'), function(tasks) { + for (var i = 0; i < tasks.length; i++) { + var guestUri = tasks[i].target_uri; + var guestName = guestUri.split('/')[4] + guests.push($.extend({}, kimchi.sampleGuestObject, { + name: guestName, + isMigrating: true + })); + if (kimchi.trackingTasks.indexOf(tasks[i].id) == -1) + kimchi.trackTask(tasks[i].id, null, function(err) { + wok.message.error(err.message); + }, null); + } + }, null, true); + return guests; + }; + kimchi.listVMs(function(result, textStatus, jqXHR) { if (result && textStatus == "success") { - result = getMigratingGuests().concat(result); result = getCloningGuests().concat(result); result = getCreatingGuests().concat(result); + result = getMigratingGuests().concat(result); if (result.length) { var listHtml = ''; var guestTemplate = kimchi.guestTemplate; @@ -400,27 +413,6 @@ kimchi.listVmsAuto = function() { kimchi.createGuestLi = function(vmObject, prevScreenImage, openMenu) { var result = kimchi.guestElem.clone(); - - var initializeMigratePanel = function() { - $("#migrateFormOk").on("click", function() { - //TODO: Get values from UI for remote_host, user, password - var data = { - "remote_host" : "ltc-hab1.aus.stglabs.ibm.com", - "user" : "root", - "password" : "passw0rd" - }; - //TODO: Need to get guest to be passed in here - kimchi.migrateGuest(guest, data, function(){ - kimchi.listVmsAuto(); - wok.window.close(); - }, function(err) { - wok.message.error(err.responseJSON.reason); - }); - }); - } - - initializeMigratePanel(); - //Setup the VM list entry var currentState = result.find('.guest-state'); var vmRunningBool = (vmObject.state == "running"); @@ -440,7 +432,6 @@ kimchi.createGuestLi = function(vmObject, prevScreenImage, openMenu) { //Add the OS Type and Icon var osType = result.find('.distro-icon'); - console.log(vmObject); if (vmObject.icon == 'plugins/kimchi/images/icon-fedora.png') { osType.addClass('icon-fedora'); osType.attr('val', 'Fedora'); @@ -475,7 +466,7 @@ kimchi.createGuestLi = function(vmObject, prevScreenImage, openMenu) { //Setup the VM console thumbnail display var curImg = vmObject.icon; if (vmObject.screenshot) { - curImg = vmObject.screenshot.replace(/^\//,''); + curImg = vmObject.screenshot.replace(/^\//, ''); } var load_src = curImg || 'plugins/kimchi/images/icon-vm.png'; var tile_src = prevScreenImage || vmObject['load-src']; @@ -666,7 +657,7 @@ kimchi.createGuestLi = function(vmObject, prevScreenImage, openMenu) { } //Setup action event handlers - if(!(vmObject.isCloning || vmObject.isCreating || vmObject.isMigrating)){ + if (!(vmObject.isCloning || vmObject.isCreating || vmObject.isMigrating)) { guestActions.find("[name=vm-start]").on("click", function(event) { event.preventDefault(); @@ -725,9 +716,9 @@ kimchi.createGuestLi = function(vmObject, prevScreenImage, openMenu) { }); }, null); }); - guestActions.find("[name=vm-migrate]").click(function(){ - var guest = $(this).closest('li[name=guest]').attr("id"); - wok.window.open('plugins/kimchi/guest-migration.html'); + guestActions.find("[name=vm-migrate]").on('click', function() { + event.preventDefault(); + kimchi.vmmigrate(event); }); } else { guestActions.find('.btn').attr('disabled', true); @@ -735,7 +726,7 @@ kimchi.createGuestLi = function(vmObject, prevScreenImage, openMenu) { pendingText = result.find('.guest-pending .text') if (vmObject.isCloning) pendingText.text(i18n['KCHAPI6009M']); - else if(vmObject.isMigrating) + else if (vmObject.isMigrating) pendingText.text("Migrating"); else pendingText.text(i18n['KCHAPI6008M']); @@ -770,4 +761,4 @@ kimchi.editTemplate = function(guestTemplate, oldPopStat) { return guestTemplate.replace("vm-action", "vm-action open"); } return guestTemplate; -}; +}; \ No newline at end of file diff --git a/ui/pages/guest-migration.html.tmpl b/ui/pages/guest-migration.html.tmpl index 278d22c..7065605 100644 --- a/ui/pages/guest-migration.html.tmpl +++ b/ui/pages/guest-migration.html.tmpl @@ -21,45 +21,47 @@ #silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True) #silent _ = t.gettext #silent _t = t.gettext -<div id="migrate-guest-window" class="window modal-content"> - <div class="modal-header"> - <h4 class="modal-title" id="migrateModalLabel">$_("Migrate a Guest")</h4> - </div> - <div id="migrateInfo" class="modal-body"> - <div class="alert alert-warning" role="alert">Disclaimer: This process cannot be stopped after started, - can take a long time to complete and will turn off the VM on this Hypervisor when it is successfully - migrated to the remote destination. - </div> - <div class="form-group"> - <label for="remoteHostName">$_("Remote Server")</label> - <input type="text" class="form-control" id="remoteHostName" /> - <p class="help-block"> - <i class="fa fa-info-circle"></i> $_("IP Address or Hostname")</p> - </div> - <div class="alert alert-info" role="alert">The following fields are optional. Fill them if you want Kimchi to - setup a password-less ssh session between the localhost and the remote host. The setup process will only - be successful if the user has 'SUDO ALL' permission in the remote machine. +<!DOCTYPE html> +<html> +<body> + <div id="migrate-guest-window" class="window modal-content"> + <div class="modal-header"> + <h4 class="modal-title" id="migrateModalLabel">$_("Migrate a Guest")</h4> </div> - <div class="form-group"> - <label for="user">$_("User")</label> - <input type="text" class="form-control" id="user" /> - <p class="help-block"> - <i class="fa fa-info-circle"></i> $_("Username of the remote host")</p> + <div id="migrateInfo" class="modal-body"> + <span id="alert-modal-container"></span> + <div class="alert alert-warning" role="alert">$_("Disclaimer: This process cannot be stopped after started, can take a long time to complete and will turn off the VM on this Hypervisor when it is successfully migrated to the remote destination.")</div> + <div class="form-group"> + <label for="remote_host">$_("Remote Server")</label> + <input type="text" class="form-control" id="remote_host" /> + <p class="help-block"> + <i class="fa fa-info-circle"></i> $_("IP Address or Hostname")</p> + </div> + <div class="alert alert-info" role="alert">$_("The following fields are optional. Fill them if you want Kimchi to setup a password-less ssh session between the localhost and the remote host. The setup process will only be successful if the user has 'SUDO ALL' permission in the remote machine.")</div> + <div class="form-group"> + <label for="user">$_("User")</label> + <input type="text" class="form-control" id="user" /> + <p class="help-block"> + <i class="fa fa-info-circle"></i> $_("Username of the remote host")</p> + </div> + <div class="form-group"> + <label for="password">$_("Password")</label> + <input type="password" class="form-control" id="password" /> + <p class="help-block"> + <i class="fa fa-info-circle"></i> $_("Password of the user in the remote host")</p> + </div> + <div class="form-group"> + <input id="deleteVM" class="wok-checkbox" type="checkbox" value="" /> + <label for="deleteVM" id="labelDeleteVM">$_("Delete this VM when the migration is completed") </label> + </div> </div> - <div class="form-group"> - <label for="password">$_("Password")</label> - <input type="password" class="form-control" id="password" /> - <p class="help-block"> - <i class="fa fa-info-circle"></i> $_("Password of the user in the remote host")</p> + <div class="modal-footer"> + <button type="submit" id="migrateFormOk" class="btn btn-default">$_("Start")</button> + <button type="button" id="migrateFormCancel" data-dismiss="modal" class="btn btn-default">$_("Cancel")</button> </div> - <div class="form-group"> - <input id="deleteVM" class="wok-checkbox" type="checkbox" value="" /> - <label for="deleteVM" id="labelDeleteVM">$_("Delete this VM when the migration is completed") </label> - </div> - </div> - <div class="modal-footer"> - <button type="submit" id="migrateFormOk" class="btn btn-default">$_("Start")</button> - <button type="button" id="migrateFormCancel" data-dismiss="modal" class="btn btn-default">$_("Cancel")</button> </div> -</div> - + <script> + kimchi.guest_livemigration_main(); + </script> +</body> +</html> diff --git a/ui/pages/i18n.json.tmpl b/ui/pages/i18n.json.tmpl index c1979c6..f940ee5 100644 --- a/ui/pages/i18n.json.tmpl +++ b/ui/pages/i18n.json.tmpl @@ -44,6 +44,8 @@ "KCHAPI6008M": "$_("Creating...")", "KCHAPI6009M": "$_("Cloning...")", "KCHAPI6010M": "$_("Saving...")", + "KCHAPI6011M": "$_("Start")", + "KCHAPI6012M": "$_("Migrating...")", "KCHTMPL6001W": "$_("No ISO found")", diff --git a/ui/pages/tabs/guests.html.tmpl b/ui/pages/tabs/guests.html.tmpl index 21d1f90..5409dfb 100644 --- a/ui/pages/tabs/guests.html.tmpl +++ b/ui/pages/tabs/guests.html.tmpl @@ -44,7 +44,7 @@ <span class="icon-bar"></span> <span class="icon-bar"></span> </button> - </div> + </div> <!-- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="toolbar"> <ul class="nav navbar-nav navbar-right tools" display="none"> @@ -60,7 +60,7 @@ <label for="search_input" class="sr-only">$_("Filter"):</label> <input type="text" class="filter form-control search" id="search_input" placeholder="$_("Filter")"> </div> - </div> + </div> <div id="alert-container"></div> <div id="guestListField" style="display: none"> <ul class="wok-guest-list"> -- 1.9.3

Almost there, but: - when deleting the VM after the migration I've got an error 'VM <name> not found' in the VM listing. Probably because the UI tried to fetch information about the VM that was deleted - The modal doesn't disappear when firing a migration, locking the user from doing anything else in Kimchi. Ideally the UI would fire the migration process, return to the Guests tab and the user would keep doing whatever he was doing. When the migration is completed the UI would report 'Migration of VM <> completed' and, if the user is in the Guests tab, instantly refresh the tab to reflect the changes (VM shutoff or VM deleted). Second issue is kind of a deal breaker. I just stood in front of the modal for 6 minutes waiting for the whole migration to be completed (non shared migration with disk copy). We need to move the modal off and the UI must handle the end of migration in a asynchronous fashion. First issue can be handled later in a bug fix IMO. Daniel On 01/15/2016 02:47 PM, sguimaraes943@gmail.com wrote:
From: samhenri <samuel.guimaraes@eldorado.org.br>
- Rebased initial checkin for live migration to new-ui; - Added form validation to optional fields (e.g. disable submit button if username is filled but password is empty, added warn classes to form fields); - Fixed error messages in modal window; - Delete VM once Live Migration is finished checkbox is working;
Socorro Stoppler (1): Initial checkin for live migration UI support
samhenri (1): Live Migration front-end
ui/js/src/kimchi.api.js | 3 +- ui/js/src/kimchi.guest_livemigration.js | 145 ++++++++++++++++++++++++++++++++ ui/js/src/kimchi.guest_main.js | 47 +++++++++-- ui/pages/guest-migration.html.tmpl | 67 +++++++++++++++ ui/pages/guest.html.tmpl | 7 +- ui/pages/i18n.json.tmpl | 2 + ui/pages/tabs/guests.html.tmpl | 4 +- 7 files changed, 261 insertions(+), 14 deletions(-) create mode 100644 ui/js/src/kimchi.guest_livemigration.js create mode 100644 ui/pages/guest-migration.html.tmpl
participants (3)
-
Aline Manera
-
Daniel Henrique Barboza
-
sguimaraes943@gmail.com