
From: samhenri <samuel.guimaraes@eldorado.org.br> Signed-off-by: samhenri <samuel.guimaraes@eldorado.org.br> --- ui/js/src/kimchi.guest_livemigration.js | 121 ++++++++++++++++++++++++++++++++ ui/js/src/kimchi.guest_main.js | 114 +++++++++++++++++++----------- ui/pages/guest-migration.html.tmpl | 78 ++++++++++---------- ui/pages/guests.html.tmpl | 4 +- ui/pages/i18n.json.tmpl | 2 + 5 files changed, 237 insertions(+), 82 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..9e74ad4 --- /dev/null +++ b/ui/js/src/kimchi.guest_livemigration.js @@ -0,0 +1,121 @@ +/* + * Project Kimchi + * + * Copyright IBM, Corp. 2013-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. + */ + +kimchi.guest_livemigration_main = function() { + kimchi.setupLiveMigrationFormEvent(); + kimchi.initLiveMigrationDialog(); +}; + +kimchi.startLiveMigration = function() { + 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() { + kimchi.listVmsAuto(); + if ($("#deleteVM").prop("checked")) { + if (deleteQueue.indexOf(kimchi.selectedGuest) === -1) { + deleteQueue.push(kimchi.selectedGuest); + } + } + wok.window.close(); + }, 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.KCHAPI6010M); + 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); + } + }; +}; diff --git a/ui/js/src/kimchi.guest_main.js b/ui/js/src/kimchi.guest_main.js index 68e17cc..5b8993a 100644 --- a/ui/js/src/kimchi.guest_main.js +++ b/ui/js/src/kimchi.guest_main.js @@ -45,6 +45,8 @@ kimchi.sampleGuestObject = { "access": "full" }; +var deleteQueue = []; + kimchi.vmstart = function(event) { var button = event.target; if (!$(button).hasClass('loading')) { @@ -229,6 +231,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]'); @@ -303,22 +313,64 @@ 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); + 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 getMigratedGuests = function() { + var guests = []; + kimchi.getTasksByFilter('status=finished&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(guestName); + 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 deleteMigratedGuests = function() { + deleteQueue.reverse(); + migratedGuests = getMigratedGuests(); + migratedGuests.sort(); + var i = deleteQueue.length; + while (i-- && i > 0) { + if (migratedGuests.indexOf(deleteQueue[i]) > -1) { + kimchi.deleteVM(deleteQueue[i], function(result) { + clearFromQueue(deleteQueue[i]); + }, function(err) { + wok.message.error(err.responseJSON.reason); + }); + } } - }, null, true); - return guests; - }; + }; + + var clearFromQueue = function(item) { + var toDequeue = deleteQueue.indexOf(item); + if (toDequeue != -1) { + deleteQueue.splice(toDequeue, 1); + }; + }; + kimchi.listVMs(function(result, textStatus, jqXHR) { + deleteMigratedGuests(); if (result && textStatus == "success") { result = getMigratingGuests().concat(result); result = getCloningGuests().concat(result); @@ -359,27 +411,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"); @@ -399,7 +430,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'); @@ -434,7 +464,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']; @@ -625,7 +655,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(); @@ -684,9 +714,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); @@ -694,7 +724,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']); 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/guests.html.tmpl b/ui/pages/guests.html.tmpl index 66a6e00..97ee17c 100644 --- a/ui/pages/guests.html.tmpl +++ b/ui/pages/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="guests-filter" class="sr-only">$_("Filter"):</label> <input type="text" class="filter form-control" placeholder="$_("Filter")"> </div> - </div> + </div> <div id="alert-container"></div> <div id="guestListField" style="display: none"> <ul class="wok-guest-list"> diff --git a/ui/pages/i18n.json.tmpl b/ui/pages/i18n.json.tmpl index d356437..bee3ad1 100644 --- a/ui/pages/i18n.json.tmpl +++ b/ui/pages/i18n.json.tmpl @@ -43,6 +43,8 @@ "KCHAPI6007M": "$_("Save")", "KCHAPI6008M": "$_("Creating...")", "KCHAPI6009M": "$_("Cloning...")", + "KCHAPI6010M": "$_("Migrating...")", + "KCHAPI6011M": "$_("Start")", "KCHTMPL6001W": "$_("No ISO found")", -- 1.9.3