
I'd like to do two suggestions: 1) Add a progress bar just below the 'Cloning..." text to show the cloning progress - libvirt provides this info; and 2) Add a warning screen when user select to clone a VM informing that the new virtual disk will be located in the default storage pool if the VM is using a iSCSI storage pool and/or the storage pool of the VM to be cloned doesn't have enough space in disk. It's a informative warning that must be displayed every time that a VM is choosed to be cloned (like when user select to execute a Power Off of some running guest). I know that the second topic was discussed in previous scrum meetings, but it's important alert the user about the backend operations. Thanks and best regards, -- Paulo Ricardo Paz Vital <pvital@linux.vnet.ibm.com> IBM Linux Technology Center
From: Yu Xin Huo <huoyuxin@linux.vnet.ibm.com>
Signed-off-by: Yu Xin Huo <huoyuxin@linux.vnet.ibm.com> --- ui/css/theme-default/list.css | 18 ++++++++++ ui/js/src/kimchi.api.js | 17 ++++++++- ui/js/src/kimchi.guest_main.js | 73 +++++++++++++++++++++++++++++++++++---- ui/pages/guest.html.tmpl | 6 +++- 4 files changed, 103 insertions(+), 11 deletions(-)
diff --git a/ui/css/theme-default/list.css b/ui/css/theme-default/list.css index 8ffee69..fc3017b 100644 --- a/ui/css/theme-default/list.css +++ b/ui/css/theme-default/list.css @@ -275,3 +275,21 @@ text-shadow: -1px -1px 1px #ccc, 1px 1px 1px #fff; padding-left: 10px; } + +.guest-clone { + margin: 10px; +} + +.guest-clone .icon { + background: url('../../images/theme-default/loading.gif') no-repeat; + display: inline-block; + width: 20px; + height: 20px; + vertical-align: middle; +} + +.guest-clone .text { + color: #666666; + margin-left: 5px; + text-shadow: -1px -1px 1px #CCCCCC, 1px 1px 1px #FFFFFF; +} diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js index 5895a07..2f90219 100644 --- a/ui/js/src/kimchi.api.js +++ b/ui/js/src/kimchi.api.js @@ -695,10 +695,10 @@ var kimchi = { }, 2000); break; case 'finished': - suc(result); + suc && suc(result); break; case 'failed': - err(result); + err && err(result); break; default: break; @@ -1233,5 +1233,18 @@ var kimchi = { success : suc, error : err }); + }, + + cloneGuest: function(vm, suc, err) { + kimchi.requestJSON({ + url : kimchi.url + 'vms/'+encodeURIComponent(vm)+"/clone", + type : 'POST', + contentType : 'application/json', + dataType : 'json', + success : suc, + error : err ? err : function(data) { + kimchi.message.error(data.responseJSON.reason); + } + }); } }; diff --git a/ui/js/src/kimchi.guest_main.js b/ui/js/src/kimchi.guest_main.js index dbe8753..ecc3b7a 100644 --- a/ui/js/src/kimchi.guest_main.js +++ b/ui/js/src/kimchi.guest_main.js @@ -15,6 +15,34 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +kimchi.sampleGuestObject = { + "name": "", + "uuid": "", + "state": "shutoff", + "persistent": true, + "icon": null, + "cpus": 0, + "memory": 0, + "stats": { + "net_throughput": 0, + "io_throughput_peak": 100, + "cpu_utilization": 0, + "io_throughput": 0, + "net_throughput_peak": 100 + }, + "screenshot": null, + "graphics": { + "passwd": null, + "passwdValidTo": null, + "type": "vnc", + "port": null, + "listen": "127.0.0.1" + }, + "users": [], + "groups": [], + "access": "full" +}; +
kimchi.vmstart = function(event) { var button=$(this); @@ -173,8 +201,24 @@ kimchi.listVmsAuto = function() { if (kimchi.vmTimeout) { clearTimeout(kimchi.vmTimeout); } + var getCloningGuests = function(){ + var guests = []; + kimchi.getTasksByFilter('status=running&target_uri='+encodeURIComponent('^/vms/*'), function(tasks) { + for(var i=0;i<tasks.length;i++){ + var guestUri = tasks[i].target_uri; + var guestName = guestUri.substring(guestUri.lastIndexOf('/')+1, guestUri.length); + guests.push($.extend({}, kimchi.sampleGuestObject, {name: guestName, isCloning: true})); + if(kimchi.trackingTasks.indexOf(tasks[i].id)==-1) + kimchi.trackTask(tasks[i].id, null, function(err){ + kimchi.message.error(err.message); + }, null); + } + }, null, true); + return guests; + }; kimchi.listVMs(function(result, textStatus, jqXHR) { if (result && textStatus=="success") { + result = getCloningGuests().concat(result); if(result.length) { var listHtml = ''; var guestTemplate = kimchi.guestTemplate; @@ -233,14 +277,16 @@ kimchi.createGuestLi = function(vmObject, prevScreenImage, openMenu) { imgLoad.attr('src',load_src);
//Link the stopped tile to the start action, the running tile to open the console - if (vmRunningBool) { - liveTile.off("click", kimchi.vmstart); - liveTile.on("click", kimchi.openVmConsole); - } - else { - liveTile.off("click", kimchi.openVmConsole); - liveTile.on("click", kimchi.vmstart); - liveTile.hover(function(event){$(this).find('.overlay').show()}, function(event){$(this).find('.overlay').hide()}); + if(!vmObject.isCloning){ + if (vmRunningBool) { + liveTile.off("click", kimchi.vmstart); + liveTile.on("click", kimchi.openVmConsole); + } + else { + liveTile.off("click", kimchi.openVmConsole); + liveTile.on("click", kimchi.vmstart); + liveTile.hover(function(event){$(this).find('.overlay').show()}, function(event){$(this).find('.overlay').hide()}); + } }
@@ -257,6 +303,7 @@ kimchi.createGuestLi = function(vmObject, prevScreenImage, openMenu) { //Setup the VM Actions var guestActions=result.find("div[name=guest-actions]"); guestActions.find(".shutoff-disabled").prop('disabled', !vmRunningBool ); + guestActions.find(".running-disabled").prop('disabled', vmRunningBool );
if (vmRunningBool) { guestActions.find(".running-hidden").hide(); @@ -286,6 +333,11 @@ kimchi.createGuestLi = function(vmObject, prevScreenImage, openMenu) { } guestActions.find("[name=vm-edit]").on({click : kimchi.vmedit}); guestActions.find("[name=vm-delete]").on({click : kimchi.vmdelete}); + guestActions.find("[name=vm-clone]").click(function(){ + kimchi.cloneGuest($(this).closest('li[name=guest]').attr("id"), function(data){ + kimchi.listVmsAuto(); + }); + });
//Maintain menu open state var actionMenu=guestActions.find("div[name=actionmenu]"); @@ -293,6 +345,11 @@ kimchi.createGuestLi = function(vmObject, prevScreenImage, openMenu) { $('.popover', actionMenu).toggle(); }
+ if(vmObject.isCloning){ + guestActions.children().hide(); + result.find('.guest-clone').removeClass('hide-content'); + } + return result; };
diff --git a/ui/pages/guest.html.tmpl b/ui/pages/guest.html.tmpl index 43fb350..74206fd 100644 --- a/ui/pages/guest.html.tmpl +++ b/ui/pages/guest.html.tmpl @@ -26,6 +26,9 @@ <div class="guest-general"> <h2 class="title" title="{name}">{name}</h2> </div> + <div class="guest-clone hide-content"> + <span class="icon"></span><span class="text">$_("Cloning")...</span> + </div> </div> <div name="cpu_utilization" class="sortable"> <div class="circleGauge"></div> @@ -56,7 +59,8 @@ <span class="text">$_("Actions")</span><span class="arrow"></span> <div class="popover actionsheet right-side" style="width: 250px"> <button class="button-big shutoff-disabled" name="vm-console" ><span class="text">$_("Connect")</span></button> - <button class="button-big running-disabled" name="vm-edit"><span class="text">$_("Edit")</span></button> + <button class="button-big running-disabled" name="vm-clone"><span class="text">$_("Clone")</span></button> + <button class="button-big" name="vm-edit"><span class="text">$_("Edit")</span></button> <button class="button-big shutoff-hidden" name="vm-reset"><span class="text">$_("Reset")</span></button> <button class="button-big shutoff-hidden" name="vm-shutdown"><span class="text">$_("Shut Down")</span></button> <button class="button-big running-hidden" name="vm-start"><span class="text">$_("Start")</span></button>