diff --git a/xCAT-UI/css/style.css b/xCAT-UI/css/style.css index b3a56eed6..9fc78eb5c 100644 --- a/xCAT-UI/css/style.css +++ b/xCAT-UI/css/style.css @@ -114,6 +114,10 @@ body { color: inherit; } +pre { + font-size: 10px; +} + /*--------------- Groups ---------------*/ #groups { width: 150px; diff --git a/xCAT-UI/js/custom/blade.js b/xCAT-UI/js/custom/blade.js index 3ac788dc4..23e0c34bb 100644 --- a/xCAT-UI/js/custom/blade.js +++ b/xCAT-UI/js/custom/blade.js @@ -14,6 +14,17 @@ var bladePlugin = function() { }; +/** + * Clone node (service page) + * + * @param node + * Node to clone + * @return Nothing + */ +bladePlugin.prototype.serviceClone = function(node) { + +}; + /** * Load provision page (service page) * diff --git a/xCAT-UI/js/custom/hmc.js b/xCAT-UI/js/custom/hmc.js index bf83d1306..ba0ce1e61 100644 --- a/xCAT-UI/js/custom/hmc.js +++ b/xCAT-UI/js/custom/hmc.js @@ -14,6 +14,17 @@ var hmcPlugin = function() { }; +/** + * Clone node (service page) + * + * @param node + * Node to clone + * @return Nothing + */ +hmcPlugin.prototype.serviceClone = function(node) { + +}; + /** * Load provision page (service page) * diff --git a/xCAT-UI/js/custom/ipmi.js b/xCAT-UI/js/custom/ipmi.js index 2b2e132b6..3c74067f3 100644 --- a/xCAT-UI/js/custom/ipmi.js +++ b/xCAT-UI/js/custom/ipmi.js @@ -14,6 +14,17 @@ var ipmiPlugin = function() { }; +/** + * Clone node (service page) + * + * @param node + * Node to clone + * @return Nothing + */ +ipmiPlugin.prototype.serviceClone = function(node) { + +}; + /** * Load provision page (service page) * diff --git a/xCAT-UI/js/custom/zvm.js b/xCAT-UI/js/custom/zvm.js index 72ea8b179..a143f5eeb 100644 --- a/xCAT-UI/js/custom/zvm.js +++ b/xCAT-UI/js/custom/zvm.js @@ -15,6 +15,44 @@ var zvmPlugin = function() { }; +/** + * Clone node (service page) + * + * @param node + * Node to clone + * @return Nothing + */ +zvmPlugin.prototype.serviceClone = function(node) { + var statBar = createStatusBar(node + 'CloneStat'); + var loader = createLoader(''); + statBar.find('div').append(loader); + statBar.prependTo($('#manageTab')); + + var owner = $.cookie('srv_usrname'); + var group = getUserNodeAttr(node, 'groups'); + + // Submit request to clone VM + // webportal clonezlinux [src node] [group] [owner] + $.ajax({ + url : 'lib/srv_cmd.php', + dataType : 'json', + data : { + cmd : 'webportal', + tgt : '', + args : 'clonezlinux;' + node + ';' + group + ';' + owner, + msg : '' + }, + success:function(data) { + // Remove loader + statBar.find('img').remove(); + // Append output to status bar + for (var i in data.rsp) { + statBar.find('div').append($('
').append(data.rsp[i])); + } + } + }); +}; + /** * Load provision page (service page) * @@ -68,7 +106,7 @@ zvmPlugin.prototype.loadServiceProvisionPage = function(tabId) { var hcp = $('#select-table tbody tr:eq(0) td:eq(0) input[name="hcp"]:checked').val(); var group = $('#select-table tbody tr:eq(0) td:eq(1) input[name="group"]:checked').val(); var img = $('#select-table tbody tr:eq(0) td:eq(2) input[name="image"]:checked').val(); - var owner = $.cookie('srv_usrname');; + var owner = $.cookie('srv_usrname'); // Begin by creating VM createzVM(tabId, group, hcp, img, owner); @@ -79,7 +117,7 @@ zvmPlugin.prototype.loadServiceProvisionPage = function(tabId) { loadSrvGroups(groupCol); loadOSImages(imageCol); - // Get zVM host names + // Get zVM host names if (!$.cookie('srv_zvm')){ $.ajax( { url : 'lib/srv_cmd.php', diff --git a/xCAT-UI/js/service/service.js b/xCAT-UI/js/service/service.js index ad639acbd..f85d043f0 100644 --- a/xCAT-UI/js/service/service.js +++ b/xCAT-UI/js/service/service.js @@ -517,6 +517,15 @@ function loadNodesTable(data) { } }); + // Clone + var cloneLnk = $('Clone'); + cloneLnk.click(function() { + var tgtNodes = getNodesChecked(nodesDTId); + if (tgtNodes) { + cloneNode(tgtNodes); + } + }); + // Delete var deleteLnk = $('Delete'); deleteLnk.click(function() { @@ -540,7 +549,7 @@ function loadNodesTable(data) { // Prepend menu to datatable var actionsLnk = 'Actions'; - var actionMenu = createMenu([deleteLnk, powerOnLnk, powerOffLnk, monitorOnLnk, monitorOffLnk, unlockLnk]); + var actionMenu = createMenu([cloneLnk, deleteLnk, monitorOnLnk, monitorOffLnk, powerOnLnk, powerOffLnk, unlockLnk]); var menu = createMenu([[actionsLnk, actionMenu]]); menu.superfish(); actionBar.append(menu); @@ -1171,6 +1180,43 @@ function monitorNode(node, monitor) { } } +/** + * Open a dialog to clone node + * + * @param tgtNodes + * Nodes to clone + * @return Nothing + */ +function cloneNode(tgtNodes) { + var nodes = tgtNodes.split(','); + + for (var n in nodes) { + // Get hardware that was selected + var hw = getUserNodeAttr(nodes[n], 'mgt'); + + // Create an instance of the plugin + var plugin; + switch (hw) { + case "blade": + plugin = new bladePlugin(); + break; + case "hmc": + plugin = new hmcPlugin(); + break; + case "ipmi": + plugin = new ipmiPlugin(); + break; + case "zvm": + plugin = new zvmPlugin(); + break; + } + + // Clone node + plugin.serviceClone(nodes[n]); + } +} + + /** * Open a dialog to delete node * diff --git a/xCAT-UI/js/service/utils.js b/xCAT-UI/js/service/utils.js index 557e795c4..62ed47c24 100644 --- a/xCAT-UI/js/service/utils.js +++ b/xCAT-UI/js/service/utils.js @@ -318,4 +318,43 @@ function showChdefOutput(data) { } info.append(prg); +} + +/** + * Get an attribute of a given node + * + * @param node + * The node + * @param attrName + * The attribute + * @return The attribute of the node + */ +function getUserNodeAttr(node, attrName) { + // Get the row + var row = $('[id=' + node + ']').parents('tr'); + + // Search for the column containing the attribute + var attrCol; + + var cols = row.parents('.dataTables_scroll').find('.dataTables_scrollHead thead tr:eq(0) th'); + // Loop through each column + for (var i in cols) { + // Find column that matches the attribute + if (cols.eq(i).html() == attrName) { + attrCol = cols.eq(i); + break; + } + } + + // If the column containing the attribute is found + if (attrCol) { + // Get the attribute column index + var attrIndex = attrCol.index(); + + // Get the attribute for the given node + var attr = row.find('td:eq(' + attrIndex + ')'); + return attr.text(); + } else { + return ''; + } } \ No newline at end of file diff --git a/xCAT-UI/lib/functions.php b/xCAT-UI/lib/functions.php index b4cceb1ba..3fa8eded5 100644 --- a/xCAT-UI/lib/functions.php +++ b/xCAT-UI/lib/functions.php @@ -111,7 +111,7 @@ function submit_request($req, $skipVerify, $opts_array){ format_TBD($tmp); } else { // Print out output by default - echo '' . $tmp . ''; + echo '
' . $tmp . ''; ob_flush(); flush(); } diff --git a/xCAT-UI/lib/srv_functions.php b/xCAT-UI/lib/srv_functions.php index e2eb01a3a..3f427cab3 100644 --- a/xCAT-UI/lib/srv_functions.php +++ b/xCAT-UI/lib/srv_functions.php @@ -111,7 +111,7 @@ function submit_request($req, $skipVerify, $opts_array){ format_TBD($tmp); } else { // Print out output by default - echo '
' . $tmp . ''; + echo '
' . $tmp . ''; ob_flush(); flush(); } diff --git a/xCAT-UI/xcat/plugins/webportal.pm b/xCAT-UI/xcat/plugins/webportal.pm index e87aa2d3a..6a2d0fbe7 100644 --- a/xCAT-UI/xcat/plugins/webportal.pm +++ b/xCAT-UI/xcat/plugins/webportal.pm @@ -34,8 +34,9 @@ sub process_request { my $callback = shift; my $sub_req = shift; my %authorized_cmds = ( - 'lszvm' => \&lszvm, - 'provzlinux' => \&provzlinux + 'lszvm' => \&lszvm, + 'provzlinux' => \&provzlinux, + 'clonezlinux' => \&clonezlinux ); # Check if the request is authorized @@ -370,4 +371,126 @@ sub gennodename { return ($hostname, $base_digit); } -1; + +sub clonezlinux { + my ( $request, $callback, $sub_req ) = @_; + + # webportal clonezlinux [src node] [group] [owner] + my $src_node = $request->{arg}->[1]; + my $group = $request->{arg}->[2]; + my $owner = $request->{arg}->[3]; + + # Get source node's HCP + my $props = xCAT::zvmUtils->getNodeProps( 'zvm', $src_node, ('hcp') ); + my $hcp = $props->{'hcp'}; + + # Read in default disk pool and disk size /opt/zhcp/conf/default.conf on zHCP + # pool = POOL3 + # eckd_size = 10016 + my $disk_pool; + my $eckd_size; + my $fba_size; + my $default_conf = '/opt/zhcp/conf/default.conf'; + my $default_direct = '/opt/zhcp/conf/default.direct'; + + # Exit if default.conf does not exist + if ( !(`ssh $hcp "test -e $default_conf && echo Exists"`) ) { + println( $callback, '(Error) $default_conf does not exists' ); + return; + } + + # Exit if default.direct does not exist + if ( !(`ssh $hcp "test -e $default_direct && echo Exists"`) ) { + println( $callback, '(Error) $default_direct does not exists' ); + return; + } + + my $out = `ssh $hcp "cat $default_conf"`; + my @tmp = split( /\n/, $out ); + foreach (@tmp) { + # Get disk pool + if ( $_ =~ m/pool =/i ) { + $disk_pool = $_; + $disk_pool =~ s/pool =//g; + } + + # Get disk size + elsif ( $_ =~ m/eckd_size =/i ) { + $eckd_size = $_; + $eckd_size =~ s/eckd_size =//g; + } + elsif ( $_ =~ m/fba_size = /i ) { + $fba_size = $_; + $fba_size =~ s/fba_size = //g; + } + } + + println( $callback, "Your virtual machine is ready. It may take a few minutes before you can logon." ); + println( $callback, "Done!" ); + + return; + + + + +# # Create VM +# # e.g. webportal provzlinux [group] [hcp] [image] +# my ($node, $base_digit) = gennodename( $callback, $group ); +# my $userid = 'XCAT' . $base_digit; +# +# # Set node definitions +# $out = `mkdef -t node -o $node userid=$userid hcp=$hcp mgt=zvm groups=$group`; +# println( $callback, "$out" ); +# +# # Set nodetype definitions +# $out = `chtab node=$node noderes.netboot=zvm nodetype.nodetype=osi nodetype.provmethod=install nodetype.os=$os nodetype.arch=$arch nodetype.profile=$profile nodetype.comments="owner:$owner"`; +# +# # Update hosts table and DNS +# `makehosts`; +# `makedns`; +# +# # Create user directory entry replacing LXUSR with user ID +# # Use /opt/zhcp/conf/default.direct on zHCP as the template +# # USER LXUSR PSWD 512M 1G G +# # INCLUDE LNXDFLT +# # COMMAND SET VSWITCH VSW2 GRANT LXUSR +# $out = `ssh $hcp "sed $default_direct -e s/LXUSR/$userid/g" > /tmp/$node-direct.txt`; +# $out = `mkvm $node /tmp/$node-direct.txt`; +# `rm -rf /tmp/$node-direct.txt`; +# println( $callback, "$out" ); +# if ( $out =~ m/Error/i ) { +# return; +# } +# +# # Update DHCP +# `makedhcp -a`; +# +# # Toggle node power so COMMAND SET will get executed +# `rpower $node on`; +# `rpower $node off`; +# +# # Punch kernel, initrd, and ramdisk to node reader +# $out = `nodeset $node install`; +# println( $callback, "$out" ); +# if ( $out =~ m/Error/i ) { +# return; +# } +# +# # IPL reader and begin installation +# $out = `rnetboot $node ipl=00C`; +# println( $callback, "$out" ); +# if ( $out =~ m/Error/i ) { +# return; +# } +# +# # Configure Ganglia monitoring +# $out = `moncfg gangliamon $node -r`; +# +# # Show node information, e.g. IP, hostname, and root password +# $out = `lsdef $node | egrep "ip=|hostnames="`; +# my $rootpw = getsysrootpw(); +# println( $callback, "Your virtual machine is ready. It may take a few minutes before you can logon using VNC ($node:1). Below is your VM attributes." ); +# println( $callback, "$out" ); +# println( $callback, " rootpw = $rootpw" ); +} +1; \ No newline at end of file