diff --git a/perl-xCAT/xCAT/zvmUtils.pm b/perl-xCAT/xCAT/zvmUtils.pm
index a7ee21798..cb337f473 100644
--- a/perl-xCAT/xCAT/zvmUtils.pm
+++ b/perl-xCAT/xCAT/zvmUtils.pm
@@ -2029,15 +2029,15 @@ sub smapi4xcat {
# Check SMAPI level
# Levels 621 and greater support SMAPI EXEC
- my $out = `ssh $user\@$hcp "$sudo $dir/smcli Query_API_Functional_Level -T $hcpUserId"`;
- $out = xCAT::zvmUtils->trimStr($out);
- if ( !($out =~ m/V6.2/i || $out =~ m/V6.1/i || $out =~ m/V5.4/i) ) {
- return 1;
- }
+# my $out = `ssh $user\@$hcp "$sudo $dir/smcli Query_API_Functional_Level -T $hcpUserId"`;
+# $out = xCAT::zvmUtils->trimStr($out);
+# if ( !($out =~ m/V6.2/i || $out =~ m/V6.1/i || $out =~ m/V5.4/i) ) {
+# return 1;
+# }
# Check if SMAPI EXEC exists
# EXEC found if RC = 8 and RS = 3002
- $out = `ssh $user\@$hcp "$sudo $dir/smcli xCAT_Commands_IUO -T $hcpUserId -c ''"`;
+ my $out = `ssh $user\@$hcp "$sudo $dir/smcli xCAT_Commands_IUO -T $hcpUserId -c ''"`;
$out = xCAT::zvmUtils->trimStr($out);
if ( $out =~ m/Return Code: 8/i && $out =~ m/Reason Code: 3002/i ) {
return 1;
diff --git a/xCAT-UI/js/custom/zvm.js b/xCAT-UI/js/custom/zvm.js
index fee3b239f..8ceae3a1d 100644
--- a/xCAT-UI/js/custom/zvm.js
+++ b/xCAT-UI/js/custom/zvm.js
@@ -33,7 +33,7 @@ zvmPlugin.prototype.loadConfigPage = function(tabId) {
// Create accordion panel for images
var imgSection = $('
');
- var imgLnk = $('').click(function () {
+ var imgLnk = $('').click(function () {
// Do not load panel again if it is already loaded
if ($('#zvmConfigImages').find('.dataTables_wrapper').length)
return;
@@ -67,7 +67,7 @@ zvmPlugin.prototype.loadConfigPage = function(tabId) {
*
* @param node Node to clone
*/
-zvmPlugin.prototype.serviceClone = function(node) {
+zvmPlugin.prototype.serviceClone = function(node) {
var owner = $.cookie('xcat_username');
var group = getUserNodeAttr(node, 'groups');
@@ -95,7 +95,7 @@ zvmPlugin.prototype.loadServiceProvisionPage = function(tabId) {
// Create provision table
var provTable = $(' zVM | Group | Image | ');
+ var provHeader = $('');
var provBody = $('');
var provFooter = $('');
provTable.append(provHeader, provBody, provFooter);
@@ -108,16 +108,18 @@ zvmPlugin.prototype.loadServiceProvisionPage = function(tabId) {
// Create row to contain selections
var provRow = $('
');
provBody.append(provRow);
- // Create columns for zVM, group, and image
+ // Create columns for zVM, group, template, and image
var zvmCol = $(' | ');
provRow.append(zvmCol);
var groupCol = $(' | ');
provRow.append(groupCol);
- var imageCol = $(' | ');
- provRow.append(imageCol);
+ var tmplCol = $(' | ');
+ provRow.append(tmplCol);
+ var imgCol = $(' | ');
+ provRow.append(imgCol);
provRow.children('td').css({
- 'min-width': '250px'
+ 'min-width': '200px'
});
/**
@@ -130,23 +132,38 @@ 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 tmpl = $('#select-table tbody tr:eq(0) td:eq(2) input[name="image"]:checked').val();
+ var img = $('#select-table tbody tr:eq(0) td:eq(3) input[name="master"]:checked').val();
var owner = $.cookie('xcat_username');
- if (!hcp || !group || !img) {
+ if (img && !group) {
+ // Show warning message
+ var warn = createWarnBar('You need to select a group');
+ warn.prependTo($(this).parent());
+ } else if (!img && (!hcp || !group || !tmpl)) {
// Show warning message
- var warn = createWarnBar('You need to select an option for each column');
+ var warn = createWarnBar('You need to select a zHCP, group, and image');
warn.prependTo($(this).parent());
} else {
- // Begin by creating VM
- createzVM(tabId, group, hcp, img, owner);
+ if (img) {
+ // Begin by clonning VM
+
+ // Submit request to clone VM
+ // webportal clonezlinux [src node] [group] [owner]
+ var iframe = createIFrame('lib/srv_cmd.php?cmd=webportal&tgt=&args=clonezlinux;' + img + ';' + group + ';' + owner + '&msg=&opts=flush');
+ iframe.prependTo($('#zvmProvisionTab'));
+ } else {
+ // Begin by creating VM
+ createzVM(tabId, group, hcp, tmpl, owner);
+ }
}
});
provForm.append(provisionBtn);
- // Load zVMs, groups, and images into their respective columns
+ // Load zVMs, groups, template, and image into their respective columns
loadSrvGroups(groupCol);
- loadOSImages(imageCol);
+ loadOSImages(tmplCol);
+ loadGoldenImages(imgCol);
// Get zVM host names
if (!$.cookie('zvms')){
diff --git a/xCAT-UI/js/custom/zvmUtils.js b/xCAT-UI/js/custom/zvmUtils.js
index 27a50451c..2ec031c01 100644
--- a/xCAT-UI/js/custom/zvmUtils.js
+++ b/xCAT-UI/js/custom/zvmUtils.js
@@ -5569,6 +5569,9 @@ function loadOSImages(col) {
$(this).children('input:radio').attr('checked', 'checked');
$(this).parents('td').find('div').attr('class', 'ui-state-default');
$(this).attr('class', 'ui-state-active');
+
+ $('#select-table tbody tr:eq(0) td:eq(3) input[name="master"]').attr('checked', '');
+ $('#select-table tbody tr:eq(0) td:eq(3) input[name="master"]').parents('td').find('div').attr('class', 'ui-state-default');
});
radio = $('').css('display', 'none');
imgBlock.append(radio, $('' + name + ': ' + desc + ''));
@@ -5581,6 +5584,60 @@ function loadOSImages(col) {
}
}
+/**
+ * Load golden images into column
+ *
+ * @param col Table column where master copies will be placed
+ */
+function loadGoldenImages(col) {
+ // Get group names and description and append to group column
+ if (!$.cookie('srv_goldenimages')) {
+ var infoBar = createInfoBar('No selectable master copies available');
+ col.append(infoBar);
+ return;
+ }
+
+ var imgNames = $.cookie('srv_goldenimages').split(',');
+
+ var imgBlock, radio, args, name, desc;
+ for (var i in imgNames) {
+ args = imgNames[i].split(':');
+ name = args[0];
+ desc = args[1];
+
+ // Create block for each image
+ imgBlock = $('').css({
+ 'border': '1px solid',
+ 'max-width': '200px',
+ 'margin': '5px auto',
+ 'padding': '5px',
+ 'display': 'block',
+ 'vertical-align': 'middle',
+ 'cursor': 'pointer',
+ 'white-space': 'normal'
+ }).click(function(){
+ $(this).children('input:radio').attr('checked', 'checked');
+ $(this).parents('td').find('div').attr('class', 'ui-state-default');
+ $(this).attr('class', 'ui-state-active');
+
+ // Un-select zVM and image
+ $('#select-table tbody tr:eq(0) td:eq(2) input[name="image"]').attr('checked', '');
+ $('#select-table tbody tr:eq(0) td:eq(2) input[name="image"]').parents('td').find('div').attr('class', 'ui-state-default');
+
+ $('#select-table tbody tr:eq(0) td:eq(0) input[name="hcp"]').attr('checked', '');
+ $('#select-table tbody tr:eq(0) td:eq(0) input[name="hcp"]').parents('td').find('div').attr('class', 'ui-state-default');
+ });
+ radio = $('').css('display', 'none');
+ imgBlock.append(radio, $('' + name + ': ' + desc + ''));
+ imgBlock.children('span').css({
+ 'display': 'block',
+ 'margin': '5px',
+ 'text-align': 'left'
+ });
+ col.append(imgBlock);
+ }
+}
+
/**
* Set a cookie for zVM host names (service page)
*
@@ -5603,6 +5660,28 @@ function setzVMCookies(data) {
}
}
+/**
+ * Set a cookie for master copies (service page)
+ *
+ * @param data Data from HTTP request
+ */
+function setGoldenImagesCookies(data) {
+ if (data.rsp[0].length) {
+ var copies = new Array();
+ var tmp = data.rsp[0].split(",");
+ for ( var i = 0; i < tmp.length; i++) {
+ if (tmp[i] != null && tmp[i] != "") {
+ copies.push(tmp[i]);
+ }
+ }
+
+ // Set cookie to expire in 60 minutes
+ var exDate = new Date();
+ exDate.setTime(exDate.getTime() + (240 * 60 * 1000));
+ $.cookie('srv_goldenimages', copies, { expires: exDate });
+ }
+}
+
/**
* Set a cookie for disk pool names of a given node
*
diff --git a/xCAT-UI/js/service/service.js b/xCAT-UI/js/service/service.js
index 4d60e2e5e..c25b24def 100644
--- a/xCAT-UI/js/service/service.js
+++ b/xCAT-UI/js/service/service.js
@@ -239,22 +239,38 @@ function loadServiceProvisionPage(tabId) {
title = 'z/VM';
// Get zVM host names
- if (!$.cookie('zvms')){
- $.ajax( {
- url : 'lib/srv_cmd.php',
- dataType : 'json',
- data : {
- cmd : 'webportal',
- tgt : '',
- args : 'lszvm',
- msg : ''
- },
+ $.ajax({
+ url : 'lib/srv_cmd.php',
+ dataType : 'json',
+ async : false,
+ data : {
+ cmd : 'webportal',
+ tgt : '',
+ args : 'lszvm',
+ msg : ''
+ },
- success : function(data) {
- setzVMCookies(data);
- }
- });
- }
+ success : function(data) {
+ setzVMCookies(data);
+ }
+ });
+
+ // Get master copies for clone
+ $.ajax({
+ url : 'lib/srv_cmd.php',
+ dataType : 'json',
+ async : false,
+ data : {
+ cmd : 'webportal',
+ tgt : '',
+ args : 'lsgoldenimages',
+ msg : ''
+ },
+
+ success : function(data) {
+ setGoldenImagesCookies(data);
+ }
+ });
break;
}
@@ -1077,11 +1093,27 @@ function setUserNodes(data) {
// where column names are: node, os, arch, profile, provmethod, supportedarchs, nodetype, comments, disable
var cols = data.rsp[i].split(',');
var node = cols[0].replace(new RegExp('"', 'g'), '');
- var owner = cols[7].replace(new RegExp('"', 'g'), '');
- owner = owner.replace('owner:', '');
- if (owner == userName) {
- usrNodes.push(node);
+ // Comments can contain the owner and description
+ var comments = new Array();
+ if (cols[7].indexOf(';') > -1) {
+ comments = cols[7].replace(new RegExp('"', 'g'), '').split(';');
+ } else {
+ comments.push(cols[7].replace(new RegExp('"', 'g'), ''));
+ }
+
+ // Extract the owner
+ var owner;
+ for (var j in comments) {
+ if (comments[j].indexOf('owner:') > -1) {
+ owner = comments[j].replace('owner:', '');
+
+ if (owner == userName) {
+ usrNodes.push(node);
+ }
+
+ break;
+ }
}
} // End of for
diff --git a/xCAT-UI/lib/functions.php b/xCAT-UI/lib/functions.php
index 1fd1f97cc..a29856934 100644
--- a/xCAT-UI/lib/functions.php
+++ b/xCAT-UI/lib/functions.php
@@ -93,7 +93,7 @@ function submit_request($req, $skipVerify, $opts_array){
syslog(LOG_INFO, "Sending request: $cmd $nr");
stream_set_blocking($fp, 0); // Set as non-blocking
fwrite($fp,$req->asXML()); // Send XML to xcatd
- set_time_limit(900); // Set 15 minutes timeout (for long running requests)
+ set_time_limit(3600); // Set 15 minutes timeout (for long running requests)
// The default is 30 seconds which is too short for some requests
// Turn on output buffering
diff --git a/xCAT-UI/lib/srv_functions.php b/xCAT-UI/lib/srv_functions.php
index c18a336fb..6dafe540e 100644
--- a/xCAT-UI/lib/srv_functions.php
+++ b/xCAT-UI/lib/srv_functions.php
@@ -91,7 +91,7 @@ function submit_request($req, $skipVerify, $opts_array){
syslog(LOG_INFO, "Sending request: $cmd $nr");
stream_set_blocking($fp, 0); // Set as non-blocking
fwrite($fp,$req->asXML()); // Send XML to xcatd
- set_time_limit(900); // Set 15 minutes timeout (for long running requests)
+ set_time_limit(3600); // Set 15 minutes timeout (for long running requests)
// The default is 30 seconds which is too short for some requests
// Turn on output buffering
diff --git a/xCAT-UI/xcat/plugins/webportal.pm b/xCAT-UI/xcat/plugins/webportal.pm
index 3cf3d5437..22b79f3c8 100644
--- a/xCAT-UI/xcat/plugins/webportal.pm
+++ b/xCAT-UI/xcat/plugins/webportal.pm
@@ -40,7 +40,8 @@ sub process_request {
'clonezlinux' => \&clonezlinux,
'genhostip' => \&genhostip,
'getmaxvm' => \&getmaxvm,
- 'getuserprivilege' => \&getuserprivilege
+ 'getuserprivilege' => \&getuserprivilege,
+ 'lsgoldenimages' => \&lsgoldenimages
);
# Check if the request is authorized
@@ -214,12 +215,13 @@ sub provzlinux {
# Create VM
# e.g. webportal provzlinux [group] [hcp] [image]
- my ($node, $ip, $base_digit) = gennodename( $callback, $group );
- if (!$base_digit) {
- println( $callback, "(Error) Failed to generate node name" );
+ # my ($node, $ip, $base_digit) = gennodename( $callback, $group );
+ my ($node, $ip, $hostname) = findfreenode( $callback, $group );
+ if (!$node) {
+ println( $callback, "Unable to find a free node, IP, and hostname for $group from the IP pool" );
return;
}
-
+
my $userid = $node;
# Set node definitions
@@ -231,9 +233,9 @@ sub provzlinux {
$out = `mkdef -t node -o $node userid=$userid hcp=$hcp mgt=zvm groups=$group,all`;
}
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"`;
+ $out = `chtab node=$node hosts.ip=$ip hosts.hostnames=$hostname noderes.netboot=zvm nodetype.nodetype=osi nodetype.provmethod=install nodetype.os=$os nodetype.arch=$arch nodetype.profile=$profile nodetype.comments="owner:$owner"`;
# Create user directory entry replacing LXUSR with user ID
# Use /opt/zhcp/conf/default.direct on zHCP as the template
@@ -673,7 +675,13 @@ sub clonezlinux {
# Create VM
# e.g. webportal provzlinux [group] [hcp] [image]
- my ($node, $ip, $base_digit) = gennodename( $callback, $group );
+ # my ($node, $ip, $base_digit) = gennodename( $callback, $group );
+ my ($node, $ip, $hostname) = findfreenode( $callback, $group );
+ if (!$node) {
+ println( $callback, "Unable to find a free node, IP, and hostname for $group from the IP pool" );
+ return;
+ }
+
my $userid = $node;
# Set node definitions
@@ -681,7 +689,7 @@ sub clonezlinux {
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"`;
+ $out = `chtab node=$node hosts.ip=$ip hosts.hostnames=$hostname 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
sleep(5); # Time needed to update /etc/hosts
@@ -715,8 +723,9 @@ sub genhostip {
my ( $request, $callback, $sub_req ) = @_;
my $group = $request->{arg}->[1];
- my ($node, $ip, $base_digit) = gennodename( $callback, $group );
- println( $callback, "$node: $ip" );
+ # my ($node, $ip, $base_digit) = gennodename( $callback, $group );
+ my ($node, $ip, $hostname) = findfreenode( $callback, $group );
+ println( $callback, "$node: $ip, $hostname" );
}
sub getmaxvm {
@@ -781,4 +790,86 @@ sub getuserprivilege {
$callback->( { data => "Privilege: $privilege" } );
}
+
+sub lsgoldenimages {
+ my ( $request, $callback, $sub_req ) = @_;
+
+ # Find the golden image that can be cloned by searching nodetype table for nodetype.provmethod=clone
+ my $clones = "";
+ my $comments = "";
+ my $description = "";
+ my @args;
+
+ # Look in 'policy' table
+ my $tab = xCAT::Table->new( 'nodetype', -create => 1, -autocommit => 0 );
+ my @results = $tab->getAllAttribsWhere( "provmethod='clone'", 'node', 'comments' );
+ foreach (@results) {
+ if ($_->{'node'}) {
+ $clones .= $_->{'node'} . ": ";
+
+ $comments = $_->{'comments'};
+ @args = split(';', $comments);
+ foreach (@args) {
+ if ($_ =~ m/description:/i) {
+ $description = $_;
+ $description =~ s/description://g;
+ $description =~ s/\s*$//; # Trim right
+ $description =~ s/^\s*//; # Trim left
+ } else {
+ $description = "No comments";
+ }
+ }
+
+ $clones .= $description . ",";
+ }
+ }
+
+ # Delete last comma
+ $clones = substr($clones, 0, -1);
+
+ $callback->( { data => $clones } );
+}
+
+sub findfreenode {
+ # Generate node name based on given group
+ my ( $callback, $group ) = @_;
+
+ # IP pool contained in /var/opt/xcat/ippool where a file exists per group
+ if ( !(`test -e /var/opt/xcat/ippool/$group.pool && echo Exists`) ) {
+ return;
+ }
+
+ # IP pool group format: node, IP, hostname
+ # It would look similar to:
+ # ihost10,10.1.136.10,ihost10.endicott.ibm.com
+ # ihost11,10.1.136.11,ihost11.endicott.ibm.com
+ # ihost12,10.1.136.12,ihost12.endicott.ibm.com
+ my $node;
+ my $ipaddr;
+ my $hostname;
+
+ my $out = `cat /var/opt/xcat/ippool/$group.pool | sed 1d`;
+ my @entries = split( /\n/, $out );
+ if (@entries < 1) {
+ return;
+ }
+
+ my $found = 0;
+ foreach(@entries) {
+ # Grab the 1st free entry found
+ ($node, $ipaddr, $hostname) = split(/,/, $_);
+ if ($node && $ipaddr && $hostname) {
+
+ # Check against xCAT tables, /etc/hosts, and ping to see if hostname is already used
+ if (`nodels $node` || `cat /etc/hosts | grep "$ipaddr "` || !(`ping -c 4 $ipaddr` =~ m/100% packet loss/)) {
+ next;
+ } else {
+ $found = 1;
+ return ($node, $ipaddr, $hostname);
+ }
+ }
+ }
+
+ return;
+}
1;
\ No newline at end of file
diff --git a/xCAT-server/lib/xcat/plugins/zvm.pm b/xCAT-server/lib/xcat/plugins/zvm.pm
index f1afe596c..84103deea 100644
--- a/xCAT-server/lib/xcat/plugins/zvm.pm
+++ b/xCAT-server/lib/xcat/plugins/zvm.pm
@@ -4793,20 +4793,16 @@ sub nodeSet {
@propNames = ( 'nfsserver', 'xcatmaster' );
$propVals = xCAT::zvmUtils->getNodeProps( 'noderes', $node, @propNames );
- my $nfs = $propVals->{'nfsserver'};
+ my $repo = $propVals->{'nfsserver'}; # Repository containing Linux ISO
my $xcatmaster = $propVals->{'xcatmaster'};
# Use noderes.xcatmaster instead of site.master if it is given
if ( $xcatmaster ) {
$master = $xcatmaster;
}
-
- if ( !$nfs ) {
- $nfs = $master;
- }
-
+
# Combine NFS server and installation directory, e.g. 10.0.0.1/install
- $nfs .= $installDir;
+ my $nfs = $master . $installDir;
# Get broadcast address of NIC
my $ifcfg = xCAT::zvmUtils->getIfcfgByNic( $::SUDOER, $hcp, $readChannel );
@@ -5025,6 +5021,10 @@ END
# Install=ftp://10.0.0.1/sles10.2/s390x/1/
# UseVNC=1 VNCPassword=12345678
# InstNetDev=osa OsaInterface=qdio OsaMedium=eth Manual=0
+ if (!$repo) {
+ $repo = "http://$nfs/$os/s390x/1/";
+ }
+
my $ay = "http://$nfs/custom/install/sles/" . $node . "." . $profile . ".tmpl";
$parms = $parmHeader . "\n";
@@ -5041,7 +5041,7 @@ END
$parms = $parms . "ReadChannel=$readChannel WriteChannel=$writeChannel DataChannel=$dataChannel\n";
$parms = $parms . "Nameserver=$nameserver Portname=$portName Portno=0\n";
- $parms = $parms . "Install=http://$nfs/$os/s390x/1/\n";
+ $parms = $parms . "Install=$repo\n";
$parms = $parms . "UseVNC=1 VNCPassword=12345678\n";
$parms = $parms . "InstNetDev=$instNetDev OsaInterface=$osaInterface OsaMedium=$osaMedium Manual=0\n";
@@ -5136,9 +5136,12 @@ END
$out = `sed --in-place -e "/%post/r $postScript" $customTmpl`;
# Edit template
- my $url = "http://$nfs/$os/s390x/";
+ if (!$repo) {
+ $repo = "http://$nfs/$os/s390x/";
+ }
+
$out =
-`sed --in-place -e "s,replace_url,$url,g" \ -e "s,replace_ip,$hostIP,g" \ -e "s,replace_netmask,$mask,g" \ -e "s,replace_gateway,$gateway,g" \ -e "s,replace_nameserver,$nameserver,g" \ -e "s,replace_hostname,$hostname,g" \ -e "s,replace_rootpw,$passwd,g" \ -e "s,replace_master,$master,g" \ -e "s,replace_install_dir,$installDir,g" $customTmpl`;
+`sed --in-place -e "s,replace_url,$repo,g" \ -e "s,replace_ip,$hostIP,g" \ -e "s,replace_netmask,$mask,g" \ -e "s,replace_gateway,$gateway,g" \ -e "s,replace_nameserver,$nameserver,g" \ -e "s,replace_hostname,$hostname,g" \ -e "s,replace_rootpw,$passwd,g" \ -e "s,replace_master,$master,g" \ -e "s,replace_install_dir,$installDir,g" $customTmpl`;
# Attach SCSI FCP devices (if any)
# Go through each pool