
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