8650 lines
320 KiB
Perl
8650 lines
320 KiB
Perl
# IBM(c) 2013 EPL license http://www.eclipse.org/legal/epl-v10.html
|
|
#-------------------------------------------------------
|
|
|
|
=head1
|
|
|
|
xCAT plugin to support z/VM (s390x)
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
package xCAT_plugin::zvm;
|
|
use xCAT::Client;
|
|
use xCAT::zvmUtils;
|
|
use xCAT::zvmCPUtils;
|
|
use xCAT::MsgUtils;
|
|
use Sys::Hostname;
|
|
use xCAT::Table;
|
|
use xCAT::Utils;
|
|
use xCAT::TableUtils;
|
|
use xCAT::ServiceNodeUtils;
|
|
use xCAT::NetworkUtils;
|
|
use XML::Simple;
|
|
use File::Basename;
|
|
use File::Copy;
|
|
use File::Path;
|
|
use Time::HiRes;
|
|
use POSIX;
|
|
use Getopt::Long;
|
|
use strict;
|
|
|
|
# If the following line is not included, you get:
|
|
# /opt/xcat/lib/perl/xCAT_plugin/zvm.pm did not return a true value
|
|
1;
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 handled_commands
|
|
|
|
Return list of commands handled by this plugin
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
sub handled_commands {
|
|
return {
|
|
rpower => 'nodehm:power,mgt',
|
|
rinv => 'nodehm:mgt',
|
|
mkvm => 'nodehm:mgt',
|
|
rmvm => 'nodehm:mgt',
|
|
lsvm => 'nodehm:mgt',
|
|
chvm => 'nodehm:mgt',
|
|
rscan => 'nodehm:mgt',
|
|
nodeset => 'noderes:netboot',
|
|
getmacs => 'nodehm:getmac,mgt',
|
|
rnetboot => 'nodehm:mgt',
|
|
rmigrate => 'nodehm:mgt',
|
|
chhypervisor => ['hypervisor:type', 'nodetype:os=(zvm.*)'],
|
|
revacuate => 'hypervisor:type',
|
|
reventlog => 'nodehm:mgt',
|
|
};
|
|
}
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 preprocess_request
|
|
|
|
Check and setup for hierarchy
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
sub preprocess_request {
|
|
my $req = shift;
|
|
my $callback = shift;
|
|
|
|
# Hash array
|
|
my %sn;
|
|
|
|
# Scalar variable
|
|
my $sn;
|
|
|
|
# Array
|
|
my @requests;
|
|
|
|
# If already preprocessed, go straight to request
|
|
if ( $req->{_xcatpreprocessed}->[0] == 1 ) {
|
|
return [$req];
|
|
}
|
|
my $nodes = $req->{node};
|
|
my $service = "xcat";
|
|
|
|
# Find service nodes for requested nodes
|
|
# Build an individual request for each service node
|
|
if ($nodes) {
|
|
$sn = xCAT::ServiceNodeUtils->get_ServiceNode( $nodes, $service, "MN" );
|
|
|
|
# Build each request for each service node
|
|
foreach my $snkey ( keys %$sn ) {
|
|
my $n = $sn->{$snkey};
|
|
print "snkey=$snkey, nodes=@$n\n";
|
|
my $reqcopy = {%$req};
|
|
$reqcopy->{node} = $sn->{$snkey};
|
|
$reqcopy->{'_xcatdest'} = $snkey;
|
|
$reqcopy->{_xcatpreprocessed}->[0] = 1;
|
|
push @requests, $reqcopy;
|
|
}
|
|
|
|
return \@requests;
|
|
}
|
|
else {
|
|
|
|
# Input error
|
|
my %rsp;
|
|
my $rsp;
|
|
$rsp->{data}->[0] = "Input noderange missing. Useage: zvm <noderange> \n";
|
|
xCAT::MsgUtils->message( "I", $rsp, $callback, 0 );
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 process_request
|
|
|
|
Process the command. This is the main call.
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
sub process_request {
|
|
my $request = shift;
|
|
my $callback = shift;
|
|
my $nodes = $request->{node};
|
|
my $command = $request->{command}->[0];
|
|
my $args = $request->{arg};
|
|
my $envs = $request->{env};
|
|
$::STDIN = $request->{stdin}->[0];
|
|
my %rsp;
|
|
my $rsp;
|
|
my @nodes = @$nodes;
|
|
my $host = hostname();
|
|
|
|
# Directory where executables are on zHCP
|
|
$::DIR = "/opt/zhcp/bin";
|
|
|
|
# Directory where system config is on zHCP
|
|
$::SYSCONF = "/opt/zhcp/conf";
|
|
|
|
# Directory where zFCP disk pools are on zHCP
|
|
$::ZFCPPOOL = "/var/opt/zhcp/zfcp";
|
|
|
|
# Use sudo or not
|
|
# This looks in the passwd table for a key = sudoer
|
|
($::SUDOER, $::SUDO) = xCAT::zvmUtils->getSudoer();
|
|
|
|
# Process ID for xfork()
|
|
my $pid;
|
|
|
|
# Child process IDs
|
|
my @children;
|
|
|
|
#*** Power on or off a node ***
|
|
if ( $command eq "rpower" ) {
|
|
foreach (@nodes) {
|
|
$pid = xCAT::Utils->xfork();
|
|
|
|
# Parent process
|
|
if ($pid) {
|
|
push( @children, $pid );
|
|
}
|
|
|
|
# Child process
|
|
elsif ( $pid == 0 ) {
|
|
powerVM( $callback, $_, $args );
|
|
|
|
# Exit process
|
|
exit(0);
|
|
}
|
|
else {
|
|
|
|
# Ran out of resources
|
|
die "Error: Could not fork\n";
|
|
}
|
|
|
|
# Handle 10 nodes at a time, else you will get errors
|
|
if ( !( @children % 10 ) ) {
|
|
|
|
# Wait for all processes to end
|
|
foreach (@children) {
|
|
waitpid( $_, 0 );
|
|
}
|
|
|
|
# Clear children
|
|
@children = ();
|
|
}
|
|
} # End of foreach
|
|
} # End of case
|
|
|
|
#*** Hardware and software inventory ***
|
|
elsif ( $command eq "rinv" ) {
|
|
foreach (@nodes) {
|
|
$pid = xCAT::Utils->xfork();
|
|
|
|
# Parent process
|
|
if ($pid) {
|
|
push( @children, $pid );
|
|
}
|
|
|
|
# Child process
|
|
elsif ( $pid == 0 ) {
|
|
if (xCAT::zvmUtils->isHypervisor($_)) {
|
|
inventoryHypervisor( $callback, $_, $args );
|
|
} else {
|
|
inventoryVM( $callback, $_, $args );
|
|
}
|
|
|
|
# Exit process
|
|
exit(0);
|
|
}
|
|
else {
|
|
|
|
# Ran out of resources
|
|
die "Error: Could not fork\n";
|
|
}
|
|
|
|
} # End of foreach
|
|
} # End of case
|
|
|
|
#*** Migrate a virtual machine ***
|
|
elsif ( $command eq "rmigrate" ) {
|
|
foreach (@nodes) {
|
|
$pid = xCAT::Utils->xfork();
|
|
|
|
# Parent process
|
|
if ($pid) {
|
|
push( @children, $pid );
|
|
}
|
|
|
|
# Child process
|
|
elsif ( $pid == 0 ) {
|
|
migrateVM( $callback, $_, $args );
|
|
|
|
# Exit process
|
|
exit(0);
|
|
}
|
|
else {
|
|
|
|
# Ran out of resources
|
|
die "Error: Could not fork\n";
|
|
}
|
|
|
|
} # End of foreach
|
|
} # End of case
|
|
|
|
#*** Evacuate all virtual machines off a hypervisor ***
|
|
elsif ( $command eq "revacuate" ) {
|
|
foreach (@nodes) {
|
|
$pid = xCAT::Utils->xfork();
|
|
|
|
# Parent process
|
|
if ($pid) {
|
|
push( @children, $pid );
|
|
}
|
|
|
|
# Child process
|
|
elsif ( $pid == 0 ) {
|
|
evacuate( $callback, $_, $args );
|
|
|
|
# Exit process
|
|
exit(0);
|
|
}
|
|
else {
|
|
|
|
# Ran out of resources
|
|
die "Error: Could not fork\n";
|
|
}
|
|
|
|
} # End of foreach
|
|
} # End of case
|
|
|
|
#*** Create a virtual server ***
|
|
elsif ( $command eq "mkvm" ) {
|
|
|
|
# Determine if the argument is a node
|
|
my $clone = 0;
|
|
if ( $args->[0] ) {
|
|
$clone = xCAT::zvmUtils->isZvmNode( $args->[0] );
|
|
}
|
|
|
|
#*** Clone virtual server ***
|
|
if ( $clone ) {
|
|
cloneVM( $callback, \@nodes, $args );
|
|
}
|
|
|
|
#*** Create user entry ***
|
|
# Create node based on directory entry
|
|
# or create a NOLOG if no entry is provided
|
|
else {
|
|
foreach (@nodes) {
|
|
$pid = xCAT::Utils->xfork();
|
|
|
|
# Parent process
|
|
if ($pid) {
|
|
push( @children, $pid );
|
|
}
|
|
|
|
# Child process
|
|
elsif ( $pid == 0 ) {
|
|
|
|
makeVM( $callback, $_, $args );
|
|
|
|
# Exit process
|
|
exit(0);
|
|
} # End of elsif
|
|
else {
|
|
|
|
# Ran out of resources
|
|
die "Error: Could not fork\n";
|
|
}
|
|
} # End of foreach
|
|
} # End of else
|
|
} # End of case
|
|
|
|
#*** Remove a virtual server ***
|
|
elsif ( $command eq "rmvm" ) {
|
|
foreach (@nodes) {
|
|
$pid = xCAT::Utils->xfork();
|
|
|
|
# Parent process
|
|
if ($pid) {
|
|
push( @children, $pid );
|
|
}
|
|
|
|
# Child process
|
|
elsif ( $pid == 0 ) {
|
|
removeVM( $callback, $_ );
|
|
|
|
# Exit process
|
|
exit(0);
|
|
}
|
|
else {
|
|
|
|
# Ran out of resources
|
|
die "Error: Could not fork\n";
|
|
}
|
|
|
|
# Handle 10 nodes at a time, else you will get errors
|
|
if ( !( @children % 10 ) ) {
|
|
|
|
# Wait for all processes to end
|
|
foreach (@children) {
|
|
waitpid( $_, 0 );
|
|
}
|
|
|
|
# Clear children
|
|
@children = ();
|
|
}
|
|
} # End of foreach
|
|
} # End of case
|
|
|
|
#*** Print the user entry ***
|
|
elsif ( $command eq "lsvm" ) {
|
|
foreach (@nodes) {
|
|
$pid = xCAT::Utils->xfork();
|
|
|
|
# Parent process
|
|
if ($pid) {
|
|
push( @children, $pid );
|
|
}
|
|
|
|
# Child process
|
|
elsif ( $pid == 0 ) {
|
|
listVM( $callback, $_, $args );
|
|
|
|
# Exit process
|
|
exit(0);
|
|
}
|
|
else {
|
|
|
|
# Ran out of resources
|
|
die "Error: Could not fork\n";
|
|
}
|
|
|
|
# Handle 10 nodes at a time, else you will get errors
|
|
if ( !( @children % 10 ) ) {
|
|
|
|
# Wait for all processes to end
|
|
foreach (@children) {
|
|
waitpid( $_, 0 );
|
|
}
|
|
|
|
# Clear children
|
|
@children = ();
|
|
}
|
|
} # End of foreach
|
|
} # End of case
|
|
|
|
#*** Change the user entry ***
|
|
elsif ( $command eq "chvm" ) {
|
|
foreach (@nodes) {
|
|
$pid = xCAT::Utils->xfork();
|
|
|
|
# Parent process
|
|
if ($pid) {
|
|
push( @children, $pid );
|
|
}
|
|
|
|
# Child process
|
|
elsif ( $pid == 0 ) {
|
|
changeVM( $callback, $_, $args );
|
|
|
|
# Exit process
|
|
exit(0);
|
|
}
|
|
else {
|
|
|
|
# Ran out of resources
|
|
die "Error: Could not fork\n";
|
|
}
|
|
|
|
# Handle 10 nodes at a time, else you will get errors
|
|
if ( !( @children % 10 ) ) {
|
|
|
|
# Wait for all processes to end
|
|
foreach (@children) {
|
|
waitpid( $_, 0 );
|
|
}
|
|
|
|
# Clear children
|
|
@children = ();
|
|
}
|
|
} # End of foreach
|
|
} # End of case
|
|
|
|
#*** Collect node information from zHCP ***
|
|
elsif ( $command eq "rscan" ) {
|
|
foreach (@nodes) {
|
|
$pid = xCAT::Utils->xfork();
|
|
|
|
# Parent process
|
|
if ($pid) {
|
|
push( @children, $pid );
|
|
}
|
|
|
|
# Child process
|
|
elsif ( $pid == 0 ) {
|
|
scanVM( $callback, $_, $args );
|
|
|
|
# Exit process
|
|
exit(0);
|
|
}
|
|
else {
|
|
|
|
# Ran out of resources
|
|
die "Error: Could not fork\n";
|
|
}
|
|
|
|
} # End of foreach
|
|
} # End of case
|
|
|
|
#*** Set the boot state for a node ***
|
|
elsif ( $command eq "nodeset" ) {
|
|
foreach (@nodes) {
|
|
|
|
# Only one file can be punched to reader at a time
|
|
# Forking this process is not possible
|
|
nodeSet( $callback, $_, $args );
|
|
|
|
} # End of foreach
|
|
} # End of case
|
|
|
|
#*** Get the MAC address of a node ***
|
|
elsif ( $command eq "getmacs" ) {
|
|
foreach (@nodes) {
|
|
$pid = xCAT::Utils->xfork();
|
|
|
|
# Parent process
|
|
if ($pid) {
|
|
push( @children, $pid );
|
|
}
|
|
|
|
# Child process
|
|
elsif ( $pid == 0 ) {
|
|
getMacs( $callback, $_, $args );
|
|
|
|
# Exit process
|
|
exit(0);
|
|
}
|
|
else {
|
|
|
|
# Ran out of resources
|
|
die "Error: Could not fork\n";
|
|
}
|
|
|
|
} # End of foreach
|
|
} # End of case
|
|
|
|
#*** Boot from network ***
|
|
elsif ( $command eq "rnetboot" ) {
|
|
foreach (@nodes) {
|
|
$pid = xCAT::Utils->xfork();
|
|
|
|
# Parent process
|
|
if ($pid) {
|
|
push( @children, $pid );
|
|
}
|
|
|
|
# Child process
|
|
elsif ( $pid == 0 ) {
|
|
netBoot( $callback, $_, $args );
|
|
|
|
# Exit process
|
|
exit(0);
|
|
}
|
|
else {
|
|
|
|
# Ran out of resources
|
|
die "Error: Could not fork\n";
|
|
}
|
|
|
|
# Handle 10 nodes at a time, else you will get errors
|
|
if ( !( @children % 10 ) ) {
|
|
|
|
# Wait for all processes to end
|
|
foreach (@children) {
|
|
waitpid( $_, 0 );
|
|
}
|
|
|
|
# Clear children
|
|
@children = ();
|
|
}
|
|
} # End of foreach
|
|
} # End of case
|
|
|
|
#*** Configure the virtualization hosts ***
|
|
elsif ( $command eq "chhypervisor" ) {
|
|
foreach (@nodes) {
|
|
$pid = xCAT::Utils->xfork();
|
|
|
|
# Parent process
|
|
if ($pid) {
|
|
push( @children, $pid );
|
|
}
|
|
|
|
# Child process
|
|
elsif ( $pid == 0 ) {
|
|
changeHypervisor( $callback, $_, $args );
|
|
|
|
# Exit process
|
|
exit(0);
|
|
}
|
|
else {
|
|
|
|
# Ran out of resources
|
|
die "Error: Could not fork\n";
|
|
}
|
|
|
|
# Handle 10 nodes at a time, else you will get errors
|
|
if ( !( @children % 10 ) ) {
|
|
|
|
# Wait for all processes to end
|
|
foreach (@children) {
|
|
waitpid( $_, 0 );
|
|
}
|
|
|
|
# Clear children
|
|
@children = ();
|
|
}
|
|
} # End of foreach
|
|
} # End of case
|
|
|
|
#*** Retrieve or clear event logs ***
|
|
elsif ( $command eq "reventlog" ) {
|
|
foreach (@nodes) {
|
|
$pid = xCAT::Utils->xfork();
|
|
|
|
# Parent process
|
|
if ($pid) {
|
|
push( @children, $pid );
|
|
}
|
|
|
|
# Child process
|
|
elsif ( $pid == 0 ) {
|
|
eventLog( $callback, $_, $args );
|
|
|
|
# Exit process
|
|
exit(0);
|
|
}
|
|
else {
|
|
|
|
# Ran out of resources
|
|
die "Error: Could not fork\n";
|
|
}
|
|
|
|
} # End of foreach
|
|
} # End of case
|
|
|
|
#*** Update the node (no longer supported) ***
|
|
elsif ( $command eq "updatenode" ) {
|
|
foreach (@nodes) {
|
|
$pid = xCAT::Utils->xfork();
|
|
|
|
# Parent process
|
|
if ($pid) {
|
|
push( @children, $pid );
|
|
}
|
|
|
|
# Child process
|
|
elsif ( $pid == 0 ) {
|
|
updateNode( $callback, $_, $args );
|
|
|
|
# Exit process
|
|
exit(0);
|
|
}
|
|
else {
|
|
|
|
# Ran out of resources
|
|
die "Error: Could not fork\n";
|
|
}
|
|
|
|
} # End of foreach
|
|
} # End of case
|
|
|
|
# Wait for all processes to end
|
|
foreach (@children) {
|
|
waitpid( $_, 0 );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 removeVM
|
|
|
|
Description : Delete the user from user directory
|
|
Arguments : Node to remove
|
|
Returns : Nothing
|
|
Example : removeVM($callback, $node);
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
sub removeVM {
|
|
|
|
# Get inputs
|
|
my ( $callback, $node ) = @_;
|
|
|
|
# Get node properties from 'zvm' table
|
|
my @propNames = ( 'hcp', 'userid' );
|
|
my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
|
|
|
|
# Get zHCP
|
|
my $hcp = $propVals->{'hcp'};
|
|
if ( !$hcp ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing node HCP" );
|
|
return;
|
|
}
|
|
|
|
# Get node user ID
|
|
my $userId = $propVals->{'userid'};
|
|
if ( !$userId ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing user ID" );
|
|
return;
|
|
}
|
|
# Capitalize user ID
|
|
$userId =~ tr/a-z/A-Z/;
|
|
|
|
xCAT::zvmUtils->printSyslog("sudoer:$::SUDOER zHCP:$hcp sudo:$::SUDO");
|
|
|
|
# Power off user ID
|
|
my $out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Deactivate -T $userId -f IMMED"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Deactivate -T $userId -f IMMED");
|
|
|
|
# Delete user entry
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Delete_DM -T $userId -e 1"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Delete_DM -T $userId -e 1");
|
|
xCAT::zvmUtils->printLn( $callback, "$node: $out" );
|
|
|
|
# Check for errors
|
|
my $rc = xCAT::zvmUtils->checkOutput( $callback, $out );
|
|
if ( $rc == -1 ) {
|
|
return;
|
|
}
|
|
|
|
# Go through each pool and free zFCP devices belonging to node
|
|
my @pools = split("\n", `ssh $::SUDOER\@$hcp "$::SUDO ls $::ZFCPPOOL"`);
|
|
my $pool;
|
|
my @luns;
|
|
my $update;
|
|
my $expression;
|
|
foreach (@pools) {
|
|
$pool = xCAT::zvmUtils->replaceStr( $_, ".conf", "" );
|
|
|
|
@luns = split("\n", `ssh $::SUDOER\@$hcp "$::SUDO cat $::ZFCPPOOL/$_" | egrep -i $node`);
|
|
foreach (@luns) {
|
|
# Update entry: status,wwpn,lun,size,range,owner,channel,tag
|
|
my @info = split(',', $_);
|
|
$update = "free,$info[1],$info[2],$info[3],$info[4],,,";
|
|
$expression = "'s#" . $_ . "#" .$update . "#i'";
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO sed -i -e $expression $::ZFCPPOOL/$pool.conf"`;
|
|
}
|
|
|
|
if (@luns) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: Updating FCP device pool $pool... Done");
|
|
}
|
|
}
|
|
|
|
# Check for errors
|
|
$rc = xCAT::zvmUtils->checkOutput( $callback, $out );
|
|
if ( $rc == -1 ) {
|
|
return;
|
|
}
|
|
|
|
# Remove node from 'zvm', 'nodelist', 'nodetype', 'noderes', and 'nodehm' tables
|
|
# Save node entry in 'mac' table
|
|
xCAT::zvmUtils->delTabEntry( 'zvm', 'node', $node );
|
|
xCAT::zvmUtils->delTabEntry( 'hosts', 'node', $node );
|
|
xCAT::zvmUtils->delTabEntry( 'nodelist', 'node', $node );
|
|
xCAT::zvmUtils->delTabEntry( 'nodetype', 'node', $node );
|
|
xCAT::zvmUtils->delTabEntry( 'noderes', 'node', $node );
|
|
xCAT::zvmUtils->delTabEntry( 'nodehm', 'node', $node );
|
|
|
|
# Erase old hostname from known_hosts
|
|
$out = `ssh-keygen -R $node`;
|
|
|
|
# Erase hostname from /etc/hosts
|
|
$out = `sed -i /$node./d /etc/hosts`;
|
|
|
|
return;
|
|
}
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 changeVM
|
|
|
|
Description : Change a virtual machine's configuration
|
|
Arguments : Node
|
|
Option
|
|
Returns : Nothing
|
|
Example : changeVM($callback, $node, $args);
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
sub changeVM {
|
|
|
|
# Get inputs
|
|
my ( $callback, $node, $args ) = @_;
|
|
|
|
# Get node properties from 'zvm' table
|
|
my @propNames = ( 'hcp', 'userid' );
|
|
my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
|
|
|
|
# Get zHCP
|
|
my $hcp = $propVals->{'hcp'};
|
|
if ( !$hcp ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing node HCP" );
|
|
return;
|
|
}
|
|
|
|
# Get node user ID
|
|
my $userId = $propVals->{'userid'};
|
|
if ( !$userId ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing user ID" );
|
|
return;
|
|
}
|
|
# Capitalize user ID
|
|
$userId =~ tr/a-z/A-Z/;
|
|
|
|
# Get zHCP user ID
|
|
my $hcpUserId = xCAT::zvmCPUtils->getUserId($::SUDOER, $hcp);
|
|
$hcpUserId =~ tr/a-z/A-Z/;
|
|
|
|
xCAT::zvmUtils->printSyslog("sudoer:$::SUDOER zHCP:$hcp sudo:$::SUDO");
|
|
|
|
# Output string
|
|
my $out = "";
|
|
|
|
# add3390 [disk pool] [device address] [size] [mode] [read password (optional)] [write password (optional)] [multi password (optional)]
|
|
if ( $args->[0] eq "--add3390" ) {
|
|
my $pool = $args->[1];
|
|
my $addr = $args->[2];
|
|
my $cyl = $args->[3];
|
|
|
|
|
|
# If the user specifies auto as the device address, then find a free device address
|
|
if ($addr eq "auto") {
|
|
$addr = xCAT::zvmUtils->getFreeAddress($::SUDOER, $node, "smapi");
|
|
}
|
|
|
|
my $mode = "MR";
|
|
if ($args->[4]) {
|
|
$mode = $args->[4];
|
|
}
|
|
|
|
my $readPw = "''";
|
|
if ($args->[5]) {
|
|
$readPw = $args->[5];
|
|
}
|
|
|
|
my $writePw = "''";
|
|
if ($args->[6]) {
|
|
$writePw = $args->[6];
|
|
}
|
|
|
|
my $multiPw = "''";
|
|
if ($args->[7]) {
|
|
$multiPw = $args->[7];
|
|
}
|
|
|
|
# Convert to cylinders if size is given as M or G
|
|
# Otherwise, assume size is given in cylinders
|
|
# Note this is for a 4096 block size ECKD disk, where 737280 bytes = 1 cylinder
|
|
if ($cyl =~ m/M/i) {
|
|
$cyl =~ s/M//g;
|
|
$cyl = xCAT::zvmUtils->trimStr($cyl);
|
|
$cyl = sprintf("%.4f", $cyl);
|
|
$cyl = ($cyl * 1024 * 1024)/737280;
|
|
$cyl = ceil($cyl);
|
|
} elsif ($cyl =~ m/G/i) {
|
|
$cyl =~ s/G//g;
|
|
$cyl = xCAT::zvmUtils->trimStr($cyl);
|
|
$cyl = sprintf("%.4f", $cyl);
|
|
$cyl = ($cyl * 1024 * 1024 * 1024)/737280;
|
|
$cyl = ceil($cyl);
|
|
} elsif ($cyl =~ m/[a-zA-Z]/) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Size can be Megabytes (M), Gigabytes (G), or number of cylinders" );
|
|
return;
|
|
}
|
|
|
|
# Add to directory entry
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Disk_Create_DM -T $userId -v $addr -t 3390 -a AUTOG -r $pool -u 1 -z $cyl -m $mode -f 1 -R $readPw -W $writePw -M $multiPw"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Disk_Create_DM -T $userId -v $addr -t 3390 -a AUTOG -r $pool -u 1 -z $cyl -m $mode -f 1 -R $readPw -W $writePw -M $multiPw");
|
|
|
|
# Add to active configuration
|
|
my $ping = `/opt/xcat/bin/pping $node`;
|
|
if (!($ping =~ m/noping/i)) {
|
|
$out .= `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Disk_Create -T $userId -v $addr -m $mode"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Disk_Create -T $userId -v $addr -m $mode");
|
|
}
|
|
$out = xCAT::zvmUtils->appendHostname( $node, $out );
|
|
}
|
|
|
|
# add3390active [device address] [mode]
|
|
elsif ( $args->[0] eq "--add3390active" ) {
|
|
my $addr = $args->[1];
|
|
my $mode = $args->[2];
|
|
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Disk_Create -T $userId -v $addr -m $mode"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Disk_Create -T $userId -v $addr -m $mode");
|
|
$out = xCAT::zvmUtils->appendHostname( $node, $out );
|
|
}
|
|
|
|
# add9336 [disk pool] [virtual device address] [size] [mode] [read password (optional)] [write password (optional)] [multi password (optional)]
|
|
elsif ( $args->[0] eq "--add9336" ) {
|
|
my $pool = $args->[1];
|
|
my $addr = $args->[2];
|
|
my $blks = $args->[3];
|
|
|
|
# If the user specifies auto as the device address, then find a free device address
|
|
if ($addr eq "auto") {
|
|
$addr = xCAT::zvmUtils->getFreeAddress($::SUDOER, $node, "smapi");
|
|
}
|
|
|
|
my $mode = "MR";
|
|
if ($args->[4]) {
|
|
$mode = $args->[4];
|
|
}
|
|
|
|
my $readPw = "''";
|
|
if ($args->[5]) {
|
|
$readPw = $args->[5];
|
|
}
|
|
|
|
my $writePw = "''";
|
|
if ($args->[6]) {
|
|
$writePw = $args->[6];
|
|
}
|
|
|
|
my $multiPw = "''";
|
|
if ($args->[7]) {
|
|
$multiPw = $args->[7];
|
|
}
|
|
|
|
# Convert to blocks if size is given as M or G
|
|
# Otherwise, assume size is given in blocks
|
|
# Note this is for a 4096 block size ECKD disk, where 737280 bytes = 1 cylinder
|
|
if ($blks =~ m/M/i) {
|
|
$blks =~ s/M//g;
|
|
$blks = xCAT::zvmUtils->trimStr($blks);
|
|
$blks = sprintf("%.4f", $blks);
|
|
$blks = ($blks * 1024 * 1024)/512;
|
|
$blks = ceil($blks);
|
|
} elsif ($blks =~ m/G/i) {
|
|
$blks =~ s/G//g;
|
|
$blks = xCAT::zvmUtils->trimStr($blks);
|
|
$blks = sprintf("%.4f", $blks);
|
|
$blks = ($blks * 1024 * 1024 * 1024)/512;
|
|
$blks = ceil($blks);
|
|
} elsif ($blks =~ m/[a-zA-Z]/) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Size can be Megabytes (M), Gigabytes (G), or number of blocks" );
|
|
return;
|
|
}
|
|
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Disk_Create_DM -T $userId -v $addr -t 9336 -a AUTOG -r $pool -u 2 -z $blks -m $mode -f 1 -R $readPw -W $writePw -M $multiPw"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Disk_Create_DM -T $userId -v $addr -t 9336 -a AUTOG -r $pool -u 2 -z $blks -m $mode -f 1 -R $readPw -W $writePw -M $multiPw");
|
|
|
|
# Add to active configuration
|
|
my $ping = `/opt/xcat/bin/pping $node`;
|
|
if (!($ping =~ m/noping/i)) {
|
|
$out .= `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Disk_Create -T $userId -v $addr -m $mode"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Disk_Create -T $userId -v $addr -m $mode");
|
|
}
|
|
$out = xCAT::zvmUtils->appendHostname( $node, $out );
|
|
}
|
|
|
|
# adddisk2pool [function] [region] [volume] [group]
|
|
elsif ( $args->[0] eq "--adddisk2pool" ) {
|
|
# This is no longer supported in chvm. Using chhypervisor instead.
|
|
changeHypervisor( $callback, $node, $args );
|
|
}
|
|
|
|
# addzfcp2pool [pool] [status] [wwpn] [lun] [size] [owner (optional)]
|
|
elsif ( $args->[0] eq "--addzfcp2pool" ) {
|
|
# This is no longer supported in chvm. Using chhypervisor instead.
|
|
changeHypervisor( $callback, $node, $args );
|
|
}
|
|
|
|
# addnic [address] [type] [device count]
|
|
elsif ( $args->[0] eq "--addnic" ) {
|
|
my $addr = $args->[1];
|
|
my $type = $args->[2];
|
|
my $devcount = $args->[3];
|
|
|
|
# Add to active configuration
|
|
my $ping = `/opt/xcat/bin/pping $node`;
|
|
if (!($ping =~ m/noping/i)) {
|
|
$out = `ssh $::SUDOER\@$node "/sbin/vmcp define nic $addr type $type"`;
|
|
}
|
|
|
|
# Translate QDIO or Hipersocket into correct type
|
|
if ($type =~m/QDIO/i) {
|
|
$type = 2;
|
|
} elsif ($type =~m/HIPER/i) {
|
|
$type = 1;
|
|
}
|
|
|
|
# Add to directory entry
|
|
$out .= `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Virtual_Network_Adapter_Create_DM -T $userId -v $addr -a $type -n $devcount"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Virtual_Network_Adapter_Create_DM -T $userId -v $addr -a $type -n $devcount");
|
|
$out = xCAT::zvmUtils->appendHostname( $node, $out );
|
|
}
|
|
|
|
# addpagespool [vol_addr] [volume_label] [volume_use] [system_config_name (optional)] [system_config_type (optional)] [parm_disk_owner (optional)] [parm_disk_number (optional)] [parm_disk_password (optional)]
|
|
elsif ( $args->[0] eq "--addpagespool" ) {
|
|
my $argsSize = @{$args};
|
|
|
|
my $i;
|
|
my @options = ("", "vol_addr=", "volume_label=", "volume_use=", "system_config_name=", "system_config_type=", "parm_disk_owner=", "parm_disk_number=", "parm_disk_password=");
|
|
my $argStr = "";
|
|
foreach $i ( 1 .. $argsSize ) {
|
|
if ( $args->[$i] ) {
|
|
$argStr .= " -k $args->[$i]";
|
|
}
|
|
}
|
|
|
|
# Add a full volume page or spool disk to the system
|
|
$out .= `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Page_or_Spool_Volume_Add -T $userId $argStr"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Page_or_Spool_Volume_Add -T $userId $argStr");
|
|
$out = xCAT::zvmUtils->appendHostname( $node, $out );
|
|
}
|
|
|
|
# addprocessor [address]
|
|
elsif ( $args->[0] eq "--addprocessor" ) {
|
|
my $addr = $args->[1];
|
|
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_CPU_Define_DM -T $userId -v $addr -b 0 -d 1 -y 0"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_CPU_Define_DM -T $userId -v $addr -b 0 -d 1 -y 0");
|
|
$out = xCAT::zvmUtils->appendHostname( $node, $out );
|
|
}
|
|
|
|
# addprocessoractive [address] [type]
|
|
elsif ( $args->[0] eq "--addprocessoractive" ) {
|
|
my $addr = $args->[1];
|
|
my $type = $args->[2];
|
|
|
|
$out = xCAT::zvmCPUtils->defineCpu( $::SUDOER, $node, $addr, $type );
|
|
$out = xCAT::zvmUtils->appendHostname( $node, $out );
|
|
}
|
|
|
|
# addvdisk [device address] [size]
|
|
elsif ( $args->[0] eq "--addvdisk" ) {
|
|
my $addr = $args->[1];
|
|
my $size = $args->[2];
|
|
my $mode = $args->[3];
|
|
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Disk_Create_DM -T $userId -v $addr -t FB-512 -a V-DISK -r NONE -u 2 -z $size -m $mode -f 0"`;
|
|
$out = xCAT::zvmUtils->appendHostname( $node, $out );
|
|
}
|
|
|
|
# addzfcp [pool] [device address (or auto)] [loaddev (0 or 1)] [size] [tag (optional)] [wwpn (optional)] [lun (optional)]
|
|
elsif ( $args->[0] eq "--addzfcp" ) {
|
|
my $argsSize = @{$args};
|
|
if ( ($argsSize != 5) && ($argsSize != 6) && ($argsSize != 8) ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Wrong number of parameters" );
|
|
return;
|
|
}
|
|
|
|
my $pool = lc($args->[1]);
|
|
my $device = $args->[2];
|
|
my $loaddev = int($args->[3]);
|
|
if ($loaddev != 0 && $loaddev != 1) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) The loaddev can be 0 or 1" );
|
|
return;
|
|
}
|
|
my $size = $args->[4];
|
|
# Tag specifies what to replace in the autoyast/kickstart template, e.g. $root_device$
|
|
# This argument is optional
|
|
my $tag = $args->[5];
|
|
|
|
# Check if WWPN and LUN are given
|
|
# WWPN can be given as a semi-colon separated list
|
|
my $wwpn = "";
|
|
my $lun = "";
|
|
my $useWwpnLun = 0;
|
|
if ($argsSize == 8) {
|
|
$useWwpnLun = 1;
|
|
$wwpn = $args->[6];
|
|
$lun = $args->[7];
|
|
}
|
|
|
|
# Find a suitable SCSI/FCP device in the zFCP storage pool
|
|
my %criteria;
|
|
my $resultsRef;
|
|
if ($useWwpnLun) {
|
|
%criteria = (
|
|
'status' => 'used',
|
|
'fcp' => $device,
|
|
'wwpn' => $wwpn,
|
|
'lun' => $lun,
|
|
'size' => $size,
|
|
'owner' => $node,
|
|
'tag' => $tag
|
|
);
|
|
$resultsRef = xCAT::zvmUtils->findAndUpdatezFcpPool($callback, $node, $::SUDOER, $hcp, $pool, \%criteria);
|
|
} else {
|
|
# Do not know the WWPN or LUN in this case
|
|
%criteria = (
|
|
'status' => 'used',
|
|
'fcp' => $device,
|
|
'size' => $size,
|
|
'owner' => $node,
|
|
'tag' => $tag
|
|
);
|
|
$resultsRef = xCAT::zvmUtils->findAndUpdatezFcpPool($callback, $node, $::SUDOER, $hcp, $pool, \%criteria);
|
|
}
|
|
|
|
my %results = %$resultsRef;
|
|
if ($results{'rc'} == -1) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Failed to add zFCP device");
|
|
return;
|
|
}
|
|
|
|
# Obtain the device assigned by xCAT
|
|
$device = $results{'fcp'};
|
|
$wwpn = $results{'wwpn'};
|
|
$lun = $results{'lun'};
|
|
|
|
# Get user directory entry
|
|
my $userEntry = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Query_DM -T $userId" | sed '\$d'`;
|
|
|
|
# Find DEDICATE statement in the entry (dedicate one if one does not exist)
|
|
my $dedicate = `echo "$userEntry" | egrep -i "DEDICATE $device"`;
|
|
if (!$dedicate) {
|
|
$out = `/opt/xcat/bin/chvm $node --dedicatedevice $device $device 0`;
|
|
xCAT::zvmUtils->printLn($callback, "$out");
|
|
if (xCAT::zvmUtils->checkOutput($callback, $out) == -1) {
|
|
# Exit if dedicate failed
|
|
return;
|
|
}
|
|
}
|
|
|
|
# Configure native SCSI/FCP inside node (if online)
|
|
my $cmd;
|
|
my $ping = `/opt/xcat/bin/pping $node`;
|
|
if (!($ping =~ m/noping/i)) {
|
|
# Add the dedicated device to the active config
|
|
# Ignore any errors since it might be already dedicated
|
|
$out = `ssh $::SUDOER\@$node "$::SUDO $::DIR/smcli Image_Device_Dedicate -T $userId -v $device -r $device -R MR"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Device_Dedicate -T $userId -v $device -r $device -R MR");
|
|
|
|
# Online device
|
|
$out = xCAT::zvmUtils->disableEnableDisk( $::SUDOER, $node, "-e", "0.0." . $device);
|
|
if (xCAT::zvmUtils->checkOutput( $callback, $out ) == -1) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: $out");
|
|
return;
|
|
}
|
|
|
|
# Set WWPN and LUN in sysfs
|
|
$device = lc($device);
|
|
$wwpn = lc($wwpn);
|
|
|
|
# For the version above RHEL6 or SLES11, the port_add is removed
|
|
# Keep the code here for lower editions, of course, ignore the potential errors
|
|
$out = xCAT::zvmUtils->rExecute($::SUDOER, $node, "echo 0x$wwpn > /sys/bus/ccw/drivers/zfcp/0.0.$device/port_add");
|
|
$out = xCAT::zvmUtils->rExecute($::SUDOER, $node, "echo 0x$lun > /sys/bus/ccw/drivers/zfcp/0.0.$device/0x$wwpn/unit_add");
|
|
|
|
# Get source node OS
|
|
my $os = xCAT::zvmUtils->getOsVersion($::SUDOER, $node);
|
|
|
|
# Set WWPN and LUN in configuration files
|
|
# RHEL: /etc/zfcp.conf
|
|
# SLES 10: /etc/sysconfig/hardware/hwcfg-zfcp-bus-ccw-*
|
|
# SLES 11: /etc/udev/rules.d/51-zfcp*
|
|
my $tmp;
|
|
if ( $os =~ m/sles10/i ) {
|
|
$out = `ssh $::SUDOER\@$node "$::SUDO /sbin/zfcp_host_configure 0.0.$device 1"`;
|
|
if ($out) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: $out");
|
|
}
|
|
|
|
$out = `ssh $::SUDOER\@$node "$::SUDO /sbin/zfcp_disk_configure 0.0.$device $wwpn $lun 1"`;
|
|
if ($out) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: $out");
|
|
}
|
|
|
|
$out = xCAT::zvmUtils->rExecute($::SUDOER, $node, "echo 0x$wwpn:0x$lun >> /etc/sysconfig/hardware/hwcfg-zfcp-bus-ccw-0.0.$device");
|
|
} elsif ( $os =~ m/sles/i ) {
|
|
$out = `ssh $::SUDOER\@$node "$::SUDO /sbin/zfcp_host_configure 0.0.$device 1"`;
|
|
if ($out) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: $out");
|
|
}
|
|
|
|
$out = `ssh $::SUDOER\@$node "$::SUDO /sbin/zfcp_disk_configure 0.0.$device $wwpn $lun 1"`;
|
|
if ($out) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: $out");
|
|
}
|
|
|
|
# Configure zFCP device to be persistent
|
|
$out = `ssh $::SUDOER\@$node "$::SUDO touch /etc/udev/rules.d/51-zfcp-0.0.$device.rules"`;
|
|
|
|
# Check if the file already contains the zFCP channel
|
|
$out = `ssh $::SUDOER\@$node "$::SUDO cat /etc/udev/rules.d/51-zfcp-0.0.$device.rules" | egrep -i "ccw/0.0.$device]online"`;
|
|
if (!$out) {
|
|
$tmp = "'ACTION==\"add\", SUBSYSTEM==\"ccw\", KERNEL==\"0.0.$device\", IMPORT{program}=\"collect 0.0.$device \%k 0.0.$device zfcp\"'";
|
|
$tmp = xCAT::zvmUtils->replaceStr($tmp, '"', '\\"');
|
|
$out = `ssh $::SUDOER\@$node "echo $tmp | $::SUDO tee -a /etc/udev/rules.d/51-zfcp-0.0.$device.rules"`;
|
|
|
|
$tmp = "'ACTION==\"add\", SUBSYSTEM==\"drivers\", KERNEL==\"zfcp\", IMPORT{program}=\"collect 0.0.$device \%k 0.0.$device zfcp\"'";
|
|
$tmp = xCAT::zvmUtils->replaceStr($tmp, '"', '\\"');
|
|
$out = `ssh $::SUDOER\@$node "echo $tmp | $::SUDO tee -a /etc/udev/rules.d/51-zfcp-0.0.$device.rules"`;
|
|
|
|
$tmp = "'ACTION==\"add\", ENV{COLLECT_0.0.$device}==\"0\", ATTR{[ccw/0.0.$device]online}=\"1\"'";
|
|
$tmp = xCAT::zvmUtils->replaceStr($tmp, '"', '\\"');
|
|
$out = `ssh $::SUDOER\@$node "echo $tmp | $::SUDO tee -a /etc/udev/rules.d/51-zfcp-0.0.$device.rules"`;
|
|
}
|
|
|
|
$tmp = "'ACTION==\"add\", KERNEL==\"rport-*\", ATTR{port_name}==\"0x$wwpn\", SUBSYSTEMS==\"ccw\", KERNELS==\"0.0.$device\", ATTR{[ccw/0.0.$device]0x$wwpn/unit_add}=\"0x$lun\"'";
|
|
$tmp = xCAT::zvmUtils->replaceStr($tmp, '"', '\\"');
|
|
$out = `ssh $::SUDOER\@$node "echo $tmp | $::SUDO tee -a /etc/udev/rules.d/51-zfcp-0.0.$device.rules"`;
|
|
} elsif ( $os =~ m/rhel/i ) {
|
|
$out = xCAT::zvmUtils->rExecute($::SUDOER, $node, "echo \"0.0.$device 0x$wwpn 0x$lun\" >> /etc/zfcp.conf");
|
|
|
|
if ($os =~ m/rhel6/i) {
|
|
$out = xCAT::zvmUtils->rExecute($::SUDOER, $node, "echo add > /sys/bus/ccw/devices/0.0.$device/uevent");
|
|
}
|
|
}
|
|
|
|
xCAT::zvmUtils->printLn($callback, "$node: Configuring FCP device to be persistent... Done");
|
|
$out = "";
|
|
}
|
|
|
|
# Set loaddev statement in directory entry
|
|
if ($loaddev) {
|
|
$out = `/opt/xcat/bin/chvm $node --setloaddev $wwpn $lun`;
|
|
xCAT::zvmUtils->printLn($callback, "$out");
|
|
if (xCAT::zvmUtils->checkOutput( $callback, $out ) == -1) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Failed to set LOADDEV statement in the directory entry");
|
|
return;
|
|
}
|
|
$out = "";
|
|
}
|
|
|
|
xCAT::zvmUtils->printLn($callback, "$node: Adding zFCP device $device/$wwpn/$lun... Done");
|
|
}
|
|
|
|
# connectnic2guestlan [address] [lan] [owner]
|
|
elsif ( $args->[0] eq "--connectnic2guestlan" ) {
|
|
my $addr = $args->[1];
|
|
my $lan = $args->[2];
|
|
my $owner = $args->[3];
|
|
|
|
# Connect to LAN in active configuration
|
|
my $ping = `/opt/xcat/bin/pping $node`;
|
|
if (!($ping =~ m/noping/i)) {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Virtual_Network_Adapter_Connect_LAN -T $userId -v $addr -l $lan -o $owner"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Virtual_Network_Adapter_Connect_LAN -T $userId -v $addr -l $lan -o $owner");
|
|
}
|
|
|
|
$out .= `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Virtual_Network_Adapter_Connect_LAN_DM -T $userId -v $addr -n $lan -o $owner"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Virtual_Network_Adapter_Connect_LAN_DM -T $userId -v $addr -n $lan -o $owner");
|
|
$out = xCAT::zvmUtils->appendHostname( $node, $out );
|
|
}
|
|
|
|
# connectnic2vswitch [address] [vSwitch]
|
|
elsif ( $args->[0] eq "--connectnic2vswitch" ) {
|
|
my $addr = $args->[1];
|
|
my $vswitch = $args->[2];
|
|
|
|
# Grant access to VSWITCH for Linux user
|
|
$out = xCAT::zvmCPUtils->grantVSwitch( $callback, $::SUDOER, $hcp, $userId, $vswitch );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Granting VSwitch ($vswitch) access for $userId... $out" );
|
|
|
|
# Connect to VSwitch in directory entry
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Virtual_Network_Adapter_Connect_Vswitch_DM -T $userId -v $addr -n $vswitch"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Virtual_Network_Adapter_Connect_Vswitch_DM -T $userId -v $addr -n $vswitch");
|
|
|
|
# Connect to VSwitch in active configuration
|
|
my $ping = `/opt/xcat/bin/pping $node`;
|
|
if (!($ping =~ m/noping/i)) {
|
|
$out .= `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Virtual_Network_Adapter_Connect_Vswitch -T $userId -v $addr -n $vswitch"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Virtual_Network_Adapter_Connect_Vswitch -T $userId -v $addr -n $vswitch");
|
|
}
|
|
|
|
$out = xCAT::zvmUtils->appendHostname( $node, $out );
|
|
}
|
|
|
|
# copydisk [target address] [source node] [source address]
|
|
elsif ( $args->[0] eq "--copydisk" ) {
|
|
my $tgtNode = $node;
|
|
my $tgtUserId = $userId;
|
|
my $tgtAddr = $args->[1];
|
|
my $srcNode = $args->[2];
|
|
my $srcAddr = $args->[3];
|
|
|
|
# Get source userID
|
|
@propNames = ( 'hcp', 'userid' );
|
|
$propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $srcNode, @propNames );
|
|
my $sourceId = $propVals->{'userid'};
|
|
|
|
# Assume flashcopy is supported (via SMAPI)
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Copying $sourceId disk ($srcAddr) to $tgtUserId disk ($srcAddr) using FLASHCOPY" );
|
|
if (xCAT::zvmUtils->smapi4xcat($::SUDOER, $hcp)) {
|
|
$out = xCAT::zvmCPUtils->smapiFlashCopy($::SUDOER, $hcp, $sourceId, $srcAddr, $tgtUserId, $srcAddr);
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: $out" );
|
|
|
|
# Exit if flashcopy completed successfully
|
|
# Otherwsie, try CP FLASHCOPY
|
|
if ( $out =~ m/Done/i ) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
#*** Link and copy disk ***
|
|
my $rc;
|
|
my $try;
|
|
my $srcDevNode;
|
|
my $tgtDevNode;
|
|
|
|
# Link source disk to HCP
|
|
my $srcLinkAddr;
|
|
$try = 5;
|
|
while ( $try > 0 ) {
|
|
# New disk address
|
|
$srcLinkAddr = $srcAddr + 1000;
|
|
|
|
# Check if new disk address is used (source)
|
|
$rc = xCAT::zvmUtils->isAddressUsed( $::SUDOER, $hcp, $srcLinkAddr );
|
|
|
|
# If disk address is used (source)
|
|
while ( $rc == 0 ) {
|
|
|
|
# Generate a new disk address
|
|
# Sleep 5 seconds to let existing disk appear
|
|
sleep(5);
|
|
$srcLinkAddr = $srcLinkAddr + 1;
|
|
$rc = xCAT::zvmUtils->isAddressUsed( $::SUDOER, $hcp, $srcLinkAddr );
|
|
}
|
|
|
|
# Link source disk
|
|
# Because the zHCP has LNKNOPAS, no disk password is required
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Linking source disk ($srcAddr) as ($srcLinkAddr)" );
|
|
$out = `ssh -o ConnectTimeout=5 $::SUDOER\@$hcp "$::SUDO /sbin/vmcp link $sourceId $srcAddr $srcLinkAddr RR"`;
|
|
|
|
# If link fails
|
|
if ( $out =~ m/not linked/i ) {
|
|
|
|
# Wait before trying again
|
|
sleep(5);
|
|
|
|
$try = $try - 1;
|
|
} else {
|
|
last;
|
|
}
|
|
} # End of while ( $try > 0 )
|
|
|
|
# If source disk is not linked
|
|
if ( $out =~ m/not linked/i ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: (Error) Failed to link source disk ($srcAddr)" );
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Failed" );
|
|
|
|
# Exit
|
|
return;
|
|
}
|
|
|
|
# Link target disk to HCP
|
|
my $tgtLinkAddr;
|
|
$try = 5;
|
|
while ( $try > 0 ) {
|
|
|
|
# New disk address
|
|
$tgtLinkAddr = $tgtAddr + 2000;
|
|
|
|
# Check if new disk address is used (target)
|
|
$rc = xCAT::zvmUtils->isAddressUsed( $::SUDOER, $hcp, $tgtLinkAddr );
|
|
|
|
# If disk address is used (target)
|
|
while ( $rc == 0 ) {
|
|
|
|
# Generate a new disk address
|
|
# Sleep 5 seconds to let existing disk appear
|
|
sleep(5);
|
|
$tgtLinkAddr = $tgtLinkAddr + 1;
|
|
$rc = xCAT::zvmUtils->isAddressUsed( $::SUDOER, $hcp, $tgtLinkAddr );
|
|
}
|
|
|
|
# Link target disk
|
|
# Because the zHCP has LNKNOPAS, no disk password is required
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Linking target disk ($tgtAddr) as ($tgtLinkAddr)" );
|
|
$out = `ssh -o ConnectTimeout=5 $::SUDOER\@$hcp "$::SUDO /sbin/vmcp link $tgtUserId $tgtAddr $tgtLinkAddr MR"`;
|
|
|
|
# If link fails
|
|
if ( $out =~ m/not linked/i ) {
|
|
|
|
# Wait before trying again
|
|
sleep(5);
|
|
|
|
$try = $try - 1;
|
|
} else {
|
|
last;
|
|
}
|
|
} # End of while ( $try > 0 )
|
|
|
|
# If target disk is not linked
|
|
if ( $out =~ m/not linked/i ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: (Error) Failed to link target disk ($tgtAddr)" );
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Failed" );
|
|
|
|
# Detatch disks from HCP
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/vmcp det $srcLinkAddr"`;
|
|
|
|
# Exit
|
|
return;
|
|
}
|
|
|
|
#*** Use flashcopy ***
|
|
# Flashcopy only supports ECKD volumes
|
|
# Assume flashcopy is supported and use Linux DD on failure
|
|
my $ddCopy = 0;
|
|
|
|
# Check for CP flashcopy lock
|
|
my $wait = 0;
|
|
while ( `ssh $::SUDOER\@$hcp "$::SUDO ls /tmp/.flashcopy_lock"` && $wait < 90 ) {
|
|
|
|
# Wait until the lock dissappears
|
|
# 90 seconds wait limit
|
|
sleep(2);
|
|
$wait = $wait + 2;
|
|
}
|
|
|
|
# If flashcopy locks still exists
|
|
if (`ssh $::SUDOER\@$hcp "$::SUDO ls /tmp/.flashcopy_lock"`) {
|
|
|
|
# Detatch disks from HCP
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/vmcp det $tgtLinkAddr"`;
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/vmcp det $srcLinkAddr"`;
|
|
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: (Error) Flashcopy lock is enabled" );
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: (Solution) Remove lock by deleting /tmp/.flashcopy_lock on the zHCP. Use caution!" );
|
|
return;
|
|
} else {
|
|
|
|
# Enable lock
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO touch /tmp/.flashcopy_lock"`;
|
|
|
|
# Flashcopy source disk
|
|
$out = xCAT::zvmCPUtils->flashCopy( $::SUDOER, $hcp, $srcLinkAddr, $tgtLinkAddr );
|
|
$rc = xCAT::zvmUtils->checkOutput( $callback, $out );
|
|
if ( $rc == -1 ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: $out" );
|
|
|
|
# Try using Linux DD
|
|
$ddCopy = 1;
|
|
|
|
# Remove lock
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO rm -f /tmp/.flashcopy_lock"`;
|
|
}
|
|
|
|
# Remove lock
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO rm -f /tmp/.flashcopy_lock"`;
|
|
}
|
|
|
|
# Flashcopy not supported, use Linux dd
|
|
if ($ddCopy) {
|
|
#*** Use Linux dd to copy ***
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: FLASHCOPY not working. Using Linux DD" );
|
|
|
|
# Enable disks
|
|
$out = xCAT::zvmUtils->disableEnableDisk( $::SUDOER, $hcp, "-e", $tgtLinkAddr );
|
|
$out = xCAT::zvmUtils->disableEnableDisk( $::SUDOER, $hcp, "-e", $srcLinkAddr );
|
|
|
|
# Determine source device node
|
|
$srcDevNode = xCAT::zvmUtils->getDeviceNode($::SUDOER, $hcp, $srcLinkAddr);
|
|
|
|
# Determine target device node
|
|
$tgtDevNode = xCAT::zvmUtils->getDeviceNode($::SUDOER, $hcp, $tgtLinkAddr);
|
|
|
|
# Format target disk
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Formating target disk ($tgtDevNode)" );
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/dasdfmt -b 4096 -y -f /dev/$tgtDevNode"`;
|
|
|
|
# Check for errors
|
|
$rc = xCAT::zvmUtils->checkOutput( $callback, $out );
|
|
if ( $rc == -1 ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: $out" );
|
|
|
|
# Detatch disks from HCP
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/vmcp det $tgtLinkAddr"`;
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/vmcp det $srcLinkAddr"`;
|
|
|
|
return;
|
|
}
|
|
|
|
# Sleep 2 seconds to let the system settle
|
|
sleep(2);
|
|
|
|
# Automatically create a partition using the entire disk
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Creating a partition using the entire disk ($tgtDevNode)" );
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/fdasd -a /dev/$tgtDevNode"`;
|
|
|
|
# Copy source disk to target disk (4096 block size)
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Copying source disk ($srcDevNode) to target disk ($tgtDevNode)" );
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /bin/dd if=/dev/$srcDevNode of=/dev/$tgtDevNode bs=4096 oflag=sync"`;
|
|
|
|
# Disable disks
|
|
$out = xCAT::zvmUtils->disableEnableDisk( $::SUDOER, $hcp, "-d", $tgtLinkAddr );
|
|
$out = xCAT::zvmUtils->disableEnableDisk( $::SUDOER, $hcp, "-d", $srcLinkAddr );
|
|
|
|
# Check for error
|
|
$rc = xCAT::zvmUtils->checkOutput( $callback, $out );
|
|
if ( $rc == -1 ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: $out" );
|
|
|
|
# Detatch disks from HCP
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/vmcp det $tgtLinkAddr"`;
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/vmcp det $srcLinkAddr"`;
|
|
|
|
return;
|
|
}
|
|
|
|
# Sleep 2 seconds to let the system settle
|
|
sleep(2);
|
|
}
|
|
|
|
# Detatch disks from HCP
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Detatching target disk ($tgtLinkAddr)" );
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Detatching source disk ($srcLinkAddr)" );
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/vmcp det $tgtLinkAddr"`;
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/vmcp det $srcLinkAddr"`;
|
|
|
|
$out = "$tgtNode: Done";
|
|
}
|
|
|
|
# createfilesysnode [source file] [target file]
|
|
elsif ( $args->[0] eq "--createfilesysnode" ) {
|
|
my $srcFile = $args->[1];
|
|
my $tgtFile = $args->[2];
|
|
|
|
my $argsSize = @{$args};
|
|
if ($argsSize != 3) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Wrong number of parameters");
|
|
return;
|
|
}
|
|
|
|
$out = `ssh $::SUDOER\@$node "$::SUDO /usr/bin/stat --printf=%n $tgtFile"`;
|
|
if ($out eq $tgtFile) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) $tgtFile already exists");
|
|
return;
|
|
}
|
|
|
|
$out = `ssh $::SUDOER\@$node "$::SUDO /usr/bin/stat --printf=%n $srcFile"`;
|
|
if ($out ne $srcFile) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) $srcFile does not exist");
|
|
return;
|
|
}
|
|
|
|
$out = `ssh $::SUDOER\@$node "$::SUDO /usr/bin/stat -L --printf=%t:%T $srcFile"`;
|
|
if ($out != '') {
|
|
my @device = split(":", $out);
|
|
my $major = sprintf("%d", hex($device[0]));
|
|
my $minor = sprintf("%d", hex($device[1]));
|
|
$out = `ssh $::SUDOER\@$node "$::SUDO /bin/mknod $tgtFile b $major $minor "`;
|
|
}
|
|
}
|
|
|
|
# dedicatedevice [virtual device] [real device] [mode (1 or 0)]
|
|
elsif ( $args->[0] eq "--dedicatedevice" ) {
|
|
my $vaddr = $args->[1];
|
|
my $raddr = $args->[2];
|
|
my $mode = $args->[3];
|
|
|
|
# Dedicate device to directory entry
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Device_Dedicate_DM -T $userId -v $vaddr -r $raddr -R $mode"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Device_Dedicate_DM -T $userId -v $vaddr -r $raddr -R $mode");
|
|
xCAT::zvmUtils->printLn( $callback, "$node: $out" );
|
|
|
|
# Dedicate device to active configuration
|
|
my $ping = `/opt/xcat/bin/pping $node`;
|
|
if (!($ping =~ m/noping/i)) {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Device_Dedicate -T $userId -v $vaddr -r $raddr -R $mode"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Device_Dedicate -T $userId -v $vaddr -r $raddr -R $mode");
|
|
xCAT::zvmUtils->printLn( $callback, "$node: $out" );
|
|
}
|
|
|
|
$out = "";
|
|
}
|
|
|
|
# deleteipl
|
|
elsif ( $args->[0] eq "--deleteipl" ) {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_IPL_Delete_DM -T $userId"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_IPL_Delete_DM -T $userId");
|
|
$out = xCAT::zvmUtils->appendHostname( $node, $out );
|
|
}
|
|
|
|
# formatdisk [address] [multi password]
|
|
elsif ( $args->[0] eq "--formatdisk" ) {
|
|
my $tgtNode = $node;
|
|
my $tgtUserId = $userId;
|
|
my $tgtAddr = $args->[1];
|
|
|
|
#*** Link and format disk ***
|
|
my $rc;
|
|
my $try;
|
|
my $tgtDevNode;
|
|
|
|
# Link target disk to zHCP
|
|
my $tgtLinkAddr;
|
|
$try = 5;
|
|
while ( $try > 0 ) {
|
|
|
|
# New disk address
|
|
$tgtLinkAddr = $tgtAddr + 1000;
|
|
|
|
# Check if new disk address is used (target)
|
|
$rc = xCAT::zvmUtils->isAddressUsed( $::SUDOER, $hcp, $tgtLinkAddr );
|
|
|
|
# If disk address is used (target)
|
|
while ( $rc == 0 ) {
|
|
|
|
# Generate a new disk address
|
|
# Sleep 5 seconds to let existing disk appear
|
|
sleep(5);
|
|
$tgtLinkAddr = $tgtLinkAddr + 1;
|
|
$rc = xCAT::zvmUtils->isAddressUsed( $::SUDOER, $hcp, $tgtLinkAddr );
|
|
}
|
|
|
|
# Link target disk
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Linking target disk ($tgtAddr) as ($tgtLinkAddr)" );
|
|
$out = `ssh -o ConnectTimeout=5 $::SUDOER\@$hcp "$::SUDO /sbin/vmcp link $tgtUserId $tgtAddr $tgtLinkAddr MR"`;
|
|
|
|
# If link fails
|
|
if ( $out =~ m/not linked/i || $out =~ m/DASD $tgtLinkAddr forced R\/O/i ) {
|
|
# Detatch link because only linked as R/O
|
|
`ssh -o ConnectTimeout=5 $::SUDOER\@$hcp "$::SUDO /sbin/vmcp det $tgtLinkAddr"`;
|
|
|
|
# Wait before trying again
|
|
sleep(5);
|
|
|
|
$try = $try - 1;
|
|
} else {
|
|
last;
|
|
}
|
|
} # End of while ( $try > 0 )
|
|
|
|
# If target disk is not linked
|
|
if ( $out =~ m/not linked/i || $out =~ m/DASD $tgtLinkAddr forced R\/O/i ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: (Error) Failed to link target disk ($tgtAddr)" );
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Failed" );
|
|
|
|
# Detatch link because only linked as R/O
|
|
`ssh $::SUDOER\@$hcp "$::SUDO /sbin/vmcp det $tgtLinkAddr"`;
|
|
|
|
# Exit
|
|
return;
|
|
}
|
|
|
|
#*** Format disk ***
|
|
my @words;
|
|
if ( $rc == -1 ) {
|
|
|
|
# Enable disk
|
|
$out = xCAT::zvmUtils->disableEnableDisk( $::SUDOER, $hcp, "-e", $tgtLinkAddr );
|
|
|
|
# Determine target device node
|
|
$tgtDevNode = xCAT::zvmUtils->getDeviceNode($::SUDOER, $hcp, $tgtLinkAddr);
|
|
|
|
# Format target disk
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Formating target disk ($tgtDevNode)" );
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/dasdfmt -b 4096 -y -f /dev/$tgtDevNode"`;
|
|
|
|
# Check for errors
|
|
$rc = xCAT::zvmUtils->checkOutput( $callback, $out );
|
|
if ( $rc == -1 ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: $out" );
|
|
return;
|
|
}
|
|
}
|
|
|
|
# Disable disk
|
|
$out = xCAT::zvmUtils->disableEnableDisk( $::SUDOER, $hcp, "-d", $tgtLinkAddr );
|
|
|
|
# Detatch disk from HCP
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Detatching target disk ($tgtLinkAddr)" );
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/vmcp det $tgtLinkAddr"`;
|
|
|
|
$out = "$tgtNode: Done";
|
|
}
|
|
|
|
# grantvswitch [VSwitch]
|
|
elsif ( $args->[0] eq "--grantvswitch" ) {
|
|
my $vsw = $args->[1];
|
|
|
|
$out = xCAT::zvmCPUtils->grantVSwitch( $callback, $::SUDOER, $hcp, $userId, $vsw );
|
|
$out = xCAT::zvmUtils->appendHostname( $node, "Granting VSwitch ($vsw) access for $userId... $out" );
|
|
}
|
|
|
|
# disconnectnic [address]
|
|
elsif ( $args->[0] eq "--disconnectnic" ) {
|
|
my $addr = $args->[1];
|
|
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Virtual_Network_Adapter_Disconnect_DM -T $userId -v $addr"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Virtual_Network_Adapter_Disconnect_DM -T $userId -v $addr");
|
|
$out = xCAT::zvmUtils->appendHostname( $node, $out );
|
|
}
|
|
|
|
# punchfile [file path] [class (optional)] [remote host (optional)]
|
|
elsif ( $args->[0] eq "--punchfile" ) {
|
|
# Punch a file to a the node reader
|
|
my $argsSize = @{$args};
|
|
if (($argsSize < 2) || ($argsSize > 4)) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Wrong number of parameters" );
|
|
return;
|
|
}
|
|
|
|
my $filePath = $args->[1];
|
|
my $class = "A"; # Default spool class should be A
|
|
my $remoteHost;
|
|
if ($argsSize > 2) {
|
|
$class = $args->[2];
|
|
} if ($argsSize > 3) {
|
|
$remoteHost = $args->[3]; # Must be specified as user@host
|
|
}
|
|
|
|
# Obtain file name
|
|
my $fileName = basename($filePath);
|
|
|
|
# Validate class
|
|
if ($class !~ /^[a-zA-Z0-9]$/) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Invalid spool class: $class. It should be 1-character alphanumeric" );
|
|
return;
|
|
}
|
|
|
|
# If a remote host is specified, obtain the file from the remote host
|
|
# The xCAT public SSH key must have been already setup if this is to work
|
|
my $rc;
|
|
if (defined $remoteHost) {
|
|
$rc = `/usr/bin/scp $remoteHost:$filePath /tmp/$fileName 2>/dev/null; echo $?`;
|
|
} else {
|
|
$rc = `/bin/cp $filePath /tmp/$fileName 2>/dev/null; echo $?`;
|
|
}
|
|
|
|
if ($rc != '0') {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Failed to copy over source file" );
|
|
return;
|
|
}
|
|
|
|
# Set up punch device and class
|
|
$rc = `ssh $::SUDOER\@$hcp "$::SUDO cio_ignore -r d"`;
|
|
xCAT::zvmUtils->disableEnableDisk($::SUDOER, $hcp, "-e", "d");
|
|
$rc = `ssh $::SUDOER\@$hcp "$::SUDO vmcp spool punch class $class"`;
|
|
|
|
# Send over file to zHCP and punch it to the node reader
|
|
$filePath = "/tmp/$fileName";
|
|
xCAT::zvmUtils->sendFile($::SUDOER, $hcp, $filePath, $filePath);
|
|
$out = xCAT::zvmCPUtils->punch2Reader($::SUDOER, $hcp, $userId, $filePath, $fileName, "");
|
|
|
|
# No extra steps are needed if the punch succeeded or failed, just output the results
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Punching $fileName to reader... $out" );
|
|
|
|
# Remove temporary file and restore punch class
|
|
`rm -rf $filePath`;
|
|
`ssh $::SUDOER\@$hcp "$::SUDO rm -f /tmp/$fileName"`;
|
|
`ssh $::SUDOER\@$hcp "$::SUDO /sbin/vmcp spool punch class A"`;
|
|
$out = "";
|
|
}
|
|
|
|
# purgerdr
|
|
elsif ( $args->[0] eq "--purgerdr" ) {
|
|
# Purge the reader of node
|
|
$out = xCAT::zvmCPUtils->purgeReader($::SUDOER, $hcp, $userId);
|
|
$out = xCAT::zvmUtils->appendHostname( $node, "$out" );
|
|
}
|
|
|
|
# removediskfrompool [function] [region] [group]
|
|
elsif ( $args->[0] eq "--removediskfrompool" ) {
|
|
# This is no longer supported in chvm. Using chhypervisor instead.
|
|
changeHypervisor( $callback, $node, $args );
|
|
}
|
|
|
|
# removezfcpfrompool [pool] [lun]
|
|
elsif ( $args->[0] eq "--removezfcpfrompool" ) {
|
|
# This is no longer supported in chvm. Using chhypervisor instead.
|
|
changeHypervisor( $callback, $node, $args );
|
|
}
|
|
|
|
# removedisk [virtual address]
|
|
elsif ( $args->[0] eq "--removedisk" ) {
|
|
my $addr = $args->[1];
|
|
|
|
# Remove from active configuration
|
|
my $ping = `/opt/xcat/bin/pping $node`;
|
|
if (!($ping =~ m/noping/i)) {
|
|
$out = xCAT::zvmUtils->disableEnableDisk( $::SUDOER, $node, "-d", $addr );
|
|
$out = `ssh $node "/sbin/vmcp det $addr"`;
|
|
}
|
|
|
|
# Remove from user directory entry
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Disk_Delete_DM -T $userId -v $addr -e 0"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Disk_Delete_DM -T $userId -v $addr -e 0");
|
|
$out = xCAT::zvmUtils->appendHostname( $node, $out );
|
|
}
|
|
|
|
# removefilesysnode [target file]
|
|
elsif ( $args->[0] eq "--removefilesysnode" ) {
|
|
my $tgtFile = $args->[1];
|
|
|
|
my $argsSize = @{$args};
|
|
if ($argsSize != 2) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Wrong number of parameters" );
|
|
return;
|
|
}
|
|
|
|
# Unmount this disk, but ignore the output
|
|
$out = `ssh $::SUDOER\@$node "$::SUDO umount $tgtFile"`;
|
|
$out = `ssh $::SUDOER\@$node "$::SUDO rm -f $tgtFile"`;
|
|
|
|
xCAT::zvmUtils->printLn($callback, "$node: Removing file system node $tgtFile... Done");
|
|
}
|
|
|
|
# removenic [address]
|
|
elsif ( $args->[0] eq "--removenic" ) {
|
|
my $addr = $args->[1];
|
|
|
|
# Remove from active configuration
|
|
my $ping = `/opt/xcat/bin/pping $node`;
|
|
if (!($ping =~ m/noping/i)) {
|
|
$out = `ssh $node "/sbin/vmcp det nic $addr"`;
|
|
}
|
|
|
|
# Remove from user directory entry
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Virtual_Network_Adapter_Delete_DM -T $userId -v $addr"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Virtual_Network_Adapter_Delete_DM -T $userId -v $addr");
|
|
$out = xCAT::zvmUtils->appendHostname( $node, $out );
|
|
}
|
|
|
|
# removeprocessor [address]
|
|
elsif ( $args->[0] eq "--removeprocessor" ) {
|
|
my $addr = $args->[1];
|
|
|
|
# Remove from user directory entry
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_CPU_Delete_DM -T $userId -v $addr"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_CPU_Delete_DM -T $userId -v $addr");
|
|
$out = xCAT::zvmUtils->appendHostname( $node, $out );
|
|
}
|
|
|
|
# removeloaddev [wwpn] [lun]
|
|
elsif ( $args->[0] eq "--removeloaddev" ) {
|
|
my $wwpn = $args->[1];
|
|
my $lun = $args->[2];
|
|
|
|
xCAT::zvmUtils->printLn($callback, "$node: Removing LOADDEV directory statements");
|
|
|
|
# Make sure WWPN and LUN do not have 0x prefix
|
|
$wwpn = xCAT::zvmUtils->replaceStr( $wwpn, "0x", "" );
|
|
$lun = xCAT::zvmUtils->replaceStr( $lun, "0x", "" );
|
|
|
|
# Get user directory entry
|
|
my $updateEntry = 0;
|
|
my $userEntryFile = "/tmp/$node.txt";
|
|
my $userEntry = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Query_DM -T $userId" | sed '\$d'`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Query_DM -T $userId | sed '\$d'");
|
|
chomp($userEntry);
|
|
if (!$wwpn && !$lun) {
|
|
# If no WWPN or LUN is provided, delete all LOADDEV statements
|
|
`echo "$userEntry" | grep -v "LOADDEV" > $userEntryFile`;
|
|
$updateEntry = 1;
|
|
} else {
|
|
|
|
# Delete old directory entry file
|
|
`rm -rf $userEntryFile`;
|
|
|
|
# Remove LOADDEV PORTNAME and LUN statements in directory entry
|
|
my @lines = split( '\n', $userEntry );
|
|
foreach (@lines) {
|
|
# Check if LOADDEV PORTNAME and LUN statements are in the directory entry
|
|
if ($_ =~ m/LOADDEV PORTNAME $wwpn/i) {
|
|
$updateEntry = 1;
|
|
next;
|
|
} elsif ($_ =~ m/LOADDEV LUN $lun/i) {
|
|
$updateEntry = 1;
|
|
next;
|
|
} else {
|
|
# Write directory entry to file
|
|
`echo "$_" >> $userEntryFile`;
|
|
}
|
|
}
|
|
}
|
|
|
|
# Replace user directory entry (if necessary)
|
|
if ($updateEntry) {
|
|
$out = `/opt/xcat/bin/chvm $node --replacevs $userEntryFile`;
|
|
xCAT::zvmUtils->printLn($callback, "$out");
|
|
|
|
# Delete directory entry file
|
|
`rm -rf $userEntryFile`;
|
|
} else {
|
|
xCAT::zvmUtils->printLn($callback, "$node: No changes required in the directory entry");
|
|
}
|
|
|
|
$out = "";
|
|
}
|
|
|
|
# removezfcp [device address] [wwpn] [lun] [persist (0 or 1)]
|
|
elsif ( $args->[0] eq "--removezfcp" ) {
|
|
my $device = $args->[1];
|
|
my $wwpn = $args->[2];
|
|
my $lun = $args->[3];
|
|
my $persist = "0"; # Optional
|
|
|
|
# Delete 0x prefix
|
|
$wwpn = xCAT::zvmUtils->replaceStr($wwpn, "0x", "");
|
|
$lun = xCAT::zvmUtils->replaceStr($lun, "0x", "");
|
|
|
|
my $argsSize = @{$args};
|
|
if ($argsSize != 4 && $argsSize != 5) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Wrong number of parameters");
|
|
return;
|
|
}
|
|
|
|
if ($argsSize == 5) {
|
|
$persist = $args->[4];
|
|
}
|
|
|
|
# Check the value of persist
|
|
if ($persist !~ /^[01]$/) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Persist can only be 0 or 1");
|
|
return;
|
|
}
|
|
$persist = int($persist);
|
|
|
|
# Find the pool that contains the SCSI/FCP device
|
|
my $pool = xCAT::zvmUtils->findzFcpDevicePool($::SUDOER, $hcp, $wwpn, $lun);
|
|
if (!$pool) {
|
|
# Continue to try and remove the SCSI/FCP device even when it is not found in a storage pool
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Could not find FCP device in any FCP storage pool" );
|
|
} else {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Found FCP device in $pool" );
|
|
|
|
# If the device is not known, try to find it in the storage pool
|
|
if ($device !~ /^[0-9a-f]/i) {
|
|
my $select = `ssh $::SUDOER\@$hcp "$::SUDO cat $::ZFCPPOOL/$pool.conf" | grep -i "$wwpn,$lun"`;
|
|
chomp($select);
|
|
my @info = split(',', $select);
|
|
if ($device) {
|
|
$device = $info[6];
|
|
}
|
|
}
|
|
|
|
my $status = "free";
|
|
my $owner = "";
|
|
if ($persist) {
|
|
# Keep the device reserved if persist = 1
|
|
$status = "reserved";
|
|
$owner = $node;
|
|
}
|
|
|
|
my %criteria = (
|
|
'status' => $status,
|
|
'wwpn' => $wwpn,
|
|
'lun' => $lun,
|
|
'owner' => $owner,
|
|
);
|
|
my $resultsRef = xCAT::zvmUtils->findAndUpdatezFcpPool($callback, $node, $::SUDOER, $hcp, $pool, \%criteria);
|
|
my %results = %$resultsRef;
|
|
|
|
if ($results{'rc'} == -1) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Failed to find zFCP device");
|
|
return;
|
|
}
|
|
|
|
# Obtain the device assigned by xCAT
|
|
$wwpn = $results{'wwpn'};
|
|
$lun = $results{'lun'};
|
|
}
|
|
|
|
# De-configure SCSI over FCP inside node (if online)
|
|
my $ping = `/opt/xcat/bin/pping $node`;
|
|
if (!($ping =~ m/noping/i)) {
|
|
# Delete WWPN and LUN from sysfs
|
|
$device = lc($device);
|
|
$wwpn = lc($wwpn);
|
|
|
|
# unit_remove does not exist on SLES 10!
|
|
$out = xCAT::zvmUtils->rExecute($::SUDOER, $node, "echo 0x$lun > /sys/bus/ccw/drivers/zfcp/0.0.$device/0x$wwpn/unit_remove");
|
|
|
|
# Get source node OS
|
|
my $os = xCAT::zvmUtils->getOsVersion($::SUDOER, $node);
|
|
|
|
# Delete WWPN and LUN from configuration files
|
|
# RHEL: /etc/zfcp.conf
|
|
# SLES 10: /etc/sysconfig/hardware/hwcfg-zfcp-bus-ccw-*
|
|
# SLES 11: /etc/udev/rules.d/51-zfcp*
|
|
my $expression = "";
|
|
if ( $os =~ m/sles/i ) {
|
|
$expression = "/$lun/d";
|
|
if ( $os =~ m/sles10/i ) {
|
|
$out = `ssh $::SUDOER\@$node "$::SUDO sed -i -e $expression /etc/sysconfig/hardware/hwcfg-zfcp-bus-ccw-0.0.$device"`;
|
|
} else {
|
|
$out = `ssh $::SUDOER\@$node "$::SUDO sed -i -e $expression /etc/udev/rules.d/51-zfcp-0.0.$device.rules"`;
|
|
}
|
|
} elsif ( $os =~ m/rhel/i ) {
|
|
$expression = "/$lun/d";
|
|
$out = `ssh $::SUDOER\@$node "$::SUDO sed -i -e $expression /etc/zfcp.conf"`;
|
|
}
|
|
|
|
xCAT::zvmUtils->printLn($callback, "$node: De-configuring FCP device on host... Done");
|
|
}
|
|
|
|
$out = "";
|
|
}
|
|
|
|
# replacevs [file]
|
|
elsif ( $args->[0] eq "--replacevs" ) {
|
|
my $argsSize = @{$args};
|
|
my $file;
|
|
if ($argsSize == 2) {
|
|
$file = $args->[1];
|
|
}
|
|
|
|
if ($file) {
|
|
if (-e $file) {
|
|
# Target system (zHCP), e.g. root@gpok2.endicott.ibm.com
|
|
my $target = "$::SUDOER@";
|
|
$target .= $hcp;
|
|
|
|
# SCP file over to zHCP
|
|
$out = `scp $file $target:$file`;
|
|
|
|
# Lock image
|
|
`ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Lock_DM -T $userId"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Lock_DM -T $userId");
|
|
|
|
# Replace user directory entry
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Replace_DM -T $userId -f $file"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Replace_DM -T $userId -f $file");
|
|
|
|
# Unlock image
|
|
`ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Unlock_DM -T $userId"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Unlock_DM -T $userId");
|
|
|
|
# Delete file on zHCP
|
|
`ssh $::SUDOER\@$hcp "rm -rf $file"`;
|
|
} else {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) File does not exist" );
|
|
return;
|
|
}
|
|
} elsif ($::STDIN) {
|
|
# Create a temporary file to contain directory on zHCP
|
|
$file = "/tmp/" . $node . ".direct";
|
|
my @lines = split("\n", $::STDIN);
|
|
|
|
# Delete existing file on zHCP (if any)
|
|
`ssh $::SUDOER\@$hcp "rm -rf $file"`;
|
|
|
|
# Write directory entry into temporary file
|
|
# because directory entry cannot be remotely echoed into stdin
|
|
foreach (@lines) {
|
|
if ($_) {
|
|
$_ = "'" . $_ . "'";
|
|
`ssh $::SUDOER\@$hcp "echo $_ >> $file"`;
|
|
}
|
|
}
|
|
|
|
# Lock image
|
|
`ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Lock_DM -T $userId"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Lock_DM -T $userId");
|
|
|
|
# Replace user directory entry
|
|
$out = `ssh $::SUDOER\@$hcp "cat $file | $::SUDO $::DIR/smcli Image_Replace_DM -T $userId -s"`;
|
|
xCAT::zvmUtils->printSyslog("ssh $::SUDOER\@$hcp cat $file | $::SUDO $::DIR/smcli Image_Replace_DM -T $userId -s");
|
|
|
|
# Unlock image
|
|
`ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Unlock_DM -T $userId"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Unlock_DM -T $userId");
|
|
|
|
# Delete created file on zHCP
|
|
`ssh $::SUDOER\@$hcp "rm -rf $file"`;
|
|
} else {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) No directory entry file specified" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Solution) Specify a text file containing the updated directory entry" );
|
|
return;
|
|
}
|
|
|
|
$out = xCAT::zvmUtils->appendHostname( $node, $out );
|
|
}
|
|
|
|
# resetsmapi
|
|
elsif ( $args->[0] eq "--resetsmapi" ) {
|
|
# This is no longer supported in chvm. Using chhypervisor instead.
|
|
changeHypervisor( $callback, $node, $args );
|
|
}
|
|
|
|
# setipl [ipl target] [load parms] [parms]
|
|
elsif ( $args->[0] eq "--setipl" ) {
|
|
my $trgt = $args->[1];
|
|
|
|
my $loadparms = "''";
|
|
if ($args->[2]) {
|
|
$loadparms = $args->[2];
|
|
}
|
|
|
|
my $parms = "''";
|
|
if ($args->[3]) {
|
|
$parms = $args->[3];
|
|
}
|
|
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_IPL_Set_DM -T $userId -s $trgt -l $loadparms -p $parms"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_IPL_Set_DM -T $userId -s $trgt -l $loadparms -p $parms");
|
|
$out = xCAT::zvmUtils->appendHostname( $node, $out );
|
|
}
|
|
|
|
# setpassword [password]
|
|
elsif ( $args->[0] eq "--setpassword" ) {
|
|
my $pw = $args->[1];
|
|
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Password_Set_DM -T $userId -p $pw"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Password_Set_DM -T $userId -p $pw");
|
|
$out = xCAT::zvmUtils->appendHostname( $node, $out );
|
|
}
|
|
|
|
# setloaddev [wwpn] [lun]
|
|
elsif ( $args->[0] eq "--setloaddev" ) {
|
|
my $wwpn = $args->[1];
|
|
my $lun = $args->[2];
|
|
|
|
if (!$wwpn || !$lun) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Wrong number of parameters" );
|
|
return;
|
|
}
|
|
|
|
# Make sure WWPN and LUN do not have 0x prefix
|
|
$wwpn = xCAT::zvmUtils->replaceStr( $wwpn, "0x", "" );
|
|
$lun = xCAT::zvmUtils->replaceStr( $lun, "0x", "" );
|
|
|
|
xCAT::zvmUtils->printLn($callback, "$node: Setting LOADDEV directory statements");
|
|
|
|
# Get user directory entry
|
|
my $userEntry = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Query_DM -T $userId" | sed '\$d'`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Query_DM -T $userId | sed '\$d'");
|
|
|
|
# Delete old directory entry file
|
|
my $userEntryFile = "/tmp/$node.txt";
|
|
`rm -rf $userEntryFile`;
|
|
|
|
# Append LOADDEV PORTNAME and LUN statements in directory entry
|
|
# These statements go before DEDICATE statements
|
|
my $containsPortname = 0;
|
|
my $containsLun = 0;
|
|
my $updateEntry = 0;
|
|
my @lines = split( '\n', $userEntry );
|
|
foreach (@lines) {
|
|
# Check if LOADDEV PORTNAME and LUN statements are in the directory entry
|
|
# This should be hit before any DEDICATE statements
|
|
if ($_ =~ m/LOADDEV PORTNAME $wwpn/i) {
|
|
$containsPortname = 1;
|
|
} if ($_ =~ m/LOADDEV LUN $lun/i) {
|
|
$containsLun = 1;
|
|
}
|
|
|
|
if ($_ =~ m/DEDICATE/i) {
|
|
# Append LOADDEV PORTNAME statement
|
|
if (!$containsPortname) {
|
|
`echo "LOADDEV PORTNAME $wwpn" >> $userEntryFile`;
|
|
$containsPortname = 1;
|
|
$updateEntry = 1;
|
|
}
|
|
|
|
# Append LOADDEV LUN statement
|
|
if (!$containsLun) {
|
|
`echo "LOADDEV LUN $lun" >> $userEntryFile`;
|
|
$containsLun = 1;
|
|
$updateEntry = 1;
|
|
}
|
|
}
|
|
|
|
# Write directory entry to file
|
|
`echo "$_" >> $userEntryFile`;
|
|
}
|
|
|
|
# Replace user directory entry (if necessary)
|
|
if ($updateEntry) {
|
|
$out = `/opt/xcat/bin/chvm $node --replacevs $userEntryFile`;
|
|
xCAT::zvmUtils->printLn( $callback, "$out");
|
|
|
|
# Delete directory entry file
|
|
`rm -rf $userEntryFile`;
|
|
} else {
|
|
xCAT::zvmUtils->printLn($callback, "$node: No changes required in the directory entry");
|
|
}
|
|
|
|
$out = "";
|
|
}
|
|
|
|
# undedicatedevice [virtual device]
|
|
elsif ( $args->[0] eq "--undedicatedevice" ) {
|
|
my $vaddr = $args->[1];
|
|
|
|
# Undedicate device in directory entry
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Device_Undedicate_DM -T $userId -v $vaddr"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Device_Undedicate_DM -T $userId -v $vaddr");
|
|
xCAT::zvmUtils->printLn( $callback, "$node: $out" );
|
|
|
|
# Undedicate device in active configuration
|
|
my $ping = `/opt/xcat/bin/pping $node`;
|
|
if (!($ping =~ m/noping/i)) {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Device_Undedicate -T $userId -v $vaddr"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Device_Undedicate -T $userId -v $vaddr");
|
|
xCAT::zvmUtils->printLn( $callback, "$node: $out" );
|
|
}
|
|
|
|
$out = "";
|
|
}
|
|
|
|
# sharevolume [vol_addr] [share_enable (YES or NO)]
|
|
elsif ( $args->[0] eq "--sharevolume" ) {
|
|
my $volAddr = $args->[1];
|
|
my $share = $args->[2];
|
|
|
|
# Add disk to running system
|
|
$out .= `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Volume_Share -T $userId -k img_vol_addr=$volAddr -k share_enable=$share"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Volume_Share -T $userId -k img_vol_addr=$volAddr -k share_enable=$share");
|
|
$out = xCAT::zvmUtils->appendHostname( $node, $out );
|
|
}
|
|
|
|
# setprocessor [count]
|
|
elsif($args->[0] eq "--setprocessor") {
|
|
my $cpuCount = $args->[1];
|
|
my @allCpu;
|
|
my $count = 0;
|
|
my $newAddr;
|
|
my $cpu;
|
|
my @allValidAddr = ('00','01','02','03','04','05','06','07','09','09','0A','0B','0C','0D','0E','0F',
|
|
'10','11','12','13','14','15','16','17','19','19','1A','1B','1C','1D','1E','1F',
|
|
'20','21','22','23','24','25','26','27','29','29','2A','2B','2C','2D','2E','2F',
|
|
'30','31','32','33','34','35','36','37','39','39','3A','3B','3C','3D','3E','3F');
|
|
|
|
# Get current CPU count and address
|
|
my $proc = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Definition_Query_DM -T $userId -k CPU" | grep CPU=`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Definition_Query_DM -T $userId -k CPU | grep CPU=");
|
|
while ( index( $proc, "CPUADDR" ) != -1) {
|
|
my $position = index($proc, "CPUADDR");
|
|
my $address = substr($proc, $position + 8, 2);
|
|
push( @allCpu, $address );
|
|
$proc = substr( $proc, $position + 10 );
|
|
}
|
|
|
|
# Find free valid CPU address
|
|
my %allCpu = map { $_=>1 } @allCpu;
|
|
my @addrLeft = grep ( !defined $allCpu{$_}, @allValidAddr );
|
|
|
|
# Add new CPUs
|
|
if ( $cpuCount > @allCpu ) {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Definition_Update_DM -T $userId -k CPU_MAXIMUM=COUNT=$cpuCount -k TYPE=ESA"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Definition_Update_DM -T $userId -k CPU_MAXIMUM=COUNT=$cpuCount -k TYPE=ESA");
|
|
while ( $count < $cpuCount - @allCpu ) {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Definition_Update_DM -T $userId -k CPU=CPUADDR=$addrLeft[$count]"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Definition_Update_DM -T $userId -k CPU=CPUADDR=$addrLeft[$count]");
|
|
$count++;
|
|
}
|
|
# Remove CPUs
|
|
} else {
|
|
while ( $count <= @allCpu - $cpuCount ) {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_CPU_Delete_DM -T $userId -v $allCpu[@allCpu-$count]"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_CPU_Delete_DM -T $userId -v $allCpu[@allCpu-$count]");
|
|
$count++;
|
|
}
|
|
}
|
|
|
|
xCAT::zvmUtils->printLn( $callback, "$node: $out" );
|
|
$out = "";
|
|
}
|
|
|
|
# setmemory [size]
|
|
elsif ($args->[0] eq "--setmemory") {
|
|
# Memory hotplug not supported, just change memory size in user directory
|
|
my $size = $args->[1];
|
|
|
|
if (!($size =~ m/G/i || $size =~ m/M/i)) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Size can be Megabytes (M) or Gigabytes (G)" );
|
|
return;
|
|
}
|
|
|
|
# Set initial memory to 1M first, make this function able to increase/descrease the storage
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Definition_Update_DM -T $userId -k STORAGE_INITIAL=1M"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Definition_Update_DM -T $userId -k STORAGE_INITIAL=1M");
|
|
|
|
# Set both initial memory and maximum memory to be the same
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Definition_Update_DM -T $userId -k STORAGE_INITIAL=$size -k STORAGE_MAXIMUM=$size"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Definition_Update_DM -T $userId -k STORAGE_INITIAL=$size -k STORAGE_MAXIMUM=$size");
|
|
|
|
xCAT::zvmUtils->printLn( $callback, "$node: $out" );
|
|
$out = "";
|
|
}
|
|
|
|
# Otherwise, print out error
|
|
else {
|
|
$out = "$node: (Error) Option not supported";
|
|
}
|
|
|
|
# Only print if there is content
|
|
if ($out) {
|
|
xCAT::zvmUtils->printLn( $callback, "$out" );
|
|
}
|
|
return;
|
|
}
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 powerVM
|
|
|
|
Description : Power on or off a given node
|
|
Arguments : Node
|
|
Option [on|off|reboot|reset|stat]
|
|
Returns : Nothing
|
|
Example : powerVM($callback, $node, $args);
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
sub powerVM {
|
|
|
|
# Get inputs
|
|
my ( $callback, $node, $args ) = @_;
|
|
|
|
# Get node properties from 'zvm' table
|
|
my @propNames = ( 'hcp', 'userid' );
|
|
my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
|
|
|
|
# Get zHCP
|
|
my $hcp = $propVals->{'hcp'};
|
|
if ( !$hcp ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing node HCP" );
|
|
return;
|
|
}
|
|
|
|
# Get node user ID
|
|
my $userId = $propVals->{'userid'};
|
|
if ( !$userId ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing user ID" );
|
|
return;
|
|
}
|
|
# Capitalize user ID
|
|
$userId =~ tr/a-z/A-Z/;
|
|
|
|
xCAT::zvmUtils->printSyslog("sudoer:$::SUDOER zHCP:$hcp sudo:$::SUDO");
|
|
|
|
# Output string
|
|
my $out;
|
|
|
|
# Power on virtual server
|
|
if ( $args->[0] eq 'on' ) {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Activate -T $userId"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Activate -T $userId");
|
|
xCAT::zvmUtils->printLn( $callback, "$node: $out" );
|
|
}
|
|
|
|
# Power off virtual server
|
|
elsif ( $args->[0] eq 'off' ) {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Deactivate -T $userId -f IMMED"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Deactivate -T $userId");
|
|
xCAT::zvmUtils->printLn( $callback, "$node: $out" );
|
|
}
|
|
|
|
# Power off virtual server (gracefully)
|
|
elsif ( $args->[0] eq 'softoff' ) {
|
|
if (`/opt/xcat/bin/pping $node` !~ m/noping/i) {
|
|
$out = `ssh -o ConnectTimeout=10 $::SUDOER\@$node "shutdown -h now"`;
|
|
sleep(15); # Wait 15 seconds before logging user off
|
|
}
|
|
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Deactivate -T $userId"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Deactivate -T $userId");
|
|
xCAT::zvmUtils->printLn( $callback, "$node: $out" );
|
|
}
|
|
|
|
# Get the status (on|off)
|
|
elsif ( $args->[0] eq 'stat' ) {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/vmcp q user $userId 2>/dev/null" | sed 's/HCPCQU045E.*/off/' | sed 's/$userId.*/on/'`;
|
|
|
|
# Wait for output
|
|
my $max = 0;
|
|
while ( !$out && $max < 10 ) {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/vmcp q user $userId 2>/dev/null" | sed 's/HCPCQU045E.*/off/' | sed 's/$userId.*/on/'`;
|
|
$max++;
|
|
}
|
|
|
|
xCAT::zvmUtils->printLn( $callback, "$node: $out" );
|
|
}
|
|
|
|
# Reset a virtual server
|
|
elsif ( $args->[0] eq 'reset' ) {
|
|
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Deactivate -T $userId"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Deactivate -T $userId");
|
|
xCAT::zvmUtils->printLn( $callback, "$node: $out" );
|
|
|
|
# Wait for output
|
|
while ( `ssh $::SUDOER\@$hcp "$::SUDO /sbin/vmcp q user $userId 2>/dev/null" | sed 's/HCPCQU045E.*/Done/'` != "Done" ) {
|
|
# Do nothing
|
|
}
|
|
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Activate -T $userId"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Activate -T $userId");
|
|
xCAT::zvmUtils->printLn( $callback, "$node: $out" );
|
|
}
|
|
|
|
# Reboot a virtual server
|
|
elsif ( $args->[0] eq 'reboot' ) {
|
|
my $timeout = 0;
|
|
$out = `ssh -o ConnectTimeout=10 $::SUDOER\@$node "shutdown -r now &>/dev/null && echo Done"`;
|
|
if (!($out =~ m/Done/)) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Connecting to $node... Failed\n" );
|
|
return;
|
|
}
|
|
|
|
# Wait until node is down or 180 seconds
|
|
while ((`/opt/xcat/bin/pping $node` !~ m/noping/i) && $timeout < 180) {
|
|
sleep(1);
|
|
$timeout++;
|
|
}
|
|
if ($timeout >= 180) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Shuting down $userId... Failed\n" );
|
|
return;
|
|
}
|
|
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Shuting down $userId... Done\n" );
|
|
|
|
# Wait until node is up or 180 seconds
|
|
$timeout = 0;
|
|
while ((`/opt/xcat/bin/pping $node` =~ m/noping/i) && $timeout < 180) {
|
|
sleep(1);
|
|
$timeout++;
|
|
}
|
|
if ($timeout >= 180) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Rebooting $userId... Failed\n" );
|
|
return;
|
|
}
|
|
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Rebooting $userId... Done\n" );
|
|
}
|
|
|
|
# Pause a virtual server
|
|
elsif ( $args->[0] eq 'pause' ) {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Pause -T $userId -k PAUSE=YES"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Pause -T $userId -k PAUSE=YES");
|
|
xCAT::zvmUtils->printLn( $callback, "$node: $out" );
|
|
}
|
|
|
|
# Unpause a virtual server
|
|
elsif ( $args->[0] eq 'unpause' ) {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Pause -T $userId -k PAUSE=NO"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Pause -T $userId -k PAUSE=NO");
|
|
xCAT::zvmUtils->printLn( $callback, "$node: $out" );
|
|
}
|
|
|
|
else {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Option not supported" );
|
|
}
|
|
return;
|
|
}
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 scanVM
|
|
|
|
Description : Get node information from zHCP
|
|
Arguments : zHCP
|
|
Returns : Nothing
|
|
Example : scanVM($callback, $node, $args);
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
sub scanVM {
|
|
|
|
# Get inputs
|
|
my ( $callback, $node, $args ) = @_;
|
|
my $write2db = '';
|
|
if ($args) {
|
|
@ARGV = @$args;
|
|
|
|
# Parse options
|
|
GetOptions( 'w' => \$write2db );
|
|
}
|
|
|
|
# Get node properties from 'zvm' table
|
|
my @propNames = ( 'hcp', 'userid' );
|
|
my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
|
|
|
|
# Get zHCP
|
|
my $hcp = $propVals->{'hcp'};
|
|
if ( !$hcp ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing node HCP" );
|
|
return;
|
|
}
|
|
|
|
# Get node user ID
|
|
my $userId = $propVals->{'userid'};
|
|
if ( !$userId ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing user ID" );
|
|
return;
|
|
}
|
|
# Capitalize user ID
|
|
$userId =~ tr/a-z/A-Z/;
|
|
|
|
xCAT::zvmUtils->printSyslog("sudoer:$::SUDOER zHCP:$hcp sudo:$::SUDO");
|
|
|
|
# Exit if node is not a HCP
|
|
if ( !( $hcp =~ m/$node/i ) ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) $node is not a hardware control point" );
|
|
return;
|
|
}
|
|
|
|
# Print output string
|
|
# [Node name]:
|
|
# objtype=node
|
|
# id=[userID]
|
|
# arch=[Architecture]
|
|
# hcp=[HCP node name]
|
|
# groups=[Group]
|
|
# mgt=zvm
|
|
#
|
|
# gpok123:
|
|
# objtype=node
|
|
# id=LINUX123
|
|
# arch=s390x
|
|
# hcp=gpok456.endicott.ibm.com
|
|
# groups=all
|
|
# mgt=zvm
|
|
|
|
# Output string
|
|
my $str = "";
|
|
|
|
# Get nodes managed by this zHCP
|
|
# Look in 'zvm' table
|
|
my $tab = xCAT::Table->new( 'zvm', -create => 1, -autocommit => 0 );
|
|
my @entries = $tab->getAllAttribsWhere( "hcp like '%" . $hcp . "%'", 'node', 'userid' );
|
|
|
|
my $out;
|
|
my $node;
|
|
my $id;
|
|
my $os;
|
|
my $arch;
|
|
my $groups;
|
|
|
|
# Get node hierarchy from /proc/sysinfo
|
|
my $hierarchy;
|
|
my $host = xCAT::zvmCPUtils->getHost($::SUDOER, $hcp);
|
|
my $sysinfo = `ssh -o ConnectTimeout=5 $::SUDOER\@$hcp "$::SUDO cat /proc/sysinfo"`;
|
|
|
|
# Get node CEC
|
|
my $cec = `echo "$sysinfo" | grep "Sequence Code"`;
|
|
my @args = split( ':', $cec );
|
|
# Remove leading spaces and zeros
|
|
$args[1] =~ s/^\s*0*//;
|
|
$cec = xCAT::zvmUtils->trimStr($args[1]);
|
|
|
|
# Get node LPAR
|
|
my $lpar = `echo "$sysinfo" | grep "LPAR Name"`;
|
|
@args = split( ':', $lpar );
|
|
$lpar = xCAT::zvmUtils->trimStr($args[1]);
|
|
|
|
# Save CEC, LPAR, and zVM to 'zvm' table
|
|
my %propHash;
|
|
if ($write2db) {
|
|
# Save CEC to 'zvm' table
|
|
%propHash = (
|
|
'nodetype' => 'cec',
|
|
'parent' => ''
|
|
);
|
|
xCAT::zvmUtils->setNodeProps( 'zvm', $cec, \%propHash );
|
|
|
|
# Save LPAR to 'zvm' table
|
|
%propHash = (
|
|
'nodetype' => 'lpar',
|
|
'parent' => $cec
|
|
);
|
|
xCAT::zvmUtils->setNodeProps( 'zvm', $lpar, \%propHash );
|
|
|
|
# Save zVM to 'zvm' table
|
|
%propHash = (
|
|
'nodetype' => 'zvm',
|
|
'parent' => $lpar
|
|
);
|
|
xCAT::zvmUtils->setNodeProps( 'zvm', lc($host), \%propHash );
|
|
}
|
|
|
|
# Search for nodes managed by given zHCP
|
|
# Get 'node' and 'userid' properties
|
|
%propHash = ();
|
|
foreach (@entries) {
|
|
$node = $_->{'node'};
|
|
|
|
# Get groups
|
|
@propNames = ('groups');
|
|
$propVals = xCAT::zvmUtils->getNodeProps( 'nodelist', $node, @propNames );
|
|
$groups = $propVals->{'groups'};
|
|
|
|
# Load VMCP module
|
|
xCAT::zvmCPUtils->loadVmcp($::SUDOER, $node);
|
|
|
|
# Get user ID
|
|
@propNames = ('userid');
|
|
$propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
|
|
$id = $propVals->{'userid'};
|
|
if (!$id) {
|
|
$id = xCAT::zvmCPUtils->getUserId($::SUDOER, $node);
|
|
}
|
|
|
|
# Get architecture
|
|
$arch = `ssh -o ConnectTimeout=2 $::SUDOER\@$node "uname -p"`;
|
|
$arch = xCAT::zvmUtils->trimStr($arch);
|
|
if (!$arch) {
|
|
# Assume arch is s390x
|
|
$arch = 's390x';
|
|
}
|
|
|
|
# Get OS
|
|
$os = xCAT::zvmUtils->getOsVersion($::SUDOER, $node);
|
|
|
|
# Save node attributes
|
|
if ($write2db) {
|
|
|
|
# Do not save if node = host
|
|
if (!(lc($host) eq lc($node))) {
|
|
# Save to 'zvm' table
|
|
%propHash = (
|
|
'hcp' => $hcp,
|
|
'userid' => $id,
|
|
'nodetype' => 'vm',
|
|
'parent' => lc($host)
|
|
);
|
|
xCAT::zvmUtils->setNodeProps( 'zvm', $node, \%propHash );
|
|
|
|
# Save to 'nodetype' table
|
|
%propHash = (
|
|
'arch' => $arch,
|
|
'os' => $os
|
|
);
|
|
xCAT::zvmUtils->setNodeProps( 'nodetype', $node, \%propHash );
|
|
}
|
|
}
|
|
|
|
# Create output string
|
|
$str .= "$node:\n";
|
|
$str .= " objtype=node\n";
|
|
$str .= " arch=$arch\n";
|
|
$str .= " os=$os\n";
|
|
$str .= " hcp=$hcp\n";
|
|
$str .= " userid=$id\n";
|
|
$str .= " nodetype=vm\n";
|
|
$str .= " parent=$host\n";
|
|
$str .= " groups=$groups\n";
|
|
$str .= " mgt=zvm\n\n";
|
|
}
|
|
|
|
xCAT::zvmUtils->printLn( $callback, "$str" );
|
|
return;
|
|
}
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 inventoryVM
|
|
|
|
Description : Get hardware and software inventory of a given node
|
|
Arguments : Node
|
|
Type of inventory (config|all)
|
|
Returns : Nothing
|
|
Example : inventoryVM($callback, $node, $args);
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
sub inventoryVM {
|
|
|
|
# Get inputs
|
|
my ( $callback, $node, $args ) = @_;
|
|
|
|
# Output string
|
|
my $str = "";
|
|
|
|
# Check if node is pingable
|
|
if (`/opt/xcat/bin/pping $node | egrep -i "noping"`) {
|
|
$str = "$node: (Error) Host is unreachable";
|
|
xCAT::zvmUtils->printLn( $callback, "$str" );
|
|
return;
|
|
}
|
|
|
|
# Get node properties from 'zvm' table
|
|
my @propNames = ( 'hcp', 'userid' );
|
|
my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
|
|
|
|
# Get zHCP
|
|
my $hcp = $propVals->{'hcp'};
|
|
if ( !$hcp ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing node HCP" );
|
|
return;
|
|
}
|
|
|
|
# Get node user ID
|
|
my $userId = $propVals->{'userid'};
|
|
if ( !$userId ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing user ID" );
|
|
return;
|
|
}
|
|
# Capitalize user ID
|
|
$userId =~ tr/a-z/A-Z/;
|
|
|
|
xCAT::zvmUtils->printSyslog("sudoer:$::SUDOER zHCP:$hcp sudo:$::SUDO");
|
|
|
|
# Load VMCP module
|
|
xCAT::zvmCPUtils->loadVmcp($::SUDOER, $node);
|
|
|
|
# Get configuration
|
|
if ( $args->[0] eq 'config' ) {
|
|
|
|
# Get z/VM host for specified node
|
|
my $host = xCAT::zvmCPUtils->getHost($::SUDOER, $node);
|
|
|
|
# Get architecture
|
|
my $arch = xCAT::zvmUtils->getArch($::SUDOER, $node);
|
|
|
|
# Get operating system
|
|
my $os = xCAT::zvmUtils->getOs($::SUDOER, $node);
|
|
|
|
# Get privileges
|
|
my $priv = xCAT::zvmCPUtils->getPrivileges($::SUDOER, $node);
|
|
|
|
# Get memory configuration
|
|
my $memory = xCAT::zvmCPUtils->getMemory($::SUDOER, $node);
|
|
|
|
# Get max memory
|
|
my $maxMem = xCAT::zvmUtils->getMaxMemory($::SUDOER, $hcp , $node);
|
|
|
|
# Get processors configuration
|
|
my $proc = xCAT::zvmCPUtils->getCpu($::SUDOER, $node);
|
|
|
|
$str .= "z/VM UserID: $userId\n";
|
|
$str .= "z/VM Host: $host\n";
|
|
$str .= "Operating System: $os\n";
|
|
$str .= "Architecture: $arch\n";
|
|
$str .= "HCP: $hcp\n";
|
|
$str .= "Privileges: \n$priv\n";
|
|
$str .= "Total Memory: $memory\n";
|
|
$str .= "Max Memory: $maxMem\n";
|
|
$str .= "Processors: \n$proc\n";
|
|
} elsif ( $args->[0] eq 'all' ) {
|
|
|
|
# Get z/VM host for specified node
|
|
my $host = xCAT::zvmCPUtils->getHost($::SUDOER, $node);
|
|
|
|
# Get architecture
|
|
my $arch = xCAT::zvmUtils->getArch($::SUDOER, $node);
|
|
|
|
# Get operating system
|
|
my $os = xCAT::zvmUtils->getOs($::SUDOER, $node);
|
|
|
|
# Get privileges
|
|
my $priv = xCAT::zvmCPUtils->getPrivileges($::SUDOER, $node);
|
|
|
|
# Get memory configuration
|
|
my $memory = xCAT::zvmCPUtils->getMemory($::SUDOER, $node);
|
|
|
|
# Get max memory
|
|
my $maxMem = xCAT::zvmUtils->getMaxMemory($::SUDOER, $hcp , $node);
|
|
|
|
# Get processors configuration
|
|
my $proc = xCAT::zvmCPUtils->getCpu($::SUDOER, $node);
|
|
|
|
# Get disks configuration
|
|
my $storage = xCAT::zvmCPUtils->getDisks($::SUDOER, $node);
|
|
|
|
# Get NICs configuration
|
|
my $nic = xCAT::zvmCPUtils->getNic($::SUDOER, $node);
|
|
|
|
# Get zFCP device info
|
|
my $zfcp = xCAT::zvmUtils->getZfcpInfo($::SUDOER, $node);
|
|
|
|
# Get OS system up time
|
|
my $uptime = xCAT::zvmUtils->getUpTime($::SUDOER, $node);
|
|
|
|
# Get instance CPU used time
|
|
my $cputime = xCAT::zvmUtils->getUsedCpuTime($::SUDOER, $hcp , $node);
|
|
|
|
# Create output string
|
|
$str .= "z/VM UserID: $userId\n";
|
|
$str .= "z/VM Host: $host\n";
|
|
$str .= "Operating System: $os\n";
|
|
$str .= "Architecture: $arch\n";
|
|
$str .= "HCP: $hcp\n";
|
|
$str .= "Uptime: $uptime\n";
|
|
$str .= "CPU Used Time: $cputime\n";
|
|
$str .= "Privileges: \n$priv\n";
|
|
$str .= "Total Memory: $memory\n";
|
|
$str .= "Max Memory: $maxMem\n";
|
|
$str .= "Processors: \n$proc\n";
|
|
$str .= "Disks: \n$storage\n";
|
|
if ($zfcp) {
|
|
$str .= "zFCP: \n$zfcp\n";
|
|
}
|
|
$str .= "NICs: \n$nic\n";
|
|
} elsif ( $args->[0] eq '--freerepospace' ) {
|
|
|
|
# Get /install available disk size
|
|
my $freespace = xCAT::zvmUtils->getFreeRepoSpace($::SUDOER, $node);
|
|
|
|
# Create output string
|
|
if ($freespace) {
|
|
$str .= "Free Image Repository: $freespace\n";
|
|
} else {
|
|
return;
|
|
}
|
|
} else {
|
|
$str = "$node: (Error) Option not supported";
|
|
xCAT::zvmUtils->printLn( $callback, "$str" );
|
|
return;
|
|
}
|
|
|
|
# Append hostname (e.g. gpok3) in front
|
|
$str = xCAT::zvmUtils->appendHostname( $node, $str );
|
|
|
|
xCAT::zvmUtils->printLn( $callback, "$str" );
|
|
return;
|
|
}
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 listVM
|
|
|
|
Description : Show the info for a given node
|
|
Arguments : Node
|
|
Option
|
|
Returns : Nothing
|
|
Example : listVM($callback, $node);
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
sub listVM {
|
|
|
|
# Get inputs
|
|
my ( $callback, $node, $args ) = @_;
|
|
|
|
# Set cache directory
|
|
my $cache = '/var/opt/zhcp/cache';
|
|
|
|
# Get node properties from 'zvm' table
|
|
my @propNames = ( 'hcp', 'userid' );
|
|
my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
|
|
|
|
# Get zHCP
|
|
my $hcp = $propVals->{'hcp'};
|
|
if ( !$hcp ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing node HCP" );
|
|
return;
|
|
}
|
|
|
|
# Get node user ID
|
|
my $userId = $propVals->{'userid'};
|
|
if ( !$userId ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing user ID" );
|
|
return;
|
|
}
|
|
# Capitalize user ID
|
|
$userId =~ tr/a-z/A-Z/;
|
|
|
|
xCAT::zvmUtils->printSyslog("sudoer:$::SUDOER zHCP:$hcp sudo:$::SUDO");
|
|
|
|
my $out;
|
|
|
|
# Get disk pool configuration
|
|
if ( $args->[0] eq "--diskpool" ) {
|
|
# This is no longer supported in lsvm. Using inventoryHypervisor instead.
|
|
inventoryHypervisor( $callback, $node, $args );
|
|
}
|
|
|
|
# Get disk pool names
|
|
elsif ( $args->[0] eq "--diskpoolnames" ) {
|
|
# This is no longer supported in lsvm. Using inventoryHypervisor instead.
|
|
inventoryHypervisor( $callback, $node, $args );
|
|
}
|
|
|
|
# Get network names
|
|
elsif ( $args->[0] eq "--getnetworknames" ) {
|
|
# This is no longer supported in lsvm. Using inventoryHypervisor instead.
|
|
inventoryHypervisor( $callback, $node, $args );
|
|
}
|
|
|
|
# Get network
|
|
elsif ( $args->[0] eq "--getnetwork" ) {
|
|
# This is no longer supported in lsvm. Using inventoryHypervisor instead.
|
|
inventoryHypervisor( $callback, $node, $args );
|
|
}
|
|
|
|
# Get the status of all DASDs accessible to a virtual image
|
|
elsif ( $args->[0] eq "--querydisk" ) {
|
|
my $vdasd = $args->[1];
|
|
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Disk_Query -T $userId -k $vdasd"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Disk_Query -T $userId -k $vdasd");
|
|
}
|
|
|
|
# Get user profile names
|
|
elsif ( $args->[0] eq "--userprofilenames" ) {
|
|
# This is no longer supported in lsvm. Using inventoryHypervisor instead.
|
|
inventoryHypervisor( $callback, $node, $args );
|
|
}
|
|
|
|
# Get zFCP disk pool configuration
|
|
elsif ( $args->[0] eq "--zfcppool" ) {
|
|
# This is no longer supported in lsvm. Using inventoryHypervisor instead.
|
|
inventoryHypervisor( $callback, $node, $args );
|
|
}
|
|
|
|
# Get zFCP disk pool names
|
|
elsif ( $args->[0] eq "--zfcppoolnames") {
|
|
# This is no longer supported in lsvm. Using inventoryHypervisor instead.
|
|
inventoryHypervisor( $callback, $node, $args );
|
|
}
|
|
|
|
# Get user entry
|
|
elsif ( !$args->[0] ) {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Query_DM -T $userId" | sed '\$d'`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Query_DM -T $userId | sed '\$d'");
|
|
} else {
|
|
$out = "$node: (Error) Option not supported";
|
|
}
|
|
|
|
# Append hostname (e.g. gpok3) in front
|
|
$out = xCAT::zvmUtils->appendHostname( $node, $out );
|
|
xCAT::zvmUtils->printLn( $callback, "$out" );
|
|
|
|
return;
|
|
}
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 makeVM
|
|
|
|
Description : Create a virtual machine
|
|
* A unique MAC address will be assigned
|
|
Arguments : Node
|
|
Directory entry text file (optional)
|
|
Returns : Nothing
|
|
Example : makeVM($callback, $node, $args);
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
sub makeVM {
|
|
|
|
# Get inputs
|
|
my ( $callback, $node, $args ) = @_;
|
|
|
|
# Get node properties from 'zvm' table
|
|
my @propNames = ( 'hcp', 'userid' );
|
|
my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
|
|
|
|
# Get zHCP
|
|
my $hcp = $propVals->{'hcp'};
|
|
if ( !$hcp ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing node HCP" );
|
|
return;
|
|
}
|
|
|
|
# Get node user ID
|
|
my $userId = $propVals->{'userid'};
|
|
if ( !$userId ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing user ID" );
|
|
return;
|
|
}
|
|
# Capitalize user ID
|
|
$userId =~ tr/a-z/A-Z/;
|
|
|
|
xCAT::zvmUtils->printSyslog("sudoer:$::SUDOER zHCP:$hcp sudo:$::SUDO");
|
|
|
|
# Find the number of arguments
|
|
my $argsSize = @{$args};
|
|
|
|
# Create a new user in zVM without user directory entry file
|
|
my $out;
|
|
my $stdin;
|
|
my $password = "";
|
|
my $memorySize = "";
|
|
my $privilege = "";
|
|
my $profileName = "";
|
|
my $cpuCount = 1;
|
|
my $diskPool = "";
|
|
my $diskSize = "";
|
|
my $diskVdev = "";
|
|
if ($args) {
|
|
@ARGV = @$args;
|
|
|
|
# Parse options
|
|
GetOptions(
|
|
's|stdin' => \$stdin, # Directory entry contained in stdin
|
|
'p|profile=s' => \$profileName,
|
|
'w|password=s' => \$password,
|
|
'c|cpus=i' => \$cpuCount, # Optional
|
|
'm|mem=s' => \$memorySize,
|
|
'd|diskpool=s' => \$diskPool,
|
|
'z|size=s' => \$diskSize,
|
|
'v|diskvdev=s' => \$diskVdev, # Optional
|
|
'r|privilege=s' => \$privilege); # Optional
|
|
}
|
|
|
|
# If one of the options above are given, create the user without a directory entry file
|
|
if ($profileName || $password || $memorySize) {
|
|
if (!$profileName || !$password || !$memorySize) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing one or more required parameter(s)" );
|
|
return;
|
|
}
|
|
|
|
# Default privilege to G if none is given
|
|
if (!$privilege) {
|
|
$privilege = 'G';
|
|
}
|
|
|
|
# Generate temporary user directory entry file
|
|
my $userEntryFile = xCAT::zvmUtils->generateUserEntryFile($userId, $password, $memorySize, $privilege, $profileName, $cpuCount);
|
|
if ( $userEntryFile == -1 ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Failed to generate user directory entry file" );
|
|
return;
|
|
}
|
|
|
|
# Create a new user in z/VM without disks
|
|
$out = `/opt/xcat/bin/mkvm $node $userEntryFile`;
|
|
xCAT::zvmUtils->printLn( $callback, "$out");
|
|
if (xCAT::zvmUtils->checkOutput($callback, $out) == -1) {
|
|
# The error would have already been printed under mkvm
|
|
return;
|
|
}
|
|
|
|
# If one of the disk operations are given, add disk(s) to this new user
|
|
if ($diskPool || $diskSize) {
|
|
if (!$diskPool || !$diskSize) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing one or more required parameter(s) for adding disk" );
|
|
return;
|
|
}
|
|
|
|
# Default disk virtual device to 0100 if none is given
|
|
if (!$diskVdev) {
|
|
$diskVdev = "0100";
|
|
}
|
|
|
|
$out = `/opt/xcat/bin/chvm $node --add3390 $diskPool $diskVdev $diskSize`;
|
|
xCAT::zvmUtils->printLn( $callback, "$out");
|
|
if (xCAT::zvmUtils->checkOutput($callback, $out) == -1) {
|
|
# The error would have already been printed under chvm
|
|
return;
|
|
}
|
|
}
|
|
|
|
# Remove the temporary file
|
|
$out = `rm -f $userEntryFile`;
|
|
return;
|
|
}
|
|
|
|
# Get user entry file (if any)
|
|
my $userEntry;
|
|
if (!$stdin) {
|
|
$userEntry = $args->[0];
|
|
}
|
|
|
|
# Get MAC address in 'mac' table
|
|
my $macId;
|
|
my $generateNew = 1;
|
|
@propNames = ('mac');
|
|
$propVals = xCAT::zvmUtils->getNodeProps( 'mac', $node, @propNames );
|
|
|
|
# If MAC address exists
|
|
my @lines;
|
|
my @words;
|
|
if ( $propVals->{'mac'} ) {
|
|
|
|
# Get MAC suffix (MACID)
|
|
$macId = $propVals->{'mac'};
|
|
$macId = xCAT::zvmUtils->replaceStr( $macId, ":", "" );
|
|
$macId = substr( $macId, 6 );
|
|
} else {
|
|
$out = `ssh -o ConnectTimeout=5 $::SUDOER\@$hcp "/sbin/modprobe vmcp"`;
|
|
|
|
# Get USER Prefix
|
|
my $prefix = `ssh -o ConnectTimeout=5 $::SUDOER\@$hcp "$::SUDO /sbin/vmcp q vmlan" | egrep -i "USER Prefix:"`;
|
|
$prefix =~ s/(.*?)USER Prefix:(.*)/$2/;
|
|
$prefix =~ s/^\s+//;
|
|
$prefix =~ s/\s+$//;
|
|
|
|
# Get MACADDR Prefix instead if USER Prefix is not defined
|
|
if (!$prefix) {
|
|
$prefix = `ssh -o ConnectTimeout=5 $::SUDOER\@$hcp "$::SUDO /sbin/vmcp q vmlan" | egrep -i "MACADDR Prefix:"`;
|
|
$prefix =~ s/(.*?)MACADDR Prefix:(.*)/$2/;
|
|
$prefix =~ s/^\s+//;
|
|
$prefix =~ s/\s+$//;
|
|
|
|
if (!$prefix) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Could not find the MACADDR/USER prefix of the z/VM system" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Solution) Verify that the node's zHCP($hcp) is correct, the node is online, and the SSH keys are setup for the zHCP" );
|
|
return;
|
|
}
|
|
}
|
|
|
|
# Generate MAC address
|
|
my $mac;
|
|
while ($generateNew) {
|
|
|
|
# If no MACID is found, get one
|
|
$macId = xCAT::zvmUtils->getMacID($::SUDOER, $hcp);
|
|
if ( !$macId ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Could not generate MACID" );
|
|
return;
|
|
}
|
|
|
|
# Create MAC address
|
|
$mac = $prefix . $macId;
|
|
|
|
# If length is less than 12, append a zero
|
|
if ( length($mac) != 12 ) {
|
|
$mac = "0" . $mac;
|
|
}
|
|
|
|
# Format MAC address
|
|
$mac =
|
|
substr( $mac, 0, 2 ) . ":"
|
|
. substr( $mac, 2, 2 ) . ":"
|
|
. substr( $mac, 4, 2 ) . ":"
|
|
. substr( $mac, 6, 2 ) . ":"
|
|
. substr( $mac, 8, 2 ) . ":"
|
|
. substr( $mac, 10, 2 );
|
|
|
|
# Check 'mac' table for MAC address
|
|
my $tab = xCAT::Table->new( 'mac', -create => 1, -autocommit => 0 );
|
|
my @entries = $tab->getAllAttribsWhere( "mac = '" . $mac . "'", 'node' );
|
|
|
|
# If MAC address exists
|
|
if (@entries) {
|
|
# Generate new MACID
|
|
$out = xCAT::zvmUtils->generateMacId($::SUDOER, $hcp);
|
|
$generateNew = 1;
|
|
} else {
|
|
$generateNew = 0;
|
|
|
|
# Save MAC address in 'mac' table
|
|
xCAT::zvmUtils->setNodeProp( 'mac', $node, 'mac', $mac );
|
|
|
|
# Generate new MACID
|
|
$out = xCAT::zvmUtils->generateMacId($::SUDOER, $hcp);
|
|
}
|
|
} # End of while ($generateNew)
|
|
}
|
|
|
|
# Create virtual server
|
|
my $line;
|
|
my @hcpNets;
|
|
my $netName = '';
|
|
my $oldNicDef;
|
|
my $nicDef;
|
|
my $id;
|
|
my $rc;
|
|
my @vswId;
|
|
my $target = "$::SUDOER\@$hcp";
|
|
if ($userEntry) {
|
|
# Copy user entry
|
|
$out = `cp $userEntry /tmp/$node.txt`;
|
|
$userEntry = "/tmp/$node.txt";
|
|
|
|
# If the directory entry contains a NICDEF statement, append MACID to the end
|
|
# User must select the right one (layer) based on template chosen
|
|
$out = `cat $userEntry | egrep -i "NICDEF"`;
|
|
if ($out) {
|
|
|
|
# Get the networks used by the zHCP
|
|
@hcpNets = xCAT::zvmCPUtils->getNetworkNamesArray($::SUDOER, $hcp);
|
|
|
|
# Search user entry for network name
|
|
foreach (@hcpNets) {
|
|
if ( $out =~ m/ $_/i ) {
|
|
$netName = $_;
|
|
last;
|
|
}
|
|
}
|
|
|
|
# Find NICDEF statement
|
|
$oldNicDef = `cat $userEntry | egrep -i "NICDEF" | egrep -i "$netName"`;
|
|
if ($oldNicDef) {
|
|
$oldNicDef = xCAT::zvmUtils->trimStr($oldNicDef);
|
|
$nicDef = xCAT::zvmUtils->replaceStr($oldNicDef, $netName, "$netName MACID $macId");
|
|
|
|
# Append MACID at the end
|
|
$out = `sed -i -e "s,$oldNicDef,$nicDef,i" $userEntry`;
|
|
}
|
|
}
|
|
|
|
# Open user entry
|
|
$out = `cat $userEntry`;
|
|
@lines = split( '\n', $out );
|
|
|
|
# Get the userID in user entry
|
|
$line = xCAT::zvmUtils->trimStr( $lines[0] );
|
|
@words = split( ' ', $line );
|
|
$id = $words[1];
|
|
|
|
# Change userID in user entry to match userID defined in xCAT
|
|
$out = `sed -i -e "s,$id,$userId,i" $userEntry`;
|
|
|
|
# SCP file over to zHCP
|
|
$out = `scp $userEntry $target:$userEntry`;
|
|
|
|
# Create virtual server
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Create_DM -T $userId -f $userEntry"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Create_DM -T $userId -f $userEntry");
|
|
xCAT::zvmUtils->printLn( $callback, "$node: $out" );
|
|
|
|
# Check output
|
|
$rc = xCAT::zvmUtils->checkOutput( $callback, $out );
|
|
if ( $rc == 0 ) {
|
|
|
|
# Get VSwitch of zHCP (if any)
|
|
@vswId = xCAT::zvmCPUtils->getVswitchId($::SUDOER, $hcp);
|
|
|
|
# Grant access to VSwitch for Linux user
|
|
# GuestLan do not need permissions
|
|
foreach (@vswId) {
|
|
$out = xCAT::zvmCPUtils->grantVSwitch( $callback, $::SUDOER, $hcp, $userId, $_ );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Granting VSwitch ($_) access for $userId... $out" );
|
|
}
|
|
|
|
# Remove user entry file (on zHCP)
|
|
$out = `ssh -o ConnectTimeout=5 $::SUDOER\@$hcp "$::SUDO rm $userEntry"`;
|
|
}
|
|
|
|
# Remove user entry on xCAT
|
|
$out = `rm -rf $userEntry`;
|
|
} elsif ($stdin) {
|
|
# Take directory entry from stdin
|
|
$stdin = $::STDIN;
|
|
|
|
# If the directory entry contains a NICDEF statement, append MACID to the end
|
|
# User must select the right one (layer) based on template chosen
|
|
$out = `echo -e "$stdin" | egrep -i "NICDEF"`;
|
|
if ($out) {
|
|
# Get the networks used by the zHCP
|
|
@hcpNets = xCAT::zvmCPUtils->getNetworkNamesArray($::SUDOER, $hcp);
|
|
|
|
# Search user entry for network name
|
|
$netName = '';
|
|
foreach (@hcpNets) {
|
|
if ( $out =~ m/ $_/i ) {
|
|
$netName = $_;
|
|
last;
|
|
}
|
|
}
|
|
|
|
# Find NICDEF statement
|
|
$oldNicDef = `echo -e "$stdin" | egrep -i "NICDEF" | egrep -i "$netName"`;
|
|
if ($oldNicDef) {
|
|
$oldNicDef = xCAT::zvmUtils->trimStr($oldNicDef);
|
|
|
|
# Append MACID at the end
|
|
$nicDef = xCAT::zvmUtils->replaceStr( $oldNicDef, $netName, "$netName MACID $macId" );
|
|
# Update stdin
|
|
$stdin =~ s/$oldNicDef/$nicDef/g;
|
|
}
|
|
}
|
|
|
|
# Create a temporary file to contain directory on zHCP
|
|
my $file = "/tmp/" . $node . ".direct";
|
|
@lines = split("\n", $stdin);
|
|
|
|
# Delete existing file on zHCP (if any)
|
|
`ssh $::SUDOER\@$hcp "rm -rf $file"`;
|
|
|
|
# Write directory entry into temporary file
|
|
# because directory entry cannot be remotely echoed into stdin
|
|
foreach (@lines) {
|
|
if ($_) {
|
|
$_ = "'" . $_ . "'";
|
|
`ssh $::SUDOER\@$hcp "echo $_ >> $file"`;
|
|
}
|
|
}
|
|
|
|
# Create virtual server
|
|
$out = `ssh $::SUDOER\@$hcp "cat $file | $::SUDO $::DIR/smcli Image_Create_DM -T $userId -s"`;
|
|
xCAT::zvmUtils->printSyslog("ssh $::SUDOER\@$hcp cat $file | $::SUDO $::DIR/smcli Image_Create_DM -T $userId -s");
|
|
xCAT::zvmUtils->printLn( $callback, "$node: $out" );
|
|
|
|
# Check output
|
|
$rc = xCAT::zvmUtils->checkOutput( $callback, $out );
|
|
if ( $rc == 0 ) {
|
|
|
|
# Get VSwitch of zHCP (if any)
|
|
@vswId = xCAT::zvmCPUtils->getVswitchId($::SUDOER, $hcp);
|
|
|
|
# Grant access to VSwitch for Linux user
|
|
# GuestLan do not need permissions
|
|
foreach (@vswId) {
|
|
$out = xCAT::zvmCPUtils->grantVSwitch( $callback, $::SUDOER, $hcp, $userId, $_ );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Granting VSwitch ($_) access for $userId... $out" );
|
|
}
|
|
|
|
# Delete created file on zHCP
|
|
`ssh -o ConnectTimeout=5 $::SUDOER\@$hcp "rm -rf $file"`;
|
|
}
|
|
} else {
|
|
|
|
# Create NOLOG virtual server
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/createvs $userId"`;
|
|
xCAT::zvmUtils->printLn( $callback, "$node: $out" );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 cloneVM
|
|
|
|
Description : Clone a virtual server
|
|
Arguments : Node
|
|
Disk pool
|
|
Disk password
|
|
Returns : Nothing
|
|
Example : cloneVM($callback, $targetNode, $args);
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
sub cloneVM {
|
|
|
|
# Get inputs
|
|
my ( $callback, $nodes, $args ) = @_;
|
|
|
|
# Get nodes
|
|
my @nodes = @$nodes;
|
|
|
|
# Return code for each command
|
|
my $rc;
|
|
my $out;
|
|
|
|
# Child process IDs
|
|
my @children;
|
|
|
|
# Process ID for xfork()
|
|
my $pid;
|
|
|
|
# Get source node
|
|
my $sourceNode = $args->[0];
|
|
my @propNames = ( 'hcp', 'userid' );
|
|
my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $sourceNode, @propNames );
|
|
|
|
# Get zHCP
|
|
my $srcHcp = $propVals->{'hcp'};
|
|
|
|
# Get node user ID
|
|
my $sourceId = $propVals->{'userid'};
|
|
# Capitalize user ID
|
|
$sourceId =~ tr/a-z/A-Z/;
|
|
|
|
# Get operating system, e.g. sles11sp2 or rhel6.2
|
|
@propNames = ( 'os' );
|
|
$propVals = xCAT::zvmUtils->getNodeProps( 'nodetype', $sourceNode, @propNames );
|
|
my $srcOs = $propVals->{'os'};
|
|
|
|
# Set IP address
|
|
my $sourceIp = xCAT::zvmUtils->getIp($sourceNode);
|
|
|
|
# Get networks in 'networks' table
|
|
my $netEntries = xCAT::zvmUtils->getAllTabEntries('networks');
|
|
my $srcNetwork = "";
|
|
my $srcMask;
|
|
foreach (@$netEntries) {
|
|
# Get source network and mask
|
|
$srcNetwork = $_->{'net'};
|
|
$srcMask = $_->{'mask'};
|
|
|
|
# If the host IP address is in this subnet, return
|
|
if (xCAT::NetworkUtils->ishostinsubnet($sourceIp, $srcMask, $srcNetwork)) {
|
|
|
|
# Exit loop
|
|
last;
|
|
} else {
|
|
$srcNetwork = "";
|
|
}
|
|
}
|
|
|
|
xCAT::zvmUtils->printSyslog("sudoer:$::SUDOER zHCP:$srcHcp sudo:$::SUDO");
|
|
xCAT::zvmUtils->printSyslog("srcHcp:$srcHcp sourceId:$sourceId srcOs:$srcOs srcNetwork:$srcNetwork srcMask:$srcMask");
|
|
|
|
foreach (@nodes) {
|
|
xCAT::zvmUtils->printLn( $callback, "$_: Cloning $sourceNode" );
|
|
|
|
# Exit if missing source node
|
|
if ( !$sourceNode ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$_: (Error) Missing source node" );
|
|
return;
|
|
}
|
|
|
|
# Exit if missing source HCP
|
|
if ( !$srcHcp ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$_: (Error) Missing source node HCP" );
|
|
return;
|
|
}
|
|
|
|
# Exit if missing source user ID
|
|
if ( !$sourceId ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$_: (Error) Missing source user ID" );
|
|
return;
|
|
}
|
|
|
|
# Exit if missing source operating system
|
|
if ( !$srcOs ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$_: (Error) Missing source operating system" );
|
|
return;
|
|
}
|
|
|
|
# Exit if missing source operating system
|
|
if ( !$sourceIp || !$srcNetwork || !$srcMask ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$_: (Error) Missing source IP, network, or mask" );
|
|
return;
|
|
}
|
|
|
|
# Get target node
|
|
@propNames = ( 'hcp', 'userid' );
|
|
$propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $_, @propNames );
|
|
|
|
# Get target HCP
|
|
my $tgtHcp = $propVals->{'hcp'};
|
|
|
|
# Get node userID
|
|
my $tgtId = $propVals->{'userid'};
|
|
# Capitalize userID
|
|
$tgtId =~ tr/a-z/A-Z/;
|
|
|
|
# Exit if missing target zHCP
|
|
if ( !$tgtHcp ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$_: (Error) Missing target node HCP" );
|
|
return;
|
|
}
|
|
|
|
# Exit if missing target user ID
|
|
if ( !$tgtId ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$_: (Error) Missing target user ID" );
|
|
return;
|
|
}
|
|
|
|
# Exit if source and target zHCP are not equal
|
|
if ( $srcHcp ne $tgtHcp ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$_: (Error) Source and target HCP are not equal" );
|
|
xCAT::zvmUtils->printLn( $callback, "$_: (Solution) Set the source and target HCP appropriately in the zvm table" );
|
|
return;
|
|
}
|
|
|
|
#*** Get MAC address ***
|
|
my $targetMac;
|
|
my $macId;
|
|
my $generateNew = 0; # Flag to generate new MACID
|
|
@propNames = ('mac');
|
|
$propVals = xCAT::zvmUtils->getNodeProps( 'mac', $_, @propNames );
|
|
if ( !$propVals->{'mac'} ) {
|
|
|
|
# If no MACID is found, get one
|
|
$macId = xCAT::zvmUtils->getMacID($::SUDOER, $tgtHcp);
|
|
if ( !$macId ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$_: (Error) Could not generate MACID" );
|
|
return;
|
|
}
|
|
|
|
# Create MAC address (target)
|
|
$targetMac = xCAT::zvmUtils->createMacAddr( $::SUDOER, $_, $macId );
|
|
|
|
# Save MAC address in 'mac' table
|
|
xCAT::zvmUtils->setNodeProp( 'mac', $_, 'mac', $targetMac );
|
|
|
|
# Generate new MACID
|
|
$out = xCAT::zvmUtils->generateMacId($::SUDOER, $tgtHcp);
|
|
}
|
|
|
|
xCAT::zvmUtils->printSyslog("tgtHcp:$tgtHcp tgtId:$tgtId targetMac:$targetMac macId:$macId");
|
|
}
|
|
|
|
#*** Link source disks ***
|
|
# Get MDisk statements of source node
|
|
my @words;
|
|
my $addr;
|
|
my $type;
|
|
my $linkAddr;
|
|
my $i;
|
|
|
|
# Hash table of source disk addresses
|
|
# $srcLinkAddr[$addr] = $linkAddr
|
|
my %srcLinkAddr;
|
|
my %srcDiskSize;
|
|
|
|
# Hash table of source disk type
|
|
# $srcLinkAddr[$addr] = $type
|
|
my %srcDiskType;
|
|
my @srcDisks = xCAT::zvmUtils->getMdisks( $callback, $::SUDOER, $sourceNode );
|
|
|
|
# Get details about source disks
|
|
# Output is similar to:
|
|
# MDISK=VDEV=0100 DEVTYPE=3390 START=0001 COUNT=10016 VOLID=EMC2C4 MODE=MR
|
|
$out = `ssh $::SUDOER\@$srcHcp "$::SUDO $::DIR/smcli Image_Definition_Query_DM -T $sourceId -k MDISK"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Definition_Query_DM -T $sourceId -k MDISK");
|
|
xCAT::zvmUtils->printSyslog("$out");
|
|
my $srcDiskDet = xCAT::zvmUtils->trimStr($out);
|
|
foreach (@srcDisks) {
|
|
|
|
# Get disk address
|
|
@words = split( ' ', $_ );
|
|
$addr = $words[1];
|
|
$type = $words[2];
|
|
|
|
# Add 0 in front if address length is less than 4
|
|
while (length($addr) < 4) {
|
|
$addr = '0' . $addr;
|
|
}
|
|
|
|
# Get disk type
|
|
$srcDiskType{$addr} = $type;
|
|
|
|
# Get disk size (cylinders or blocks)
|
|
# ECKD or FBA disk
|
|
if ( $type eq '3390' || $type eq '9336' ) {
|
|
my @lines = split( '\n', $srcDiskDet );
|
|
|
|
# Loop through each line
|
|
for ( $i = 0 ; $i < @lines ; $i++ ) {
|
|
$lines[$i] =~ s/MDISK=//g;
|
|
|
|
# Extract NIC address
|
|
@words = ($lines[$i] =~ m/=(\S+)/g);
|
|
my $srcDiskAddr = $words[0];
|
|
|
|
$srcDiskSize{$srcDiskAddr} = $words[3];
|
|
xCAT::zvmUtils->printSyslog("addr:$addr type:$type srcDiskAddr:$srcDiskAddr srcDiskSize:$words[3]");
|
|
}
|
|
}
|
|
|
|
# If source disk is not linked
|
|
my $try = 5;
|
|
while ( $try > 0 ) {
|
|
|
|
# New disk address
|
|
$linkAddr = $addr + 1000;
|
|
|
|
# Check if new disk address is used (source)
|
|
$rc = xCAT::zvmUtils->isAddressUsed( $::SUDOER, $srcHcp, $linkAddr );
|
|
|
|
# If disk address is used (source)
|
|
while ( $rc == 0 ) {
|
|
|
|
# Generate a new disk address
|
|
# Sleep 5 seconds to let existing disk appear
|
|
sleep(5);
|
|
$linkAddr = $linkAddr + 1;
|
|
$rc = xCAT::zvmUtils->isAddressUsed( $::SUDOER, $srcHcp, $linkAddr );
|
|
}
|
|
|
|
$srcLinkAddr{$addr} = $linkAddr;
|
|
|
|
# Link source disk to HCP
|
|
foreach (@nodes) {
|
|
xCAT::zvmUtils->printLn( $callback, "$_: Linking source disk ($addr) as ($linkAddr)" );
|
|
}
|
|
$out = `ssh -o ConnectTimeout=5 $::SUDOER\@$srcHcp "$::SUDO /sbin/vmcp link $sourceId $addr $linkAddr RR"`;
|
|
|
|
if ( $out =~ m/not linked/i ) {
|
|
# Do nothing
|
|
} else {
|
|
last;
|
|
}
|
|
|
|
$try = $try - 1;
|
|
|
|
# Wait before next try
|
|
sleep(5);
|
|
} # End of while ( $try > 0 )
|
|
|
|
# If source disk is not linked
|
|
if ( $out =~ m/not linked/i ) {
|
|
foreach (@nodes) {
|
|
xCAT::zvmUtils->printLn( $callback, "$_: Failed" );
|
|
}
|
|
|
|
# Exit
|
|
return;
|
|
}
|
|
|
|
# Enable source disk
|
|
$out = xCAT::zvmUtils->disableEnableDisk( $::SUDOER, $srcHcp, "-e", $linkAddr );
|
|
} # End of foreach (@srcDisks)
|
|
|
|
# Get the networks the HCP is on
|
|
my @hcpNets = xCAT::zvmCPUtils->getNetworkNamesArray($::SUDOER, $srcHcp);
|
|
|
|
# Get the NICDEF address of the network on the source node
|
|
my @tmp;
|
|
my $srcNicAddr = '';
|
|
my $hcpNetName = '';
|
|
|
|
# Find the NIC address
|
|
xCAT::zvmCPUtils->loadVmcp($::SUDOER, $sourceNode);
|
|
$out = `ssh $::SUDOER\@$srcHcp "$::SUDO $::DIR/smcli Image_Definition_Query_DM -T $sourceId -k NICDEF"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Definition_Query_DM -T $sourceId -k NICDEF");
|
|
xCAT::zvmUtils->printSyslog("$out");
|
|
# Output is similar to:
|
|
# NICDEF_PROFILE=VDEV=0800 TYPE=QDIO LAN=SYSTEM SWITCHNAME=VSW2
|
|
# NICDEF=VDEV=0900 TYPE=QDIO DEVICES=3 LAN=SYSTEM SWITCHNAME=GLAN1
|
|
# NICDEF=VDEV=0A00 TYPE=QDIO DEVICES=3 LAN=SYSTEM SWITCHNAME=VSW2
|
|
|
|
my @lines = split( '\n', $out );
|
|
|
|
# Loop through each line
|
|
my $line;
|
|
for ( $i = 0 ; $i < @lines ; $i++ ) {
|
|
# Loop through each network name
|
|
foreach (@hcpNets) {
|
|
# If the network is found
|
|
if ( $lines[$i] =~ m/SWITCHNAME=$_/i ) {
|
|
# Save network name
|
|
$hcpNetName = $_;
|
|
|
|
$lines[$i] =~ s/NICDEF_PROFILE=//g;
|
|
$lines[$i] =~ s/NICDEF=//g;
|
|
|
|
# Extract NIC address
|
|
@words = ($lines[$i] =~ m/=(\S+)/g);
|
|
$srcNicAddr = $words[0];
|
|
xCAT::zvmUtils->printSyslog("hcpNetName:$hcpNetName srcNicAddr:$srcNicAddr");
|
|
|
|
# Grab only the 1st match
|
|
last;
|
|
}
|
|
}
|
|
}
|
|
|
|
# If no network name is found, exit
|
|
if (!$hcpNetName || !$srcNicAddr) {
|
|
#*** Detatch source disks ***
|
|
for $addr ( keys %srcLinkAddr ) {
|
|
$linkAddr = $srcLinkAddr{$addr};
|
|
|
|
# Disable and detatch source disk
|
|
$out = xCAT::zvmUtils->disableEnableDisk( $::SUDOER, $srcHcp, "-d", $linkAddr );
|
|
$out = `ssh -o ConnectTimeout=5 $::SUDOER\@$srcHcp "$::SUDO /sbin/vmcp det $linkAddr"`;
|
|
foreach (@nodes) {
|
|
xCAT::zvmUtils->printLn( $callback, "$_: Detatching source disk ($addr) at ($linkAddr)" );
|
|
}
|
|
}
|
|
|
|
foreach (@nodes) {
|
|
xCAT::zvmUtils->printLn( $callback, "$_: (Error) No suitable network device found in user directory entry" );
|
|
xCAT::zvmUtils->printLn( $callback, "$_: (Solution) Verify that the node has one of the following network devices: @hcpNets" );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
# Get vSwitch of source node (if any)
|
|
my @srcVswitch = xCAT::zvmCPUtils->getVswitchId($::SUDOER, $srcHcp);
|
|
|
|
# Get source MAC address in 'mac' table
|
|
my $srcMac;
|
|
@propNames = ('mac');
|
|
$propVals = xCAT::zvmUtils->getNodeProps( 'mac', $sourceNode, @propNames );
|
|
if ( $propVals->{'mac'} ) {
|
|
|
|
# Get MAC address
|
|
$srcMac = $propVals->{'mac'};
|
|
}
|
|
|
|
# Get user entry of source node
|
|
my $srcUserEntry = "/tmp/$sourceNode.txt";
|
|
$out = `rm $srcUserEntry`;
|
|
$out = xCAT::zvmUtils->getUserEntryWODisk( $callback, $::SUDOER, $sourceNode, $srcUserEntry );
|
|
|
|
# Check if user entry is valid
|
|
$out = `cat $srcUserEntry`;
|
|
|
|
# If output contains USER LINUX123, then user entry is good
|
|
if ( $out =~ m/USER $sourceId/i ) {
|
|
|
|
# Turn off source node
|
|
if (`/opt/xcat/bin/pping $sourceNode` =~ m/ ping/i) {
|
|
$out = `ssh -o ConnectTimeout=10 $sourceNode "shutdown -h now"`;
|
|
sleep(90); # Wait 1.5 minutes before logging user off
|
|
|
|
foreach (@nodes) {
|
|
xCAT::zvmUtils->printLn( $callback, "$_: Shutting down $sourceNode" );
|
|
}
|
|
}
|
|
|
|
$out = `ssh $::SUDOER\@$srcHcp "$::SUDO $::DIR/smcli Image_Deactivate -T $sourceId"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Deactivate -T $sourceId");
|
|
xCAT::zvmUtils->printSyslog("$out");
|
|
|
|
#*** Clone source node ***
|
|
# Remove flashcopy lock (if any)
|
|
$out = `ssh $::SUDOER\@$srcHcp "$::SUDO rm -f /tmp/.flashcopy_lock"`;
|
|
foreach (@nodes) {
|
|
$pid = xCAT::Utils->xfork();
|
|
|
|
# Parent process
|
|
if ($pid) {
|
|
push( @children, $pid );
|
|
}
|
|
|
|
# Child process
|
|
elsif ( $pid == 0 ) {
|
|
clone(
|
|
$callback, $_, $args, \@srcDisks, \%srcLinkAddr, \%srcDiskSize, \%srcDiskType,
|
|
$srcNicAddr, $hcpNetName, \@srcVswitch, $srcOs, $srcMac, $netEntries, $sourceIp, $srcNetwork, $srcMask
|
|
);
|
|
|
|
# Exit process
|
|
exit(0);
|
|
}
|
|
|
|
# End of elsif
|
|
else {
|
|
# Ran out of resources
|
|
die "Error: Could not fork\n";
|
|
}
|
|
|
|
# Clone 4 nodes at a time
|
|
# If you handle more than this, some nodes will not be cloned
|
|
# You will get errors because SMAPI cannot handle many nodes
|
|
if ( !( @children % 4 ) ) {
|
|
|
|
# Wait for all processes to end
|
|
foreach (@children) {
|
|
waitpid( $_, 0 );
|
|
}
|
|
|
|
# Clear children
|
|
@children = ();
|
|
}
|
|
} # End of foreach
|
|
|
|
# Handle the remaining nodes
|
|
# Wait for all processes to end
|
|
foreach (@children) {
|
|
waitpid( $_, 0 );
|
|
}
|
|
|
|
# Remove source user entry
|
|
$out = `rm $srcUserEntry`;
|
|
} # End of if
|
|
|
|
#*** Detatch source disks ***
|
|
for $addr ( keys %srcLinkAddr ) {
|
|
$linkAddr = $srcLinkAddr{$addr};
|
|
|
|
# Disable and detatch source disk
|
|
$out = xCAT::zvmUtils->disableEnableDisk( $::SUDOER, $srcHcp, "-d", $linkAddr );
|
|
$out = `ssh -o ConnectTimeout=5 $::SUDOER\@$srcHcp "$::SUDO /sbin/vmcp det $linkAddr"`;
|
|
|
|
foreach (@nodes) {
|
|
xCAT::zvmUtils->printLn( $callback, "$_: Detatching source disk ($addr) at ($linkAddr)" );
|
|
}
|
|
}
|
|
|
|
#*** Done ***
|
|
foreach (@nodes) {
|
|
xCAT::zvmUtils->printLn( $callback, "$_: Done" );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 clone
|
|
|
|
Description : Clone a virtual server
|
|
Arguments : Target node
|
|
Disk pool
|
|
Disk password (optional)
|
|
Source disks
|
|
Source disk link addresses
|
|
Source disk sizes
|
|
NIC address
|
|
Network name
|
|
VSwitch names (if any)
|
|
Operating system
|
|
MAC address
|
|
Root parition device address
|
|
Path to network configuration file
|
|
Path to hardware configuration file (SUSE only)
|
|
Returns : Nothing
|
|
Example : clone($callback, $_, $args, \@srcDisks, \%srcLinkAddr, \%srcDiskSize,
|
|
$srcNicAddr, $hcpNetName, \@srcVswitch, $srcOs, $srcMac, $netEntries,
|
|
$sourceIp, $srcNetwork, $srcMask);
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
sub clone {
|
|
|
|
# Get inputs
|
|
my (
|
|
$callback, $tgtNode, $args, $srcDisksRef, $srcLinkAddrRef, $srcDiskSizeRef, $srcDiskTypeRef,
|
|
$srcNicAddr, $hcpNetName, $srcVswitchRef, $srcOs, $srcMac, $netEntries, $sourceIp, $srcNetwork, $srcMask
|
|
)
|
|
= @_;
|
|
|
|
# Get source node properties from 'zvm' table
|
|
my $sourceNode = $args->[0];
|
|
my @propNames = ( 'hcp', 'userid' );
|
|
my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $sourceNode, @propNames );
|
|
|
|
# Get zHCP
|
|
my $srcHcp = $propVals->{'hcp'};
|
|
|
|
# Get node user ID
|
|
my $sourceId = $propVals->{'userid'};
|
|
# Capitalize user ID
|
|
$sourceId =~ tr/a-z/A-Z/;
|
|
|
|
# Get source disks
|
|
my @srcDisks = @$srcDisksRef;
|
|
my %srcLinkAddr = %$srcLinkAddrRef;
|
|
my %srcDiskSize = %$srcDiskSizeRef;
|
|
my %srcDiskType = %$srcDiskTypeRef;
|
|
my @srcVswitch = @$srcVswitchRef;
|
|
|
|
# Return code for each command
|
|
my $rc;
|
|
|
|
# Get node properties from 'zvm' table
|
|
@propNames = ( 'hcp', 'userid' );
|
|
$propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $tgtNode, @propNames );
|
|
|
|
# Get zHCP
|
|
my $hcp = $propVals->{'hcp'};
|
|
if ( !$hcp ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: (Error) Missing node HCP" );
|
|
return;
|
|
}
|
|
|
|
# Get node user ID
|
|
my $tgtUserId = $propVals->{'userid'};
|
|
if ( !$tgtUserId ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: (Error) Missing user ID" );
|
|
return;
|
|
}
|
|
# Capitalize user ID
|
|
$tgtUserId =~ tr/a-z/A-Z/;
|
|
|
|
# Exit if source node HCP is not the same as target node HCP
|
|
if ( !( $srcHcp eq $hcp ) ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: (Error) Source node HCP ($srcHcp) is not the same as target node HCP ($hcp)" );
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: (Solution) Set the source and target HCP appropriately in the zvm table" );
|
|
return;
|
|
}
|
|
|
|
# Get target IP from /etc/hosts
|
|
`makehosts`;
|
|
sleep(5);
|
|
my $targetIp = xCAT::zvmUtils->getIp($tgtNode);
|
|
if ( !$targetIp ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: (Error) Missing IP for $tgtNode in /etc/hosts" );
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: (Solution) Verify that the node's IP address is specified in the hosts table and then run makehosts" );
|
|
return;
|
|
}
|
|
xCAT::zvmUtils->printSyslog("hcp:$hcp tgtUserId:$tgtUserId targetIp:$targetIp");
|
|
|
|
my $out;
|
|
my @lines;
|
|
my @words;
|
|
|
|
# Get disk pool and multi password
|
|
my $i;
|
|
my %inputs;
|
|
foreach $i ( 1 .. 2 ) {
|
|
if ( $args->[$i] ) {
|
|
|
|
# Split parameters by '='
|
|
@words = split( "=", $args->[$i] );
|
|
|
|
# Create hash array
|
|
$inputs{ $words[0] } = $words[1];
|
|
}
|
|
}
|
|
|
|
# Get disk pool
|
|
my $pool = $inputs{"pool"};
|
|
if ( !$pool ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: (Error) Missing disk pool. Please specify one." );
|
|
return;
|
|
}
|
|
xCAT::zvmUtils->printSyslog("pool:$pool");
|
|
|
|
# Get multi password
|
|
# It is Ok not have a password
|
|
my $tgtPw = "''";
|
|
if ($inputs{"pw"}) {
|
|
$tgtPw = $inputs{"pw"};
|
|
}
|
|
|
|
# Save user directory entry as /tmp/hostname.txt, e.g. /tmp/gpok3.txt
|
|
# The source user entry is retrieved in cloneVM()
|
|
my $userEntry = "/tmp/$tgtNode.txt";
|
|
my $srcUserEntry = "/tmp/$sourceNode.txt";
|
|
|
|
# Remove existing user entry if any
|
|
$out = `rm $userEntry`;
|
|
$out = `ssh -o ConnectTimeout=5 $::SUDOER\@$hcp "$::SUDO rm $userEntry"`;
|
|
|
|
# Copy user entry of source node
|
|
$out = `cp $srcUserEntry $userEntry`;
|
|
|
|
# Replace source userID with target userID
|
|
$out = `sed -i -e "s,$sourceId,$tgtUserId,i" $userEntry`;
|
|
|
|
# Get target MAC address in 'mac' table
|
|
my $targetMac;
|
|
my $macId;
|
|
my $generateNew = 0; # Flag to generate new MACID
|
|
@propNames = ('mac');
|
|
$propVals = xCAT::zvmUtils->getNodeProps( 'mac', $tgtNode, @propNames );
|
|
if ($propVals) {
|
|
|
|
# Get MACID
|
|
$targetMac = $propVals->{'mac'};
|
|
$macId = $propVals->{'mac'};
|
|
$macId = xCAT::zvmUtils->replaceStr( $macId, ":", "" );
|
|
$macId = substr( $macId, 6 );
|
|
} else {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: (Error) Missing target MAC address" );
|
|
return;
|
|
}
|
|
|
|
# If the user entry contains a NICDEF statement
|
|
$out = `cat $userEntry | egrep -i "NICDEF"`;
|
|
if ($out) {
|
|
|
|
# Get the networks used by the zHCP
|
|
my @hcpNets = xCAT::zvmCPUtils->getNetworkNamesArray($::SUDOER, $hcp);
|
|
|
|
# Search user entry for network name
|
|
my $hcpNetName = '';
|
|
foreach (@hcpNets) {
|
|
if ( $out =~ m/ $_/i ) {
|
|
$hcpNetName = $_;
|
|
last;
|
|
}
|
|
}
|
|
|
|
# If the user entry contains a MACID
|
|
$out = `cat $userEntry | egrep -i "MACID"`;
|
|
if ($out) {
|
|
my $pos = rindex( $out, "MACID" );
|
|
my $oldMacId = substr( $out, $pos + 6, 12 );
|
|
$oldMacId = xCAT::zvmUtils->trimStr($oldMacId);
|
|
|
|
# Replace old MACID
|
|
$out = `sed -i -e "s,$oldMacId,$macId,i" $userEntry`;
|
|
} else {
|
|
|
|
# Find NICDEF statement
|
|
my $oldNicDef = `cat $userEntry | egrep -i "NICDEF" | egrep -i "$hcpNetName"`;
|
|
$oldNicDef = xCAT::zvmUtils->trimStr($oldNicDef);
|
|
my $nicDef = xCAT::zvmUtils->replaceStr( $oldNicDef, $hcpNetName, "$hcpNetName MACID $macId" );
|
|
|
|
# Append MACID at the end
|
|
$out = `sed -i -e "s,$oldNicDef,$nicDef,i" $userEntry`;
|
|
}
|
|
}
|
|
|
|
# SCP user entry file over to HCP
|
|
xCAT::zvmUtils->sendFile( $::SUDOER, $hcp, $userEntry, $userEntry );
|
|
|
|
#*** Create new virtual server ***
|
|
my $try = 5;
|
|
while ( $try > 0 ) {
|
|
if ( $try > 4 ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Creating user directory entry" );
|
|
} else {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Trying again ($try) to create user directory entry" );
|
|
}
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Create_DM -T $tgtUserId -f $userEntry"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Create_DM -T $tgtUserId -f $userEntry");
|
|
xCAT::zvmUtils->printSyslog("$out");
|
|
|
|
# Check if user entry is created
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Query_DM -T $tgtUserId" | sed '\$d'`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Query_DM -T $tgtUserId | sed '\$d'");
|
|
xCAT::zvmUtils->printSyslog("$out");
|
|
$rc = xCAT::zvmUtils->checkOutput( $callback, $out );
|
|
|
|
if ( $rc == -1 ) {
|
|
|
|
# Wait before trying again
|
|
sleep(5);
|
|
|
|
$try = $try - 1;
|
|
} else {
|
|
last;
|
|
}
|
|
}
|
|
|
|
# Remove user entry
|
|
$out = `rm $userEntry`;
|
|
$out = `ssh -o ConnectTimeout=5 $::SUDOER\@$hcp "$::SUDO rm $userEntry"`;
|
|
|
|
# Exit on bad output
|
|
if ( $rc == -1 ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: (Error) Could not create user entry" );
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: (Solution) Verify that the node's zHCP and its zVM's SMAPI are both online" );
|
|
return;
|
|
}
|
|
|
|
# Load VMCP module on HCP and source node
|
|
$out = `ssh -o ConnectTimeout=5 $::SUDOER\@$hcp "/sbin/modprobe vmcp"`;
|
|
|
|
# Grant access to VSwitch for Linux user
|
|
# GuestLan do not need permissions
|
|
foreach (@srcVswitch) {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Granting VSwitch ($_) access for $tgtUserId" );
|
|
$out = xCAT::zvmCPUtils->grantVSwitch( $callback, $::SUDOER, $hcp, $tgtUserId, $_ );
|
|
|
|
# Check for errors
|
|
$rc = xCAT::zvmUtils->checkOutput( $callback, $out );
|
|
if ( $rc == -1 ) {
|
|
|
|
# Exit on bad output
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: $out" );
|
|
return;
|
|
}
|
|
} # End of foreach (@vswitchId)
|
|
|
|
#*** Add MDisk to target user entry ***
|
|
my $addr;
|
|
my @tgtDisks;
|
|
my $type;
|
|
my $mode;
|
|
my $cyl;
|
|
foreach (@srcDisks) {
|
|
|
|
# Get disk address
|
|
@words = split( ' ', $_ );
|
|
$addr = $words[1];
|
|
push( @tgtDisks, $addr );
|
|
$type = $words[2];
|
|
$mode = $words[6];
|
|
if (!$mode) {
|
|
$mode = "MR";
|
|
}
|
|
|
|
# Add 0 in front if address length is less than 4
|
|
while (length($addr) < 4) {
|
|
$addr = '0' . $addr;
|
|
}
|
|
|
|
# Add ECKD disk
|
|
if ( $type eq '3390' ) {
|
|
|
|
# Get disk size (cylinders)
|
|
$cyl = $srcDiskSize{$addr};
|
|
|
|
$try = 5;
|
|
while ( $try > 0 ) {
|
|
|
|
# Add ECKD disk
|
|
if ( $try > 4 ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Adding minidisk ($addr)" );
|
|
} else {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Trying again ($try) to add minidisk ($addr)" );
|
|
}
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Disk_Create_DM -T $tgtUserId -v $addr -t 3390 -a AUTOG -r $pool -u 1 -z $cyl -m $mode -f 1 -R $tgtPw -W $tgtPw -M $tgtPw"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Disk_Create_DM -T $tgtUserId -v $addr -t 3390 -a AUTOG -r $pool -u 1 -z $cyl -m $mode -f 1 -R $tgtPw -W $tgtPw -M $tgtPw");
|
|
xCAT::zvmUtils->printSyslog("$out");
|
|
|
|
# Check output
|
|
$rc = xCAT::zvmUtils->checkOutput( $callback, $out );
|
|
if ( $rc == -1 ) {
|
|
|
|
# Wait before trying again
|
|
sleep(5);
|
|
|
|
# One less try
|
|
$try = $try - 1;
|
|
} else {
|
|
|
|
# If output is good, exit loop
|
|
last;
|
|
}
|
|
} # End of while ( $try > 0 )
|
|
|
|
# Exit on bad output
|
|
if ( $rc == -1 ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: (Error) Could not add minidisk ($addr)" );
|
|
return;
|
|
}
|
|
} # End of if ( $type eq '3390' )
|
|
|
|
# Add FBA disk
|
|
elsif ( $type eq '9336' ) {
|
|
|
|
# Get disk size (blocks)
|
|
my $blkSize = '512';
|
|
my $blks = $srcDiskSize{$addr};
|
|
|
|
$try = 10;
|
|
while ( $try > 0 ) {
|
|
|
|
# Add FBA disk
|
|
if ( $try > 9 ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Adding minidisk ($addr)" );
|
|
} else {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Trying again ($try) to add minidisk ($addr)" );
|
|
}
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Disk_Create_DM -T $tgtUserId -v $addr -t 9336 -a AUTOG -r $pool -u 1 -z $blks -m $mode -f 1 -R $tgtPw -W $tgtPw -M $tgtPw"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Disk_Create_DM -T $tgtUserId -v $addr -t 9336 -a AUTOG -r $pool -u 1 -z $blks -m $mode -f 1 -R $tgtPw -W $tgtPw -M $tgtPw");
|
|
xCAT::zvmUtils->printSyslog("$out");
|
|
|
|
# Check output
|
|
$rc = xCAT::zvmUtils->checkOutput( $callback, $out );
|
|
if ( $rc == -1 ) {
|
|
|
|
# Wait before trying again
|
|
sleep(5);
|
|
|
|
# One less try
|
|
$try = $try - 1;
|
|
} else {
|
|
|
|
# If output is good, exit loop
|
|
last;
|
|
}
|
|
} # End of while ( $try > 0 )
|
|
|
|
# Exit on bad output
|
|
if ( $rc == -1 ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: (Error) Could not add minidisk ($addr)" );
|
|
return;
|
|
}
|
|
} # End of elsif ( $type eq '9336' )
|
|
}
|
|
|
|
# Check if the number of disks in target user entry
|
|
# is equal to the number of disks added
|
|
my @disks;
|
|
$try = 10;
|
|
while ( $try > 0 ) {
|
|
|
|
# Get disks within user entry
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Query_DM -T $tgtUserId" | sed '\$d' | grep "MDISK"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Query_DM -T $tgtUserId | grep MDISK");
|
|
xCAT::zvmUtils->printSyslog("$out");
|
|
@disks = split( '\n', $out );
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Disks added (" . @tgtDisks . "). Disks in user entry (" . @disks . ")" );
|
|
|
|
if ( @disks != @tgtDisks ) {
|
|
$try = $try - 1;
|
|
|
|
# Wait before trying again
|
|
sleep(5);
|
|
} else {
|
|
last;
|
|
}
|
|
}
|
|
|
|
# Exit if all disks are not present
|
|
if ( @disks != @tgtDisks ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: (Error) Disks not present in user entry" );
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: (Solution) Verify disk pool($pool) has free disks" );
|
|
return;
|
|
}
|
|
|
|
#*** Link, format, and copy source disks ***
|
|
my $srcAddr;
|
|
my $tgtAddr;
|
|
my $srcDevNode;
|
|
my $tgtDevNode;
|
|
my $tgtDiskType;
|
|
foreach (@tgtDisks) {
|
|
|
|
#*** Link target disk ***
|
|
$try = 10;
|
|
while ( $try > 0 ) {
|
|
|
|
# Add 0 in front if address length is less than 4
|
|
while (length($_) < 4) {
|
|
$_ = '0' . $_;
|
|
}
|
|
|
|
# New disk address
|
|
$srcAddr = $srcLinkAddr{$_};
|
|
$tgtAddr = $_ + 2000;
|
|
|
|
# Check if new disk address is used (target)
|
|
$rc = xCAT::zvmUtils->isAddressUsed( $::SUDOER, $hcp, $tgtAddr );
|
|
|
|
# If disk address is used (target)
|
|
while ( $rc == 0 ) {
|
|
|
|
# Generate a new disk address
|
|
# Sleep 5 seconds to let existing disk appear
|
|
sleep(5);
|
|
$tgtAddr = $tgtAddr + 1;
|
|
$rc = xCAT::zvmUtils->isAddressUsed( $::SUDOER, $hcp, $tgtAddr );
|
|
}
|
|
|
|
# Link target disk
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Linking target disk ($_) as ($tgtAddr)" );
|
|
$out = `ssh -o ConnectTimeout=5 $::SUDOER\@$hcp "$::SUDO /sbin/vmcp link $tgtUserId $_ $tgtAddr MR $tgtPw"`;
|
|
|
|
# If link fails
|
|
if ( $out =~ m/not linked/i || $out =~ m/not write-enabled/i ) {
|
|
|
|
# Wait before trying again
|
|
sleep(5);
|
|
|
|
$try = $try - 1;
|
|
} else {
|
|
last;
|
|
}
|
|
} # End of while ( $try > 0 )
|
|
|
|
# If target disk is not linked
|
|
if ( $out =~ m/not linked/i ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: (Error) Failed to link target disk ($_)" );
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Failed" );
|
|
|
|
# Exit
|
|
return;
|
|
}
|
|
|
|
# Get disk type (3390 or 9336)
|
|
$tgtDiskType = $srcDiskType{$_};
|
|
|
|
#*** Use flashcopy ***
|
|
# Flashcopy only supports ECKD volumes
|
|
# Assume flashcopy is supported and use Linux DD on failure
|
|
my $ddCopy = 0;
|
|
my $cpFlashcopy = 1;
|
|
if ($tgtDiskType eq '3390') {
|
|
|
|
# Use SMAPI FLASHCOPY
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Copying source disk ($srcAddr) to target disk ($srcAddr) using FLASHCOPY" );
|
|
if (xCAT::zvmUtils->smapi4xcat($::SUDOER, $hcp)) {
|
|
$out = xCAT::zvmCPUtils->smapiFlashCopy($::SUDOER, $hcp, $sourceId, $srcAddr, $tgtUserId, $srcAddr);
|
|
xCAT::zvmUtils->printSyslog("smapiFlashCopy: $out");
|
|
|
|
# Exit if flashcopy completed successfully
|
|
# Otherwsie, try CP FLASHCOPY
|
|
if ( $out =~ m/Done/i ) {
|
|
$cpFlashcopy = 0;
|
|
}
|
|
}
|
|
|
|
# Use CP FLASHCOPY
|
|
if ($cpFlashcopy) {
|
|
# Check for CP flashcopy lock
|
|
my $wait = 0;
|
|
while ( `ssh $::SUDOER\@$hcp "$::SUDO ls /tmp/.flashcopy_lock"` && $wait < 90 ) {
|
|
|
|
# Wait until the lock dissappears
|
|
# 90 seconds wait limit
|
|
sleep(2);
|
|
$wait = $wait + 2;
|
|
}
|
|
|
|
# If flashcopy locks still exists
|
|
if (`ssh $::SUDOER\@$hcp "$::SUDO ls /tmp/.flashcopy_lock"`) {
|
|
|
|
# Detatch disks from HCP
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/vmcp det $tgtAddr"`;
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: (Error) Flashcopy lock is enabled" );
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: (Solution) Remove lock by deleting /tmp/.flashcopy_lock on the zHCP. Use caution!" );
|
|
return;
|
|
} else {
|
|
|
|
# Enable lock
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO touch /tmp/.flashcopy_lock"`;
|
|
|
|
# Flashcopy source disk
|
|
$out = xCAT::zvmCPUtils->flashCopy( $::SUDOER, $hcp, $srcAddr, $tgtAddr );
|
|
xCAT::zvmUtils->printSyslog("flashCopy: $out");
|
|
$rc = xCAT::zvmUtils->checkOutput( $callback, $out );
|
|
if ( $rc == -1 ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: $out" );
|
|
|
|
# Try Linux dd
|
|
$ddCopy = 1;
|
|
}
|
|
|
|
# Wait a while for flashcopy to completely finish
|
|
sleep(10);
|
|
|
|
# Remove lock
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO rm -f /tmp/.flashcopy_lock"`;
|
|
}
|
|
}
|
|
} else {
|
|
$ddCopy = 1;
|
|
}
|
|
|
|
# Flashcopy not supported, use Linux dd
|
|
if ($ddCopy) {
|
|
|
|
#*** Use Linux dd to copy ***
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: FLASHCOPY not working. Using Linux DD" );
|
|
|
|
# Enable target disk
|
|
$out = xCAT::zvmUtils->disableEnableDisk( $::SUDOER, $hcp, "-e", $tgtAddr );
|
|
|
|
# Determine source device node
|
|
$srcDevNode = xCAT::zvmUtils->getDeviceNode($::SUDOER, $hcp, $srcAddr);
|
|
|
|
# Determine target device node
|
|
$tgtDevNode = xCAT::zvmUtils->getDeviceNode($::SUDOER, $hcp, $tgtAddr);
|
|
|
|
# Format target disk
|
|
# Only ECKD disks need to be formated
|
|
if ($tgtDiskType eq '3390') {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Formating target disk ($tgtAddr)" );
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/dasdfmt -b 4096 -y -f /dev/$tgtDevNode"`;
|
|
xCAT::zvmUtils->printSyslog("dasdfmt -b 4096 -y -f /dev/$tgtDevNode");
|
|
|
|
# Check for errors
|
|
$rc = xCAT::zvmUtils->checkOutput( $callback, $out );
|
|
if ( $rc == -1 ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: $out" );
|
|
|
|
# Detatch disks from HCP
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/vmcp det $tgtAddr"`;
|
|
|
|
return;
|
|
}
|
|
|
|
# Sleep 2 seconds to let the system settle
|
|
sleep(2);
|
|
|
|
# Copy source disk to target disk
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Copying source disk ($srcAddr) to target disk ($tgtAddr)" );
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /bin/dd if=/dev/$srcDevNode of=/dev/$tgtDevNode bs=4096 oflag=sync && $::SUDO echo $?"`;
|
|
$out = xCAT::zvmUtils->trimStr($out);
|
|
if (int($out) != 0) {
|
|
# If $? is not 0 then there was an error during Linux dd
|
|
$out = "(Error) Failed to copy /dev/$srcDevNode";
|
|
}
|
|
|
|
xCAT::zvmUtils->printSyslog("dd if=/dev/$srcDevNode of=/dev/$tgtDevNode bs=4096 oflag=sync");
|
|
xCAT::zvmUtils->printSyslog("$out");
|
|
} else {
|
|
# Copy source disk to target disk
|
|
# Block size = 512
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Copying source disk ($srcAddr) to target disk ($tgtAddr)" );
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /bin/dd if=/dev/$srcDevNode of=/dev/$tgtDevNode bs=512 oflag=sync && $::SUDO echo $?"`;
|
|
$out = xCAT::zvmUtils->trimStr($out);
|
|
if (int($out) != 0) {
|
|
# If $? is not 0 then there was an error during Linux dd
|
|
$out = "(Error) Failed to copy /dev/$srcDevNode";
|
|
}
|
|
|
|
xCAT::zvmUtils->printSyslog("dd if=/dev/$srcDevNode of=/dev/$tgtDevNode bs=512 oflag=sync");
|
|
xCAT::zvmUtils->printSyslog("$out");
|
|
|
|
# Force Linux to re-read partition table
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Forcing Linux to re-read partition table" );
|
|
$out =
|
|
`ssh $::SUDOER\@$hcp "$::SUDO cat<<EOM | fdisk /dev/$tgtDevNode
|
|
p
|
|
w
|
|
EOM"`;
|
|
}
|
|
|
|
# Check for error
|
|
$rc = xCAT::zvmUtils->checkOutput( $callback, $out );
|
|
if ( $rc == -1 ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: $out" );
|
|
|
|
# Disable disks
|
|
$out = xCAT::zvmUtils->disableEnableDisk( $::SUDOER, $hcp, "-d", $tgtAddr );
|
|
|
|
# Detatch disks from zHCP
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/vmcp det $tgtAddr"`;
|
|
|
|
return;
|
|
}
|
|
|
|
# Sleep 2 seconds to let the system settle
|
|
sleep(2);
|
|
}
|
|
|
|
# Disable and enable target disk
|
|
$out = xCAT::zvmUtils->disableEnableDisk( $::SUDOER, $hcp, "-d", $tgtAddr );
|
|
$out = xCAT::zvmUtils->disableEnableDisk( $::SUDOER, $hcp, "-e", $tgtAddr );
|
|
|
|
# Determine target device node (it might have changed)
|
|
$tgtDevNode = xCAT::zvmUtils->getDeviceNode($::SUDOER, $hcp, $tgtAddr);
|
|
|
|
# Mount device and check if it is the root partition
|
|
# If it is, then modify the network configuration
|
|
|
|
# Mount target disk
|
|
my $cloneMntPt = "/mnt/$tgtUserId/$tgtDevNode";
|
|
|
|
# Disk can contain more than 1 partition. Find the right one (not swap)
|
|
# Check if /usr/bin/file is available
|
|
if (`ssh $::SUDOER\@$hcp "$::SUDO test -f /usr/bin/file && echo Exists"`) {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /usr/bin/file -s /dev/$tgtDevNode*"`;
|
|
xCAT::zvmUtils->printSyslog("file -s /dev/$tgtDevNode*");
|
|
} else {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/fdisk -l /dev/$tgtDevNode*"`;
|
|
xCAT::zvmUtils->printSyslog("fdisk -l /dev/$tgtDevNode*");
|
|
}
|
|
xCAT::zvmUtils->printSyslog("$out");
|
|
|
|
$out = "";
|
|
$try = 5;
|
|
while (!$out && $try > 0) {
|
|
# Check if /usr/bin/file is available
|
|
if (`ssh $::SUDOER\@$hcp "$::SUDO test -f /usr/bin/file && echo Exists"`) {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /usr/bin/file -s /dev/$tgtDevNode*" | grep -v swap | grep -o "$tgtDevNode\[1-9\]"`;
|
|
} else {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/fdisk -l /dev/$tgtDevNode* | grep -v swap | grep -o $tgtDevNode\[1-9\]"`;
|
|
}
|
|
$out = xCAT::zvmUtils->trimStr($out);
|
|
xCAT::zvmUtils->printSyslog("fdisk -l /dev/$tgtDevNode* | grep -v swap | grep -o $tgtDevNode\[1-9\]");
|
|
xCAT::zvmUtils->printSyslog("$out");
|
|
|
|
# Wait before trying again
|
|
sleep(5);
|
|
$try = $try - 1;
|
|
}
|
|
|
|
my @tgtDevNodes = split( "\n", $out );
|
|
my $iTgtDevNode = 0;
|
|
$tgtDevNode = xCAT::zvmUtils->trimStr($tgtDevNodes[$iTgtDevNode]);
|
|
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Mounting /dev/$tgtDevNode to $cloneMntPt" );
|
|
|
|
# Check the disk is mounted
|
|
$try = 5;
|
|
while ( !(`ssh $::SUDOER\@$hcp "$::SUDO ls $cloneMntPt"`) && $try > 0 ) {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO mkdir -p $cloneMntPt"`;
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO mount /dev/$tgtDevNode $cloneMntPt"`;
|
|
xCAT::zvmUtils->printSyslog("mount /dev/$tgtDevNode $cloneMntPt");
|
|
|
|
# If more than 1 partition, try other partitions
|
|
if (@tgtDevNodes > 1 && $iTgtDevNode < @tgtDevNodes) {
|
|
$iTgtDevNode++;
|
|
$tgtDevNode = xCAT::zvmUtils->trimStr($tgtDevNodes[$iTgtDevNode]);
|
|
}
|
|
|
|
# Wait before trying again
|
|
sleep(10);
|
|
$try = $try - 1;
|
|
}
|
|
|
|
if (!(`ssh $::SUDOER\@$hcp "$::SUDO ls $cloneMntPt"`)) {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Failed to mount /dev/$tgtDevNode. Skipping device." );
|
|
}
|
|
|
|
# Is this the partition containing /etc?
|
|
if (`ssh $::SUDOER\@$hcp "$::SUDO test -d $cloneMntPt/etc && echo Exists"`) {
|
|
#*** Set network configuration ***
|
|
# Set hostname
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Setting network configuration" );
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO sed -i -e \"s/$sourceNode/$tgtNode/i\" $cloneMntPt/etc/HOSTNAME"`;
|
|
xCAT::zvmUtils->printSyslog("sed -i -e s/$sourceNode/$tgtNode/i $cloneMntPt/etc/HOSTNAME");
|
|
|
|
# If Red Hat - Set hostname in /etc/sysconfig/network
|
|
if ( $srcOs =~ m/rhel/i ) {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO sed -i -e \"s/$sourceNode/$tgtNode/i\" $cloneMntPt/etc/sysconfig/network"`;
|
|
xCAT::zvmUtils->printSyslog("sed -i -e s/$sourceNode/$tgtNode/i $cloneMntPt/etc/sysconfig/network");
|
|
}
|
|
|
|
# Get network layer
|
|
my $layer = xCAT::zvmCPUtils->getNetworkLayer( $::SUDOER, $hcp, $hcpNetName );
|
|
xCAT::zvmUtils->printSyslog("hcp:$hcp hcpNetName:$hcpNetName layer:$layer");
|
|
|
|
# Get network configuration file
|
|
# Location of this file depends on the OS
|
|
my $srcIfcfg = '';
|
|
|
|
# If it is Red Hat - ifcfg-qeth file is in /etc/sysconfig/network-scripts
|
|
my @files;
|
|
if ( $srcOs =~ m/rhel/i ) {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO grep -H -i -r $srcNicAddr $cloneMntPt/etc/sysconfig/network-scripts"`;
|
|
xCAT::zvmUtils->printSyslog("grep -H -i -r $srcNicAddr $cloneMntPt/etc/sysconfig/network-scripts");
|
|
xCAT::zvmUtils->printSyslog("$out");
|
|
@files = split('\n', $out);
|
|
@words = split( ':', $files[0] );
|
|
$srcIfcfg = $words[0];
|
|
}
|
|
|
|
# If it is SLES 10 - ifcfg-qeth file is in /etc/sysconfig/network
|
|
elsif ( $srcOs =~ m/sles10/i ) {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO grep -H -i -r $srcNicAddr $cloneMntPt/etc/sysconfig/network/ifcfg-qeth*"`;
|
|
xCAT::zvmUtils->printSyslog("grep -H -i -r $srcNicAddr $cloneMntPt/etc/sysconfig/network/ifcfg-qeth*");
|
|
xCAT::zvmUtils->printSyslog("$out");
|
|
@files = split('\n', $out);
|
|
@words = split( ':', $files[0] );
|
|
$srcIfcfg = $words[0];
|
|
}
|
|
|
|
# If it is SLES 11 - ifcfg-qeth file is in /etc/sysconfig/network
|
|
elsif ( $srcOs =~ m/sles/i ) {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO grep -H -i -r $srcNicAddr $cloneMntPt/etc/sysconfig/network/ifcfg-eth*"`;
|
|
xCAT::zvmUtils->printSyslog("grep -H -i -r $srcNicAddr $cloneMntPt/etc/sysconfig/network/ifcfg-eth*");
|
|
xCAT::zvmUtils->printSyslog("$out");
|
|
@files = split('\n', $out);
|
|
@words = split( ':', $files[0] );
|
|
$srcIfcfg = $words[0];
|
|
}
|
|
|
|
my $ifcfgPath = $srcIfcfg;
|
|
|
|
# Change IP, network, and mask
|
|
# Go through each network
|
|
my $tgtNetwork = "";
|
|
my $tgtMask;
|
|
foreach (@$netEntries) {
|
|
|
|
# Get network and mask
|
|
$tgtNetwork = $_->{'net'};
|
|
$tgtMask = $_->{'mask'};
|
|
|
|
# If the host IP address is in this subnet, return
|
|
if (xCAT::NetworkUtils->ishostinsubnet($targetIp, $tgtMask, $tgtNetwork)) {
|
|
|
|
# Exit loop
|
|
last;
|
|
} else {
|
|
$tgtNetwork = "";
|
|
}
|
|
}
|
|
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO sed -i -e \"s/$sourceNode/$tgtNode/i\" \ -e \"s/$sourceIp/$targetIp/i\" $cloneMntPt/etc/hosts"`;
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO sed -i -e \"s/$sourceIp/$targetIp/i\" \ -e \"s/$sourceNode/$tgtNode/i\" $ifcfgPath"`;
|
|
xCAT::zvmUtils->printSyslog("sed -i -e s/$sourceNode/$tgtNode/i \ -e s/$sourceIp/$targetIp/i $cloneMntPt/etc/hosts");
|
|
xCAT::zvmUtils->printSyslog("sed -i -e s/$sourceIp/$targetIp/i \ -e s/$sourceNode/$tgtNode/i $ifcfgPath");
|
|
|
|
if ($tgtNetwork && $tgtMask) {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO sed -i -e \"s/$srcNetwork/$tgtNetwork/i\" \ -e \"s/$srcMask/$tgtMask/i\" $ifcfgPath"`;
|
|
xCAT::zvmUtils->printSyslog("sed -i -e s/$srcNetwork/$tgtNetwork/i \ -e s/$srcMask/$tgtMask/i $ifcfgPath");
|
|
}
|
|
|
|
# Set MAC address
|
|
my $networkFile = $tgtNode . "NetworkConfig";
|
|
my $config;
|
|
if ( $srcOs =~ m/rhel/i ) {
|
|
|
|
# Red Hat only
|
|
$config = `ssh $::SUDOER\@$hcp "$::SUDO cat $ifcfgPath" | grep -v "MACADDR"`;
|
|
$config .= "MACADDR='" . $targetMac . "'\n";
|
|
} else {
|
|
|
|
# SUSE only
|
|
$config = `ssh $::SUDOER\@$hcp "$::SUDO cat $ifcfgPath" | grep -v "LLADDR" | grep -v "UNIQUE"`;
|
|
|
|
# Set to MAC address (only for layer 2)
|
|
if ( $layer == 2 ) {
|
|
$config .= "LLADDR='" . $targetMac . "'\n";
|
|
$config .= "UNIQUE=''\n";
|
|
}
|
|
}
|
|
xCAT::zvmUtils->printSyslog("$config");
|
|
|
|
# Write network configuration
|
|
# You cannot SCP file over to mount point as sudo, so you have to copy file to zHCP
|
|
# and move it to mount point
|
|
$out = `echo -e "$config" > /tmp/$networkFile`;
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO rm -rf $ifcfgPath"`;
|
|
$out = `cat /tmp/$networkFile | ssh $::SUDOER\@$hcp "$::SUDO cat > /tmp/$networkFile"`;
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO mv /tmp/$networkFile $ifcfgPath"`;
|
|
$out = `rm -rf /tmp/$networkFile`;
|
|
|
|
# Set to hardware configuration (only for layer 2)
|
|
if ( $layer == 2 ) {
|
|
if ( $srcOs =~ m/rhel/i && $srcMac ) {
|
|
#*** Red Hat Linux ***
|
|
|
|
# Set MAC address
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO sed -i -e \"s/$srcMac/$targetMac/i\" $ifcfgPath"`;
|
|
xCAT::zvmUtils->printSyslog("sed -i -e s/$srcMac/$targetMac/i $ifcfgPath");
|
|
} else {
|
|
#*** SuSE Linux ***
|
|
|
|
# Get hardware configuration
|
|
# hwcfg-qeth file is in /etc/sysconfig/hardware
|
|
my $hwcfgPath = $cloneMntPt . "/etc/sysconfig/hardware/hwcfg-qeth-bus-ccw-0.0.$srcNicAddr";
|
|
xCAT::zvmUtils->printSyslog("hwcfgPath=$hwcfgPath");
|
|
my $hardwareFile = $tgtNode . "HardwareConfig";
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO cat $hwcfgPath" | grep -v "QETH_LAYER2_SUPPORT" > /tmp/$hardwareFile`;
|
|
$out = `echo "QETH_LAYER2_SUPPORT='1'" >> /tmp/$hardwareFile`;
|
|
xCAT::zvmUtils->sendFile( $::SUDOER, $hcp, "/tmp/$hardwareFile", $hwcfgPath );
|
|
|
|
# Remove hardware file from /tmp
|
|
$out = `rm /tmp/$hardwareFile`;
|
|
}
|
|
} # End of if ( $layer == 2 )
|
|
|
|
# Remove old SSH keys
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO rm -f $cloneMntPt/etc/ssh/ssh_host_*"`;
|
|
}
|
|
|
|
# Flush disk
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /bin/sync"`;
|
|
|
|
# Unmount disk
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /bin/umount $cloneMntPt"`;
|
|
|
|
# Remove mount point
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO rm -rf $cloneMntPt"`;
|
|
|
|
# Disable disks
|
|
$out = xCAT::zvmUtils->disableEnableDisk( $::SUDOER, $hcp, "-d", $tgtAddr );
|
|
|
|
# Detatch disks from HCP
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/vmcp det $tgtAddr"`;
|
|
|
|
sleep(5);
|
|
} # End of foreach (@tgtDisks)
|
|
|
|
# Update DHCP (only if it is running)
|
|
$out = `service dhcpd status`;
|
|
if (!($out =~ m/unused/i || $out =~ m/stopped/i)) {
|
|
$out = `/opt/xcat/bin/makedhcp -a`;
|
|
}
|
|
|
|
# Power on target virtual server
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: Powering on" );
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Activate -T $tgtUserId"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Activate -T $tgtUserId");
|
|
|
|
# Check for error
|
|
$rc = xCAT::zvmUtils->checkOutput( $callback, $out );
|
|
if ( $rc == -1 ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$tgtNode: $out" );
|
|
return;
|
|
}
|
|
}
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 nodeSet
|
|
|
|
Description : Set the boot state for a node
|
|
* Punch initrd, kernel, and parmfile to node reader
|
|
* Layer 2 and 3 VSwitch/Lan supported
|
|
Arguments : Node
|
|
Returns : Nothing
|
|
Example : nodeSet($callback, $node, $args);
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
sub nodeSet {
|
|
|
|
# Get inputs
|
|
my ( $callback, $node, $args ) = @_;
|
|
|
|
# Get node properties from 'zvm' table
|
|
my @propNames = ( 'hcp', 'userid' );
|
|
my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
|
|
|
|
# Get zHCP
|
|
my $hcp = $propVals->{'hcp'};
|
|
if (!$hcp) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing node HCP" );
|
|
return;
|
|
}
|
|
|
|
# Get node user ID
|
|
my $userId = $propVals->{'userid'};
|
|
if (!$userId) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing user ID" );
|
|
return;
|
|
}
|
|
# Capitalize user ID
|
|
$userId =~ tr/a-z/A-Z/;
|
|
|
|
xCAT::zvmUtils->printSyslog("sudoer:$::SUDOER zHCP:$hcp sudo:$::SUDO");
|
|
|
|
# Parse the possible operands
|
|
my $osImg;
|
|
my $remoteHost;
|
|
my $transport;
|
|
my $device;
|
|
my $action;
|
|
|
|
foreach my $arg ( @$args ) {
|
|
if ($arg =~ m/^osimage=/i) {
|
|
$osImg = $arg;
|
|
$osImg =~ s/^osimage=//;
|
|
} elsif ($arg =~ m/^device=/i) {
|
|
$device = $arg;
|
|
$device =~ s/device=//;
|
|
} elsif ($arg =~ m/^remotehost=/i) {
|
|
$remoteHost = $arg;
|
|
$remoteHost =~ s/remotehost=//;
|
|
} elsif ($arg =~ m/^transport=/i) {
|
|
$transport = $arg;
|
|
$transport =~ s/transport=//;
|
|
} else {
|
|
# If not a recognized operand with a value then it must be an action
|
|
$action = $arg;
|
|
}
|
|
}
|
|
|
|
# Handle case where osimage is specified
|
|
my $os;
|
|
my $arch;
|
|
my $profile;
|
|
my $provMethod;
|
|
if (defined $osImg) {
|
|
$osImg =~ s/osimage=//;
|
|
$osImg =~ s/^\s+//;
|
|
$osImg =~ s/\s+$//;
|
|
|
|
@propNames = ('profile', 'provmethod', 'osvers', 'osarch');
|
|
$propVals = xCAT::zvmUtils->getTabPropsByKey( 'osimage', 'imagename', $osImg, @propNames );
|
|
|
|
# Update nodetype table with os, arch, and profile based on osimage
|
|
if ( !$propVals->{'profile'} || !$propVals->{'provmethod'} || !$propVals->{'osvers'} || !$propVals->{'osarch'} ) {
|
|
# Exit
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing profile, provmethod, osvers, or osarch for osimage" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Solution) Provide profile, provmethod, osvers, and osarch in the osimage definition" );
|
|
return;
|
|
}
|
|
|
|
# Update nodetype table with osimage attributes for node
|
|
my %propHash = (
|
|
'os' => $propVals->{'osvers'},
|
|
'arch' => $propVals->{'osarch'},
|
|
'profile' => $propVals->{'profile'},
|
|
'provmethod' => $propVals->{'provmethod'}
|
|
);
|
|
xCAT::zvmUtils->setNodeProps( 'nodetype', $node, \%propHash );
|
|
$action = $propVals->{'provmethod'};
|
|
}
|
|
|
|
# Get install directory and domain from site table
|
|
my @entries = xCAT::TableUtils->get_site_attribute("installdir");
|
|
my $installDir = $entries[0];
|
|
@entries = xCAT::TableUtils->get_site_attribute("domain");
|
|
my $domain = $entries[0];
|
|
@entries = xCAT::TableUtils->get_site_attribute("master");
|
|
my $master = $entries[0];
|
|
@entries = xCAT::TableUtils->get_site_attribute("xcatdport");
|
|
my $xcatdPort = $entries[0];
|
|
|
|
# Get node OS, arch, and profile from 'nodetype' table
|
|
@propNames = ( 'os', 'arch', 'profile' );
|
|
$propVals = xCAT::zvmUtils->getNodeProps( 'nodetype', $node, @propNames );
|
|
|
|
$os = $propVals->{'os'};
|
|
$arch = $propVals->{'arch'};
|
|
$profile = $propVals->{'profile'};
|
|
|
|
# If no OS, arch, or profile is found
|
|
if (!$os || !$arch || !$profile) {
|
|
|
|
# Exit
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing node OS, arch, and profile in nodetype table" );
|
|
return;
|
|
}
|
|
|
|
# Get action
|
|
my $out;
|
|
if ( $action eq "install" ) {
|
|
|
|
# Get node root password
|
|
@propNames = ('password');
|
|
$propVals = xCAT::zvmUtils->getTabPropsByKey( 'passwd', 'key', 'system', @propNames );
|
|
my $passwd = $propVals->{'password'};
|
|
if ( !$passwd ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing root password for this node" );
|
|
return;
|
|
}
|
|
|
|
# Get node OS base
|
|
my @tmp;
|
|
if ( $os =~ m/sp/i ) {
|
|
@tmp = split( /sp/, $os );
|
|
} else {
|
|
@tmp = split( /\./, $os );
|
|
}
|
|
my $osBase = $tmp[0];
|
|
|
|
# Get node distro
|
|
my $distro = "";
|
|
if ( $os =~ m/sles/i ) {
|
|
$distro = "sles";
|
|
} elsif ( $os =~ m/rhel/i ) {
|
|
$distro = "rh";
|
|
} else {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Unable to determine node Linux distribution" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Solution) Verify the node Linux distribution is either sles* or rh*" );
|
|
return;
|
|
}
|
|
|
|
# Get autoyast/kickstart template
|
|
my $tmpl;
|
|
|
|
# Check for $profile.$os.$arch.tmpl
|
|
if ( -e "$installDir/custom/install/$distro/$profile.$os.$arch.tmpl" ) {
|
|
$tmpl = "$profile.$os.$arch.tmpl";
|
|
}
|
|
# Check for $profile.$osBase.$arch.tmpl
|
|
elsif ( -e "$installDir/custom/install/$distro/$profile.$osBase.$arch.tmpl" ) {
|
|
$tmpl = "$profile.$osBase.$arch.tmpl";
|
|
}
|
|
# Check for $profile.$arch.tmpl
|
|
elsif ( -e "$installDir/custom/install/$distro/$profile.$arch.tmpl" ) {
|
|
$tmpl = "$profile.$arch.tmpl";
|
|
}
|
|
# Check for $profile.tmpl second
|
|
elsif ( -e "$installDir/custom/install/$distro/$profile.tmpl" ) {
|
|
$tmpl = "$profile.tmpl";
|
|
}
|
|
else {
|
|
# No template exists
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing autoyast/kickstart template" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Solution) Create a template under $installDir/custom/install/$distro/" );
|
|
return;
|
|
}
|
|
|
|
# Get host IP and hostname from /etc/hosts
|
|
$out = `cat /etc/hosts | egrep -i "$node |$node."`;
|
|
my @words = split( ' ', $out );
|
|
my $hostIP = $words[0];
|
|
my $hostname = $words[2];
|
|
if (!($hostname =~ m/./i)) {
|
|
$hostname = $words[1];
|
|
}
|
|
|
|
if ( !$hostIP || !$hostname ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing IP for $node in /etc/hosts" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Solution) Verify that the nodes IP address is specified in the hosts table and then run makehosts" );
|
|
return;
|
|
}
|
|
|
|
# Check template if DHCP is used
|
|
my $dhcp = 0;
|
|
if ($distro eq "sles") {
|
|
# Check autoyast template
|
|
if ( -e "$installDir/custom/install/sles/$tmpl" ) {
|
|
$out = `cat $installDir/custom/install/sles/$tmpl | egrep -i "<bootproto>"`;
|
|
if ($out =~ m/dhcp/i) {
|
|
$dhcp = 1;
|
|
}
|
|
}
|
|
} elsif ($distro eq "rh") {
|
|
# Check kickstart template
|
|
if ( -e "$installDir/custom/install/rh/$tmpl" ) {
|
|
$out = `cat $installDir/custom/install/rh/$tmpl | egrep -ie "--bootproto dhcp"`;
|
|
if ($out =~ m/dhcp/i) {
|
|
$dhcp = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
# Get the noderes.primarynic
|
|
my $channel = '';
|
|
my $layer;
|
|
my $i;
|
|
|
|
@propNames = ( 'primarynic', 'nfsserver', 'xcatmaster' );
|
|
$propVals = xCAT::zvmUtils->getNodeProps( 'noderes', $node, @propNames );
|
|
|
|
my $repo = $propVals->{'nfsserver'}; # Repository containing Linux ISO
|
|
my $xcatmaster = $propVals->{'xcatmaster'};
|
|
my $primaryNic = $propVals->{'primarynic'}; # NIC to use for OS installation
|
|
|
|
# If noderes.primarynic is not specified, find an acceptable NIC shared with the zHCP
|
|
if ($primaryNic) {
|
|
$layer = xCAT::zvmCPUtils->getNetworkLayer($::SUDOER, $hcp, $primaryNic);
|
|
|
|
# If DHCP is used and the NIC is not layer 2, then exit
|
|
if ($dhcp && $layer != 2) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) The template selected uses DHCP. A layer 2 VSWITCH or GLAN is required. None were found." );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Solution) Modify the template to use <bootproto>static</bootproto> or --bootproto=static, or change the network device attached to virtual machine" );
|
|
return;
|
|
}
|
|
|
|
# Find device channel of NIC
|
|
my $userEntry = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Query_DM -T $userId" | sed '\$d'`;
|
|
$out = `echo "$userEntry" | grep "NICDEF" | grep "$primaryNic"`;
|
|
|
|
# Check user profile for device channel
|
|
if (!$out) {
|
|
my $profileName = `echo "$userEntry" | grep "INCLUDE"`;
|
|
if ($profileName) {
|
|
@words = split(' ', xCAT::zvmUtils->trimStr($profileName));
|
|
|
|
# Get user profile
|
|
my $userProfile = xCAT::zvmUtils->getUserProfile($::SUDOER, $hcp, $words[1]);
|
|
|
|
# Get the NICDEF statement containing the HCP network
|
|
$out = `echo "$userProfile" | grep "NICDEF" | grep "$primaryNic"`;
|
|
}
|
|
}
|
|
|
|
# Grab the device channel from the NICDEF statement
|
|
my @lines = split('\n', $out);
|
|
@words = split(' ', $lines[0]);
|
|
$channel = sprintf('%d', hex($words[1]));
|
|
} else {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Searching for acceptable network device");
|
|
($primaryNic, $channel, $layer) = xCAT::zvmUtils->findUsablezHcpNetwork($::SUDOER, $hcp, $userId, $dhcp);
|
|
|
|
# If DHCP is used and not layer 2
|
|
if ($dhcp && $layer != 2) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) The template selected uses DHCP. A layer 2 VSWITCH or GLAN is required. None were found." );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Solution) Modify the template to use <bootproto>static</bootproto> or change the network device attached to virtual machine" );
|
|
return;
|
|
}
|
|
}
|
|
|
|
# Exit if no suitable network found
|
|
if (!$primaryNic || !$channel || !$layer) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) No suitable network device found in user directory entry" );
|
|
return;
|
|
}
|
|
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Setting up networking on $primaryNic (layer:$layer | DHCP:$dhcp)" );
|
|
|
|
# Generate read, write, and data channels
|
|
my $readChannel = "0.0." . (sprintf('%X', $channel + 0));
|
|
if (length($readChannel) < 8) {
|
|
# Prepend a zero
|
|
$readChannel = "0.0.0" . (sprintf('%X', $channel + 0));
|
|
}
|
|
|
|
my $writeChannel = "0.0." . (sprintf('%X', $channel + 1));
|
|
if (length($writeChannel) < 8) {
|
|
# Prepend a zero
|
|
$writeChannel = "0.0.0" . (sprintf('%X', $channel + 1));
|
|
}
|
|
|
|
my $dataChannel = "0.0." . (sprintf('%X', $channel + 2));
|
|
if (length($dataChannel) < 8) {
|
|
# Prepend a zero
|
|
$dataChannel = "0.0.0" . (sprintf('%X', $channel + 2));
|
|
}
|
|
|
|
# Get MAC address (Only for layer 2)
|
|
my $mac = "";
|
|
my @propNames;
|
|
my $propVals;
|
|
if ($layer == 2) {
|
|
|
|
# Search 'mac' table for node
|
|
@propNames = ('mac');
|
|
$propVals = xCAT::zvmUtils->getTabPropsByKey('mac', 'node', $node, @propNames);
|
|
$mac = $propVals->{'mac'};
|
|
|
|
# If no MAC address is found, exit
|
|
# MAC address should have been assigned to the node upon creation
|
|
if (!$mac) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Missing MAC address of node");
|
|
return;
|
|
}
|
|
}
|
|
|
|
# Get networks in 'networks' table
|
|
my $entries = xCAT::zvmUtils->getAllTabEntries('networks');
|
|
|
|
# Go through each network
|
|
my $network = "";
|
|
my $mask;
|
|
foreach (@$entries) {
|
|
|
|
# Get network and mask
|
|
$network = $_->{'net'};
|
|
$mask = $_->{'mask'};
|
|
|
|
# If the host IP address is in this subnet, return
|
|
if (xCAT::NetworkUtils->ishostinsubnet($hostIP, $mask, $network)) {
|
|
|
|
# Exit loop
|
|
last;
|
|
} else {
|
|
$network = "";
|
|
}
|
|
}
|
|
|
|
# If no network found
|
|
if ( !$network ) {
|
|
|
|
# Exit
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Node does not belong to any network in the networks table" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Solution) Specify the subnet in the networks table. The mask, gateway, tftpserver, and nameservers must be specified for the subnet." );
|
|
return;
|
|
}
|
|
|
|
@propNames = ( 'mask', 'gateway', 'tftpserver', 'nameservers' );
|
|
$propVals = xCAT::zvmUtils->getTabPropsByKey( 'networks', 'net', $network, @propNames );
|
|
my $mask = $propVals->{'mask'};
|
|
my $gateway = $propVals->{'gateway'};
|
|
|
|
# Convert <xcatmaster> to nameserver IP
|
|
my $nameserver;
|
|
if ($propVals->{'nameservers'} eq '<xcatmaster>') {
|
|
$nameserver = xCAT::InstUtils->convert_xcatmaster();
|
|
} else {
|
|
$nameserver = $propVals->{'nameservers'};
|
|
}
|
|
|
|
if ( !$network || !$mask || !$nameserver ) {
|
|
# It is acceptable to not have a gateway
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing network information" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Solution) Specify the mask, gateway, and nameservers for the subnet in the networks table" );
|
|
return;
|
|
}
|
|
|
|
@propNames = ( 'nfsserver', 'xcatmaster' );
|
|
$propVals = xCAT::zvmUtils->getNodeProps( 'noderes', $node, @propNames );
|
|
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;
|
|
}
|
|
|
|
# Combine NFS server and installation directory, e.g. 10.0.0.1/install
|
|
my $nfs = $master . $installDir;
|
|
|
|
# Get broadcast address
|
|
@words = split(/\./, $hostIP);
|
|
my ($ipUnpack) = unpack("N", pack("C4", @words));
|
|
@words = split(/\./, $mask);
|
|
my ($maskUnpack) = unpack("N", pack( "C4", @words ));
|
|
|
|
# Calculate broadcast address by inverting the netmask and do a logical or with network address
|
|
my $math = ( $ipUnpack & $maskUnpack ) + ( ~ $maskUnpack );
|
|
@words = unpack("C4", pack( "N", $math )) ;
|
|
my $broadcast = join(".", @words);
|
|
|
|
# Load VMCP module on HCP
|
|
$out = `ssh -o ConnectTimeout=5 $::SUDOER\@$hcp "/sbin/modprobe vmcp"`;
|
|
|
|
# Sample paramter file exists in installation CD (Use that as a guide)
|
|
my $sampleParm;
|
|
my $parmHeader;
|
|
my $parms;
|
|
my $parmFile;
|
|
my $kernelFile;
|
|
my $initFile;
|
|
|
|
# If punch is successful - Look for this string
|
|
my $searchStr = "created and transferred";
|
|
|
|
# Default parameters - SUSE
|
|
my $instNetDev = "osa"; # Only OSA interface type is supported
|
|
my $osaInterface = "qdio"; # OSA interface = qdio or lcs
|
|
my $osaMedium = "eth"; # OSA medium = eth (ethernet) or tr (token ring)
|
|
|
|
# Default parameters - RHEL
|
|
my $netType = "qeth";
|
|
my $portName = "FOOBAR";
|
|
my $portNo = "0";
|
|
|
|
# Get postscript content
|
|
my $postScript;
|
|
if ( $os =~ m/sles10/i ) {
|
|
$postScript = "/opt/xcat/share/xcat/install/scripts/post.sles10.s390x";
|
|
} elsif ( $os =~ m/sles11/i ) {
|
|
$postScript = "/opt/xcat/share/xcat/install/scripts/post.sles11.s390x";
|
|
} elsif ( $os =~ m/rhel5/i ) {
|
|
$postScript = "/opt/xcat/share/xcat/install/scripts/post.rhel5.s390x";
|
|
} elsif ( $os =~ m/rhel6/i ) {
|
|
$postScript = "/opt/xcat/share/xcat/install/scripts/post.rhel6.s390x";
|
|
} else {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) No postscript available for $os" );
|
|
return;
|
|
}
|
|
|
|
# SUSE installation
|
|
my $customTmpl;
|
|
my $pkglist;
|
|
my $patterns = '';
|
|
my $packages = '';
|
|
my $postBoot = "$installDir/postscripts/xcatinstallpost";
|
|
my $postInit = "$installDir/postscripts/xcatpostinit1";
|
|
if ( $os =~ m/sles/i ) {
|
|
|
|
# Create directory in FTP root (/install) to hold template
|
|
$out = `mkdir -p $installDir/custom/install/sles`;
|
|
|
|
# Copy autoyast template
|
|
$customTmpl = "$installDir/custom/install/sles/" . $node . "." . $profile . ".tmpl";
|
|
if ( -e "$installDir/custom/install/sles/$tmpl" ) {
|
|
$out = `cp $installDir/custom/install/sles/$tmpl $customTmpl`;
|
|
} else {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) An autoyast template does not exist for $os in $installDir/custom/install/sles/. Please create one." );
|
|
return;
|
|
}
|
|
|
|
# Get pkglist from /install/custom/install/sles/compute.sles11.s390x.otherpkgs.pkglist
|
|
# Original one is in /opt/xcat/share/xcat/install/sles/compute.sles11.s390x.otherpkgs.pkglist
|
|
$pkglist = "/install/custom/install/sles/" . $profile . "." . $osBase . "." . $arch . ".pkglist";
|
|
if ( !(-e $pkglist) ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing package list for $os in /install/custom/install/sles/" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Solution) Please create one or copy default one from /opt/xcat/share/xcat/install/sles/" );
|
|
return;
|
|
}
|
|
|
|
# Read in each software pattern or package
|
|
open (FILE, $pkglist);
|
|
while (<FILE>) {
|
|
chomp;
|
|
|
|
# Create <xml> tags, e.g.
|
|
# <package>apache</package>
|
|
# <pattern>directory_server</pattern>
|
|
$_ = xCAT::zvmUtils->trimStr($_);
|
|
if ($_ && $_ =~ /@/) {
|
|
$_ =~ s/@//g;
|
|
$patterns .= "<pattern>$_</pattern>";
|
|
} elsif ($_) {
|
|
$packages .= "<package>$_</package>";
|
|
}
|
|
|
|
}
|
|
close (FILE);
|
|
|
|
# Add appropriate software packages or patterns
|
|
$out = `sed -i -e "s,replace_software_packages,$packages,g" \ -e "s,replace_software_patterns,$patterns,g" $customTmpl`;
|
|
|
|
# Copy postscript into template
|
|
$out = `sed -i -e "/<scripts>/r $postScript" $customTmpl`;
|
|
|
|
# Copy the contents of /install/postscripts/xcatpostinit1
|
|
$out = `sed -i -e "/replace_xcatpostinit1/r $postInit" $customTmpl`;
|
|
$out = `sed -i -e "s,replace_xcatpostinit1,,g" $customTmpl`;
|
|
|
|
# Copy the contents of /install/postscripts/xcatinstallpost
|
|
$out = `sed -i -e "/replace_xcatinstallpost/r $postBoot" $customTmpl`;
|
|
$out = `sed -i -e "s,replace_xcatinstallpost,,g" $customTmpl`;
|
|
|
|
# Edit template
|
|
my $device;
|
|
my $chanIds = "$readChannel $writeChannel $dataChannel";
|
|
|
|
# SLES
|
|
if ( $os =~ m/sles10/i ) {
|
|
# SLES 10
|
|
$device = "qeth-bus-ccw-$readChannel";
|
|
} else {
|
|
$device = "eth0";
|
|
}
|
|
|
|
$out =
|
|
`sed -i -e "s,replace_host_address,$hostIP,g" \ -e "s,replace_long_name,$hostname,g" \ -e "s,replace_short_name,$node,g" \ -e "s,replace_domain,$domain,g" \ -e "s,replace_hostname,$node,g" \ -e "s,replace_nameserver,$nameserver,g" \ -e "s,replace_broadcast,$broadcast,g" \ -e "s,replace_device,$device,g" \ -e "s,replace_ipaddr,$hostIP,g" \ -e "s,replace_lladdr,$mac,g" \ -e "s,replace_netmask,$mask,g" \ -e "s,replace_network,$network,g" \ -e "s,replace_ccw_chan_ids,$chanIds,g" \ -e "s,replace_ccw_chan_mode,FOOBAR,g" \ -e "s,replace_gateway,$gateway,g" \ -e "s,replace_root_password,$passwd,g" \ -e "s,replace_nic_addr,$readChannel,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
|
|
# Find the SCSI device belonging to host
|
|
my @pools = split("\n", `ssh $::SUDOER\@$hcp "$::SUDO ls $::ZFCPPOOL"`);
|
|
my $hasZfcp = 0;
|
|
my $entry;
|
|
my $zfcpSection = "";
|
|
foreach (@pools) {
|
|
$entry = `ssh $::SUDOER\@$hcp "$::SUDO cat $::ZFCPPOOL/$_" | egrep -i ",$node,"`;
|
|
chomp($entry);
|
|
if (!$entry) {
|
|
next;
|
|
}
|
|
|
|
# Go through each zFCP device
|
|
my @device = split('\n', $entry);
|
|
foreach (@device) {
|
|
# Each entry contains: status,wwpn,lun,size,range,owner,channel,tag
|
|
@tmp = split(',', $_);
|
|
my $wwpn = $tmp[1];
|
|
my $lun = $tmp[2];
|
|
my $device = lc($tmp[6]);
|
|
my $tag = $tmp[7];
|
|
|
|
# If multiple WWPNs or device channels are specified (multipathing), just take the 1st one
|
|
if ($wwpn =~ m/;/i) {
|
|
@tmp = split(';', $wwpn);
|
|
$wwpn = xCAT::zvmUtils->trimStr($tmp[0]);
|
|
}
|
|
|
|
if ($device =~ m/;/i) {
|
|
@tmp = split(';', $device);
|
|
$device = xCAT::zvmUtils->trimStr($tmp[0]);
|
|
}
|
|
|
|
# Make sure WWPN and LUN do not have 0x prefix
|
|
$wwpn = xCAT::zvmUtils->replaceStr($wwpn, "0x", "");
|
|
$lun = xCAT::zvmUtils->replaceStr($lun, "0x", "");
|
|
|
|
# Make sure channel has a length of 4
|
|
while (length($device) < 4) {
|
|
$device = "0" . $device;
|
|
}
|
|
|
|
# zFCP variables must be in lower-case or AutoYast would get confused
|
|
$device = lc($device);
|
|
$wwpn = lc($wwpn);
|
|
$lun = lc($lun);
|
|
|
|
# Find tag in template and attach SCSI device associated with it
|
|
$out = `sed -i -e "s#$tag#/dev/disk/by-path/ccw-0.0.$device-zfcp-0x$wwpn:0x$lun#i" $customTmpl`;
|
|
|
|
# Generate <zfcp> section
|
|
$zfcpSection .= <<END;
|
|
<listentry>\\
|
|
<controller_id>0.0.$device</controller_id>\\
|
|
<fcp_lun>0x$lun</fcp_lun>\\
|
|
<wwpn>0x$wwpn</wwpn>\\
|
|
</listentry>\\
|
|
END
|
|
$hasZfcp = 1;
|
|
}
|
|
}
|
|
|
|
if ($hasZfcp) {
|
|
# Insert <zfcp> device list
|
|
my $find = 'replace_zfcp';
|
|
my $replace = <<END;
|
|
<devices config:type="list">\\
|
|
END
|
|
$replace .= $zfcpSection;
|
|
$replace .= <<END;
|
|
</devices>\\
|
|
END
|
|
my $expression = "'s#" . $find . "#" .$replace . "#i'";
|
|
$out = `sed -i -e $expression $customTmpl`;
|
|
|
|
xCAT::zvmUtils->printLn($callback, "$node: Inserting FCP devices into template... Done");
|
|
}
|
|
|
|
# Read sample parmfile in /install/sles10.2/s390x/1/boot/s390x/
|
|
$sampleParm = "$installDir/$os/s390x/1/boot/s390x/parmfile";
|
|
open( SAMPLEPARM, "<$sampleParm" );
|
|
|
|
# Search parmfile for -- ramdisk_size=65536 root=/dev/ram1 ro init=/linuxrc TERM=dumb
|
|
while (<SAMPLEPARM>) {
|
|
|
|
# If the line contains 'ramdisk_size'
|
|
if ( $_ =~ m/ramdisk_size/i ) {
|
|
$parmHeader = xCAT::zvmUtils->trimStr($_);
|
|
}
|
|
}
|
|
|
|
# Close sample parmfile
|
|
close(SAMPLEPARM);
|
|
|
|
# Create parmfile -- Limited to 10 lines
|
|
# End result should be:
|
|
# ramdisk_size=65536 root=/dev/ram1 ro init=/linuxrc TERM=dumb
|
|
# HostIP=10.0.0.5 Hostname=gpok5.endicott.ibm.com
|
|
# Gateway=10.0.0.1 Netmask=255.255.255.0
|
|
# Broadcast=10.0.0.0 Layer2=1 OSAHWaddr=02:00:01:FF:FF:FF
|
|
# ReadChannel=0.0.0800 WriteChannel=0.0.0801 DataChannel=0.0.0802
|
|
# Nameserver=10.0.0.1 Portname=OSAPORT Portno=0
|
|
# 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";
|
|
$parms = $parms . "AutoYaST=$ay\n";
|
|
$parms = $parms . "HostIP=$hostIP Hostname=$hostname\n";
|
|
$parms = $parms . "Gateway=$gateway Netmask=$mask\n";
|
|
|
|
# Set layer in autoyast profile
|
|
if ( $layer == 2 ) {
|
|
$parms = $parms . "Broadcast=$broadcast Layer2=1 OSAHWaddr=$mac\n";
|
|
} else {
|
|
$parms = $parms . "Broadcast=$broadcast Layer2=0\n";
|
|
}
|
|
|
|
$parms = $parms . "ReadChannel=$readChannel WriteChannel=$writeChannel DataChannel=$dataChannel\n";
|
|
$parms = $parms . "Nameserver=$nameserver Portname=$portName Portno=0\n";
|
|
$parms = $parms . "Install=$repo\n";
|
|
$parms = $parms . "UseVNC=1 VNCPassword=12345678\n";
|
|
$parms = $parms . "InstNetDev=$instNetDev OsaInterface=$osaInterface OsaMedium=$osaMedium Manual=0\n";
|
|
|
|
# Write to parmfile
|
|
$parmFile = "/tmp/" . $node . "Parm";
|
|
open( PARMFILE, ">$parmFile" );
|
|
print PARMFILE "$parms";
|
|
close(PARMFILE);
|
|
|
|
# Send kernel, parmfile, and initrd to reader to HCP
|
|
$kernelFile = "/tmp/" . $node . "Kernel";
|
|
$initFile = "/tmp/" . $node . "Initrd";
|
|
|
|
if ($repo) {
|
|
$out = `/usr/bin/wget $repo/boot/s390x/vmrdr.ikr -O $kernelFile --no-check-certificate`;
|
|
$out = `/usr/bin/wget $repo/boot/s390x/initrd -O $initFile --no-check-certificate`;
|
|
} else {
|
|
$out = `cp $installDir/$os/s390x/1/boot/s390x/vmrdr.ikr $kernelFile`;
|
|
$out = `cp $installDir/$os/s390x/1/boot/s390x/initrd $initFile`;
|
|
}
|
|
|
|
xCAT::zvmUtils->sendFile( $::SUDOER, $hcp, $kernelFile, $kernelFile );
|
|
xCAT::zvmUtils->sendFile( $::SUDOER, $hcp, $parmFile, $parmFile );
|
|
xCAT::zvmUtils->sendFile( $::SUDOER, $hcp, $initFile, $initFile );
|
|
|
|
# Set the virtual unit record devices online on HCP
|
|
$out = xCAT::zvmUtils->disableEnableDisk( $::SUDOER, $hcp, "-e", "c" );
|
|
$out = xCAT::zvmUtils->disableEnableDisk( $::SUDOER, $hcp, "-e", "d" );
|
|
|
|
# Purge reader
|
|
$out = xCAT::zvmCPUtils->purgeReader( $::SUDOER, $hcp, $userId );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Purging reader... Done" );
|
|
|
|
# Punch kernel to reader on HCP
|
|
$out = xCAT::zvmCPUtils->punch2Reader( $::SUDOER, $hcp, $userId, $kernelFile, "sles.kernel", "" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Punching kernel to reader... $out" );
|
|
if ( $out =~ m/Failed/i ) {
|
|
return;
|
|
}
|
|
|
|
# Punch parm to reader on HCP
|
|
$out = xCAT::zvmCPUtils->punch2Reader( $::SUDOER, $hcp, $userId, $parmFile, "sles.parm", "-t" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Punching parm to reader... $out" );
|
|
if ( $out =~ m/Failed/i ) {
|
|
return;
|
|
}
|
|
|
|
# Punch initrd to reader on HCP
|
|
$out = xCAT::zvmCPUtils->punch2Reader( $::SUDOER, $hcp, $userId, $initFile, "sles.initrd", "" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Punching initrd to reader... $out" );
|
|
if ( $out =~ m/Failed/i ) {
|
|
return;
|
|
}
|
|
|
|
# Remove kernel, parmfile, and initrd from /tmp
|
|
$out = `rm $parmFile $kernelFile $initFile`;
|
|
$out = `ssh -o ConnectTimeout=5 $::SUDOER\@$hcp "$::SUDO rm $parmFile $kernelFile $initFile"`;
|
|
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Kernel, parm, and initrd punched to reader. Ready for boot." );
|
|
}
|
|
|
|
# RHEL installation
|
|
elsif ( $os =~ m/rhel/i ) {
|
|
|
|
# Create directory in FTP root (/install) to hold template
|
|
$out = `mkdir -p $installDir/custom/install/rh`;
|
|
|
|
# Copy kickstart template
|
|
$customTmpl = "$installDir/custom/install/rh/" . $node . "." . $profile . ".tmpl";
|
|
if ( -e "$installDir/custom/install/rh/$tmpl" ) {
|
|
$out = `cp $installDir/custom/install/rh/$tmpl $customTmpl`;
|
|
} else {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) An kickstart template does not exist for $os in $installDir/custom/install/rh/" );
|
|
return;
|
|
}
|
|
|
|
# Get pkglist from /install/custom/install/rh/compute.rhel6.s390x.otherpkgs.pkglist
|
|
# Original one is in /opt/xcat/share/xcat/install/rh/compute.rhel6.s390x.otherpkgs.pkglist
|
|
$pkglist = "/install/custom/install/rh/" . $profile . "." . $osBase . "." . $arch . ".pkglist";
|
|
if ( !(-e $pkglist) ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing package list for $os in /install/custom/install/rh/" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Solution) Please create one or copy default one from /opt/xcat/share/xcat/install/rh/" );
|
|
return;
|
|
}
|
|
|
|
# Read in each software pattern or package
|
|
open (FILE, $pkglist);
|
|
while (<FILE>) {
|
|
chomp;
|
|
$_ = xCAT::zvmUtils->trimStr($_);
|
|
$packages .= "$_\\n";
|
|
}
|
|
close (FILE);
|
|
|
|
# Add appropriate software packages or patterns
|
|
$out = `sed -i -e "s,replace_software_packages,$packages,g" $customTmpl`;
|
|
|
|
# Copy postscript into template
|
|
$out = `sed -i -e "/%post/r $postScript" $customTmpl`;
|
|
|
|
# Copy the contents of /install/postscripts/xcatpostinit1
|
|
$out = `sed -i -e "/replace_xcatpostinit1/r $postInit" $customTmpl`;
|
|
$out = `sed -i -e "s,replace_xcatpostinit1,,g" $customTmpl`;
|
|
|
|
# Copy the contents of /install/postscripts/xcatinstallpost
|
|
$out = `sed -i -e "/replace_xcatinstallpost/r $postBoot" $customTmpl`;
|
|
$out = `sed -i -e "s,replace_xcatinstallpost,,g" $customTmpl`;
|
|
|
|
# Edit template
|
|
if (!$repo) {
|
|
$repo = "http://$nfs/$os/s390x";
|
|
}
|
|
|
|
$out =
|
|
`sed -i -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
|
|
# Find the SCSI device belonging to host
|
|
my @pools = split("\n", `ssh $::SUDOER\@$hcp "$::SUDO ls $::ZFCPPOOL"`);
|
|
my $hasZfcp = 0;
|
|
my $entry;
|
|
my $zfcpSection = "";
|
|
foreach (@pools) {
|
|
$entry = `ssh $::SUDOER\@$hcp "$::SUDO cat $::ZFCPPOOL/$_" | egrep -i ",$node,"`;
|
|
chomp($entry);
|
|
if (!$entry) {
|
|
next;
|
|
}
|
|
|
|
# Go through each zFCP device
|
|
my @device = split('\n', $entry);
|
|
foreach (@device) {
|
|
# Each entry contains: status,wwpn,lun,size,range,owner,channel,tag
|
|
@tmp = split(',', $_);
|
|
my $wwpn = $tmp[1];
|
|
my $lun = $tmp[2];
|
|
my $device = lc($tmp[6]);
|
|
my $tag = $tmp[7];
|
|
|
|
# If multiple WWPNs or device channels are specified (multipathing), just take the 1st one
|
|
if ($wwpn =~ m/;/i) {
|
|
@tmp = split(';', $wwpn);
|
|
$wwpn = xCAT::zvmUtils->trimStr($tmp[0]);
|
|
}
|
|
|
|
if ($device =~ m/;/i) {
|
|
@tmp = split(';', $device);
|
|
$device = xCAT::zvmUtils->trimStr($tmp[0]);
|
|
}
|
|
|
|
# Make sure WWPN and LUN do not have 0x prefix
|
|
$wwpn = xCAT::zvmUtils->replaceStr($wwpn, "0x", "");
|
|
$lun = xCAT::zvmUtils->replaceStr($lun, "0x", "");
|
|
|
|
# Make sure channel has a length of 4
|
|
while (length($device) < 4) {
|
|
$device = "0" . $device;
|
|
}
|
|
|
|
# zFCP variables must be in lower-case or AutoYast would get confused.
|
|
$device = lc($device);
|
|
$wwpn = lc($wwpn);
|
|
$lun = lc($lun);
|
|
|
|
# Create zfcp section
|
|
$zfcpSection = "zfcp --devnum 0.0.$device --wwpn 0x$wwpn --fcplun 0x$lun" . '\n';
|
|
|
|
# Look for replace_zfcp keyword in template and replace it
|
|
$out = `sed -i -e "s,$tag,$zfcpSection,i" $customTmpl`;
|
|
$hasZfcp = 1;
|
|
}
|
|
}
|
|
|
|
if ($hasZfcp) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: Inserting FCP devices into template... Done");
|
|
}
|
|
|
|
# Read sample parmfile in /install/rhel5.3/s390x/images
|
|
$sampleParm = "$installDir/$os/s390x/images/generic.prm";
|
|
open( SAMPLEPARM, "<$sampleParm" );
|
|
|
|
# Search parmfile for -- root=/dev/ram0 ro ip=off ramdisk_size=40000
|
|
while (<SAMPLEPARM>) {
|
|
|
|
# If the line contains 'ramdisk_size'
|
|
if ( $_ =~ m/ramdisk_size/i ) {
|
|
$parmHeader = xCAT::zvmUtils->trimStr($_);
|
|
|
|
# RHEL 6.1 needs cio_ignore in order to install
|
|
if ( !($os =~ m/rhel6.1/i) ) {
|
|
$parmHeader =~ s/cio_ignore=all,!0.0.0009//g;
|
|
}
|
|
}
|
|
}
|
|
|
|
# Close sample parmfile
|
|
close(SAMPLEPARM);
|
|
|
|
# Get mdisk virtual address
|
|
my @mdisks = xCAT::zvmUtils->getMdisks( $callback, $::SUDOER, $node );
|
|
@mdisks = sort(@mdisks);
|
|
my $dasd = "";
|
|
my $devices = "";
|
|
my $i = 0;
|
|
foreach (@mdisks) {
|
|
$i = $i + 1;
|
|
@words = split( ' ', $_ );
|
|
|
|
# Do not put a comma at the end of the last disk address
|
|
if ( $i == @mdisks ) {
|
|
$dasd = $dasd . "0.0.$words[1]";
|
|
} else {
|
|
$dasd = $dasd . "0.0.$words[1],";
|
|
}
|
|
}
|
|
|
|
# Character limit of 50 in parm file for DASD parameter
|
|
if (length($dasd) > 50) {
|
|
@words = split( ',', $dasd );
|
|
$dasd = $words[0] . "-" . $words[@words - 1];
|
|
}
|
|
|
|
# Get dedicated virtual address
|
|
my @dedicates = xCAT::zvmUtils->getDedicates( $callback, $::SUDOER, $node );
|
|
@dedicates = sort(@dedicates);
|
|
$i = 0;
|
|
foreach (@dedicates) {
|
|
$i = $i + 1;
|
|
@words = split( ' ', $_ );
|
|
|
|
# Do not put a comma at the end of the last disk address
|
|
if ( $i == @dedicates ) {
|
|
$devices = $devices . "0.0.$words[1]";
|
|
} else {
|
|
$devices = $devices . "0.0.$words[1],";
|
|
}
|
|
}
|
|
|
|
# Character limit of 50 in parm file for DASD parameter
|
|
if (length($devices) > 50) {
|
|
@words = split( ',', $devices );
|
|
$devices = $words[0] . "-" . $words[@words - 1];
|
|
}
|
|
|
|
# Concat dedicated devices and DASD together
|
|
if ($devices) {
|
|
if ($dasd) {
|
|
$dasd = $dasd . "," . $devices;
|
|
} else {
|
|
$dasd = $devices;
|
|
}
|
|
}
|
|
|
|
# Create parmfile -- Limited to 80 characters/line, maximum of 11 lines
|
|
# End result should be:
|
|
# ramdisk_size=40000 root=/dev/ram0 ro ip=off
|
|
# ks=ftp://10.0.0.1/rhel5.3/s390x/compute.rhel5.s390x.tmpl
|
|
# RUNKS=1 cmdline
|
|
# DASD=0.0.0100 HOSTNAME=gpok4.endicott.ibm.com
|
|
# NETTYPE=qeth IPADDR=10.0.0.4
|
|
# SUBCHANNELS=0.0.0800,0.0.0801,0.0.0800
|
|
# NETWORK=10.0.0.0 NETMASK=255.255.255.0
|
|
# SEARCHDNS=endicott.ibm.com BROADCAST=10.0.0.255
|
|
# GATEWAY=10.0.0.1 DNS=9.0.2.11 MTU=1500
|
|
# PORTNAME=UNASSIGNED PORTNO=0 LAYER2=0
|
|
# vnc vncpassword=12345678
|
|
my $ks = "http://$nfs/custom/install/rh/" . $node . "." . $profile . ".tmpl";
|
|
|
|
$parms = $parmHeader . "\n";
|
|
$parms = $parms . "ks=$ks\n";
|
|
$parms = $parms . "RUNKS=1 cmdline\n";
|
|
$parms = $parms . "DASD=$dasd\n";
|
|
$parms = $parms . "HOSTNAME=$hostname NETTYPE=$netType IPADDR=$hostIP\n";
|
|
$parms = $parms . "SUBCHANNELS=$readChannel,$writeChannel,$dataChannel\n";
|
|
$parms = $parms . "NETWORK=$network NETMASK=$mask\n";
|
|
$parms = $parms . "SEARCHDNS=$domain BROADCAST=$broadcast\n";
|
|
$parms = $parms . "GATEWAY=$gateway DNS=$nameserver MTU=1500\n";
|
|
|
|
# Set layer in kickstart profile
|
|
if ( $layer == 2 ) {
|
|
$parms = $parms . "PORTNAME=$portName PORTNO=$portNo LAYER2=1 MACADDR=$mac\n";
|
|
} else {
|
|
$parms = $parms . "PORTNAME=$portName PORTNO=$portNo LAYER2=0\n";
|
|
}
|
|
|
|
$parms = $parms . "vnc vncpassword=12345678\n";
|
|
|
|
# Write to parmfile
|
|
$parmFile = "/tmp/" . $node . "Parm";
|
|
open( PARMFILE, ">$parmFile" );
|
|
print PARMFILE "$parms";
|
|
close(PARMFILE);
|
|
|
|
# Send kernel, parmfile, conf, and initrd to reader to HCP
|
|
$kernelFile = "/tmp/" . $node . "Kernel";
|
|
$initFile = "/tmp/" . $node . "Initrd";
|
|
|
|
# Copy over kernel, parmfile, conf, and initrd from remote repository
|
|
if ($repo) {
|
|
$out = `/usr/bin/wget $repo/images/kernel.img -O $kernelFile --no-check-certificate`;
|
|
$out = `/usr/bin/wget $repo/images/initrd.img -O $initFile --no-check-certificate`;
|
|
} else {
|
|
$out = `cp $installDir/$os/s390x/images/kernel.img $kernelFile`;
|
|
$out = `cp $installDir/$os/s390x/images/initrd.img $initFile`;
|
|
}
|
|
|
|
xCAT::zvmUtils->sendFile( $::SUDOER, $hcp, $kernelFile, $kernelFile );
|
|
xCAT::zvmUtils->sendFile( $::SUDOER, $hcp, $parmFile, $parmFile );
|
|
xCAT::zvmUtils->sendFile( $::SUDOER, $hcp, $initFile, $initFile );
|
|
|
|
# Set the virtual unit record devices online
|
|
$out = xCAT::zvmUtils->disableEnableDisk( $::SUDOER, $hcp, "-e", "c" );
|
|
$out = xCAT::zvmUtils->disableEnableDisk( $::SUDOER, $hcp, "-e", "d" );
|
|
|
|
# Purge reader
|
|
$out = xCAT::zvmCPUtils->purgeReader( $::SUDOER, $hcp, $userId );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Purging reader... Done" );
|
|
|
|
# Punch kernel to reader on HCP
|
|
$out = xCAT::zvmCPUtils->punch2Reader( $::SUDOER, $hcp, $userId, $kernelFile, "rhel.kernel", "" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Punching kernel to reader... $out" );
|
|
if ( $out =~ m/Failed/i ) {
|
|
return;
|
|
}
|
|
|
|
# Punch parm to reader on HCP
|
|
$out = xCAT::zvmCPUtils->punch2Reader( $::SUDOER, $hcp, $userId, $parmFile, "rhel.parm", "-t" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Punching parm to reader... $out" );
|
|
if ( $out =~ m/Failed/i ) {
|
|
return;
|
|
}
|
|
|
|
# Punch initrd to reader on HCP
|
|
$out = xCAT::zvmCPUtils->punch2Reader( $::SUDOER, $hcp, $userId, $initFile, "rhel.initrd", "" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Punching initrd to reader... $out" );
|
|
if ( $out =~ m/Failed/i ) {
|
|
return;
|
|
}
|
|
|
|
# Remove kernel, parmfile, and initrd from /tmp
|
|
$out = `rm $parmFile $kernelFile $initFile`;
|
|
$out = `ssh -o ConnectTimeout=5 $::SUDOER\@$hcp "$::SUDO rm $parmFile $kernelFile $initFile"`;
|
|
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Kernel, parm, and initrd punched to reader. Ready for boot." );
|
|
}
|
|
} elsif ( $action eq "statelite" ) {
|
|
|
|
# Get node group from 'nodelist' table
|
|
@propNames = ('groups');
|
|
$propVals = xCAT::zvmUtils->getTabPropsByKey( 'nodelist', 'node', $node, @propNames );
|
|
my $group = $propVals->{'groups'};
|
|
|
|
# Get node statemnt (statelite mount point) from 'statelite' table
|
|
@propNames = ('statemnt');
|
|
$propVals = xCAT::zvmUtils->getTabPropsByKey( 'statelite', 'node', $node, @propNames );
|
|
my $stateMnt = $propVals->{'statemnt'};
|
|
if ( !$stateMnt ) {
|
|
$propVals = xCAT::zvmUtils->getTabPropsByKey( 'statelite', 'node', $group, @propNames );
|
|
$stateMnt = $propVals->{'statemnt'};
|
|
|
|
if ( !$stateMnt ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing node statemnt in statelite table. Please specify one." );
|
|
return;
|
|
}
|
|
}
|
|
|
|
# Netboot directory
|
|
my $netbootDir = "$installDir/netboot/$os/$arch/$profile";
|
|
my $kernelFile = "$netbootDir/kernel";
|
|
my $parmFile = "$netbootDir/parm-statelite";
|
|
my $initFile = "$netbootDir/initrd-statelite.gz";
|
|
|
|
# If parmfile exists
|
|
if ( -e $parmFile ) {
|
|
# Do nothing
|
|
} else {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Creating parmfile" );
|
|
|
|
my $sampleParm;
|
|
my $parmHeader;
|
|
my $parms;
|
|
if ( $os =~ m/sles/i ) {
|
|
if ( -e "$installDir/$os/s390x/1/boot/s390x/parmfile" ) {
|
|
# Read sample parmfile in /install/sles11.1/s390x/1/boot/s390x/
|
|
$sampleParm = "$installDir/$os/s390x/1/boot/s390x/parmfile";
|
|
} else {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing $installDir/$os/s390x/1/boot/s390x/parmfile" );
|
|
return;
|
|
}
|
|
} elsif ( $os =~ m/rhel/i ) {
|
|
if ( -e "$installDir/$os/s390x/images/generic.prm" ) {
|
|
# Read sample parmfile in /install/rhel5.3/s390x/images
|
|
$sampleParm = "$installDir/$os/s390x/images/generic.prm";
|
|
} else {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing $installDir/$os/s390x/images/generic.prm" );
|
|
return;
|
|
}
|
|
}
|
|
|
|
open( SAMPLEPARM, "<$sampleParm" );
|
|
|
|
# Search parmfile for -- ramdisk_size=65536 root=/dev/ram1 ro init=/linuxrc TERM=dumb
|
|
while (<SAMPLEPARM>) {
|
|
# If the line contains 'ramdisk_size'
|
|
if ( $_ =~ m/ramdisk_size/i ) {
|
|
$parmHeader = xCAT::zvmUtils->trimStr($_);
|
|
}
|
|
}
|
|
|
|
# Close sample parmfile
|
|
close(SAMPLEPARM);
|
|
|
|
# Create parmfile
|
|
# End result should be:
|
|
# ramdisk_size=65536 root=/dev/ram1 ro init=/linuxrc TERM=dumb
|
|
# NFSROOT=10.1.100.1:/install/netboot/sles11.1.1/s390x/compute
|
|
# STATEMNT=10.1.100.1:/lite/state XCAT=10.1.100.1:3001
|
|
$parms = $parmHeader . "\n";
|
|
$parms = $parms . "NFSROOT=$master:$netbootDir\n";
|
|
$parms = $parms . "STATEMNT=$stateMnt XCAT=$master:$xcatdPort\n";
|
|
|
|
# Write to parmfile
|
|
open( PARMFILE, ">$parmFile" );
|
|
print PARMFILE "$parms";
|
|
close(PARMFILE);
|
|
}
|
|
|
|
# Temporary kernel, parmfile, and initrd
|
|
my $tmpKernelFile = "/tmp/$os-kernel";
|
|
my $tmpParmFile = "/tmp/$os-parm-statelite";
|
|
my $tmpInitFile = "/tmp/$os-initrd-statelite.gz";
|
|
|
|
if (`ssh -o ConnectTimeout=5 $::SUDOER\@$hcp "$::SUDO ls /tmp" | grep "$os-kernel"`) {
|
|
# Do nothing
|
|
} else {
|
|
# Send kernel to reader to HCP
|
|
xCAT::zvmUtils->sendFile( $::SUDOER, $hcp, $kernelFile, $tmpKernelFile );
|
|
}
|
|
|
|
if (`ssh -o ConnectTimeout=5 $::SUDOER\@$hcp "$::SUDO ls /tmp" | grep "$os-parm-statelite"`) {
|
|
# Do nothing
|
|
} else {
|
|
# Send parmfile to reader to HCP
|
|
xCAT::zvmUtils->sendFile( $::SUDOER, $hcp, $parmFile, $tmpParmFile );
|
|
}
|
|
|
|
if (`ssh -o ConnectTimeout=5 $::SUDOER\@$hcp "$::SUDO ls /tmp" | grep "$os-initrd-statelite.gz"`) {
|
|
# Do nothing
|
|
} else {
|
|
# Send initrd to reader to HCP
|
|
xCAT::zvmUtils->sendFile( $::SUDOER, $hcp, $initFile, $tmpInitFile );
|
|
}
|
|
|
|
# Set the virtual unit record devices online
|
|
$out = xCAT::zvmUtils->disableEnableDisk( $::SUDOER, $hcp, "-e", "c" );
|
|
$out = xCAT::zvmUtils->disableEnableDisk( $::SUDOER, $hcp, "-e", "d" );
|
|
|
|
# Purge reader
|
|
$out = xCAT::zvmCPUtils->purgeReader( $::SUDOER, $hcp, $userId );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Purging reader... Done" );
|
|
|
|
# Kernel, parm, and initrd are in /install/netboot/<os>/<arch>/<profile>
|
|
# Punch kernel to reader on HCP
|
|
$out = xCAT::zvmCPUtils->punch2Reader( $::SUDOER, $hcp, $userId, $tmpKernelFile, "sles.kernel", "" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Punching kernel to reader... $out" );
|
|
if ( $out =~ m/Failed/i ) {
|
|
return;
|
|
}
|
|
|
|
# Punch parm to reader on HCP
|
|
$out = xCAT::zvmCPUtils->punch2Reader( $::SUDOER, $hcp, $userId, $tmpParmFile, "sles.parm", "-t" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Punching parm to reader... $out" );
|
|
if ( $out =~ m/Failed/i ) {
|
|
return;
|
|
}
|
|
|
|
# Punch initrd to reader on HCP
|
|
$out = xCAT::zvmCPUtils->punch2Reader( $::SUDOER, $hcp, $userId, $tmpInitFile, "sles.initrd", "" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Punching initrd to reader... $out" );
|
|
if ( $out =~ m/Failed/i ) {
|
|
return;
|
|
}
|
|
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Kernel, parm, and initrd punched to reader. Ready for boot." );
|
|
} elsif ( $action eq "netboot" ) {
|
|
|
|
# Obtain the location of the install root directory
|
|
my $installRoot = xCAT::TableUtils->getInstallDir();
|
|
|
|
# Verify the image exists
|
|
my $imageFile;
|
|
my $deployImgDir = "$installRoot/$action/$os/$arch/$profile";
|
|
my @imageFiles = glob "$deployImgDir/*.img";
|
|
if (@imageFiles == 0) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) $deployImgDir does not contain image files" );
|
|
return;
|
|
} elsif (@imageFiles > 1) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) $deployImgDir contains more than the expected number of image files" );
|
|
return;
|
|
} else {
|
|
$imageFile = (split('/', $imageFiles[0]))[-1];
|
|
}
|
|
|
|
if (! defined $device) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Image device was not specified" );
|
|
return;
|
|
}
|
|
|
|
# Prepare the deployable netboot mount point on zHCP, if they need to be established.
|
|
my $remoteDeployDir;
|
|
my $rc = xCAT::zvmUtils->establishMount($callback, $::SUDOER, $::SUDO, $hcp, "$installRoot/$action", "ro", \$remoteDeployDir);
|
|
if ( $rc ) {
|
|
# Mount failed
|
|
return;
|
|
}
|
|
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Deploying the image using the zHCP node" );
|
|
|
|
# Copy the image to the target disk using the zHCP node
|
|
xCAT::zvmUtils->printSyslog( "nodeset() unpackdiskimage $userId $device $remoteDeployDir/$os/$arch/$profile/$imageFile" );
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/unpackdiskimage $userId $device $remoteDeployDir/$os/$arch/$profile/$imageFile"`;
|
|
$rc = $?;
|
|
|
|
my $reasonString = "";
|
|
$rc = xCAT::zvmUtils->checkOutputExtractReason($callback, $out, \$reasonString);
|
|
if ($rc != 0) {
|
|
my $reason = "Reason: $reasonString";
|
|
xCAT::zvmUtils->printSyslog( "nodeset() unpackdiskimage of $userId $device failed. $reason" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Unable to deploy the image to $userId $device. $reason" );
|
|
return;
|
|
}
|
|
|
|
# If the transport file was specified then setup the transport disk.
|
|
if ($transport) {
|
|
my $transImgDir = "$installRoot/staging/transport";
|
|
if(!-d $transImgDir) {
|
|
mkpath($transImgDir);
|
|
}
|
|
|
|
# Create unique transport directory and copy the transport file to it
|
|
my $transportDir = `/bin/mktemp -d $installDir/staging/transport/XXXXXX`;
|
|
chomp($transportDir);
|
|
if ($remoteHost) {
|
|
# Copy the transport file from the remote system to the local transport directory.
|
|
xCAT::zvmUtils->printLn( $callback, "/usr/bin/scp -B $remoteHost:$transport $transportDir" );
|
|
$out = `/usr/bin/scp -v -B $remoteHost:$transport $transportDir`;
|
|
$rc = $?;
|
|
} else {
|
|
# Safely copy the transport file from a local directory.
|
|
$out = `/bin/cp $transport $transportDir`;
|
|
$rc = $?;
|
|
}
|
|
|
|
if ($rc != 0) {
|
|
# Copy failed Get rid of the unique directory that was going to receive the copy.
|
|
rmtree $transportDir;
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Unable to copy the transport file");
|
|
return;
|
|
}
|
|
|
|
# Purge the target node's reader
|
|
$out = xCAT::zvmCPUtils->purgeReader( $::SUDOER, $hcp, $userId );
|
|
xCAT::zvmUtils->printLn($callback, "$node: Purging reader... Done");
|
|
|
|
# Online zHCP's punch
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/chccwdev -e 00d && echo $?"`;
|
|
if ($out != '0') {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Failed to online the zHCP's punch");
|
|
return;
|
|
}
|
|
|
|
# Load VMCP module on HCP
|
|
$out = `ssh -o ConnectTimeout=5 $::SUDOER\@$hcp "/sbin/modprobe vmcp"`;
|
|
if ($out != '0') {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Failed to load the vmcp module on the zHCP node");
|
|
return;
|
|
}
|
|
|
|
# Set the punch to class 'x'
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/vmcp spool punch class x"`;
|
|
if ($out != '0') {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Failed to spool the punch on the zHCP node");
|
|
return;
|
|
}
|
|
|
|
# Punch files to node's reader so it could be pulled on boot
|
|
# Reader = transport disk
|
|
my @files = glob "$transportDir/*";
|
|
foreach (@files) {
|
|
my $file = basename($_);
|
|
my $filePath = "/tmp/$node-" . $file;
|
|
|
|
# Spool file only accepts [A-Za-z] and file name can only be 8-characters long
|
|
my @filePortions = split( '\.', $file );
|
|
if (( @filePortions > 2 ) ||
|
|
( $filePortions[0] =~ m/[^a-zA-Z0-9]/ ) || ( length($filePortions[0]) > 8 ) || ( length($filePortions[0]) < 1 ) ||
|
|
( $filePortions[1] =~ m/[^a-zA-Z0-9]{1,8}/ ) || ( length($filePortions[1]) > 8 )) {
|
|
$out = `/bin/rm -rf $transportDir`;
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) $file contains a file name or file type portion that is longer than 8 characters, or not alphanumeric ");
|
|
return;
|
|
}
|
|
|
|
xCAT::zvmUtils->sendFile($::SUDOER, $hcp, $_, $filePath);
|
|
|
|
my $punchOpt = "";
|
|
if ($file =~ /.txt/ || $file =~ /.sh/) {
|
|
$punchOpt = "-t";
|
|
}
|
|
$out = xCAT::zvmCPUtils->punch2Reader($::SUDOER, $hcp, $userId, $filePath, "$file", $punchOpt);
|
|
|
|
# Clean up file
|
|
`ssh $::SUDOER\@$hcp "$::SUDO /bin/rm $filePath"`;
|
|
|
|
xCAT::zvmUtils->printLn($callback, "$node: Punching $file to reader... $out");
|
|
if ($out =~ m/Failed/i) {
|
|
# Clean up transport directory
|
|
$out = `/bin/rm -rf $transportDir`;
|
|
return;
|
|
}
|
|
}
|
|
|
|
# Clean up transport directory
|
|
$out = `/bin/rm -rf $transportDir`;
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Completed deploying image($os-$arch-netboot-$profile)" );
|
|
}
|
|
} else {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Option not supported" );
|
|
return;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 getMacs
|
|
|
|
Description : Get the MAC address of a given node
|
|
* Requires the node be online
|
|
* Saves MAC address in 'mac' table
|
|
Arguments : Node
|
|
Returns : Nothing
|
|
Example : getMacs($callback, $node, $args);
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
sub getMacs {
|
|
|
|
# Get inputs
|
|
my ( $callback, $node, $args ) = @_;
|
|
my $force = '';
|
|
if ($args) {
|
|
@ARGV = @$args;
|
|
|
|
# Parse options
|
|
GetOptions( 'f' => \$force );
|
|
}
|
|
|
|
# Get node properties from 'zvm' table
|
|
my @propNames = ( 'hcp', 'userid' );
|
|
my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
|
|
|
|
# Get zHCP
|
|
my $hcp = $propVals->{'hcp'};
|
|
if ( !$hcp ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing node HCP" );
|
|
return;
|
|
}
|
|
|
|
# Get node user ID
|
|
my $userId = $propVals->{'userid'};
|
|
if ( !$userId ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing user ID" );
|
|
return;
|
|
}
|
|
# Capitalize user ID
|
|
$userId =~ tr/a-z/A-Z/;
|
|
|
|
# Get MAC address in 'mac' table
|
|
@propNames = ('mac');
|
|
$propVals = xCAT::zvmUtils->getNodeProps( 'mac', $node, @propNames );
|
|
my $mac;
|
|
if ( $propVals->{'mac'} && !$force) {
|
|
|
|
# Get MAC address
|
|
$mac = $propVals->{'mac'};
|
|
xCAT::zvmUtils->printLn( $callback, "$node: $mac" );
|
|
return;
|
|
}
|
|
|
|
# If MAC address is not in the 'mac' table, get it using VMCP
|
|
xCAT::zvmCPUtils->loadVmcp($::SUDOER, $node);
|
|
|
|
# Get xCat MN Lan/VSwitch name
|
|
my $out = `ssh -o ConnectTimeout=5 $::SUDOER\@$hcp "$::SUDO /sbin/vmcp q v nic" | egrep -i "VSWITCH|LAN"`;
|
|
my @lines = split( '\n', $out );
|
|
my @words;
|
|
|
|
# Go through each line and extract VSwitch and Lan names
|
|
# and create search string
|
|
my $searchStr = "";
|
|
my $i;
|
|
for ( $i = 0 ; $i < @lines ; $i++ ) {
|
|
|
|
# Extract VSwitch name
|
|
if ( $lines[$i] =~ m/VSWITCH/i ) {
|
|
@words = split( ' ', $lines[$i] );
|
|
$searchStr = $searchStr . "$words[4]";
|
|
}
|
|
|
|
# Extract Lan name
|
|
elsif ( $lines[$i] =~ m/LAN/i ) {
|
|
@words = split( ' ', $lines[$i] );
|
|
$searchStr = $searchStr . "$words[4]";
|
|
}
|
|
|
|
if ( $i != ( @lines - 1 ) ) {
|
|
$searchStr = $searchStr . "|";
|
|
}
|
|
}
|
|
|
|
# Get MAC address of node
|
|
# This node should be on only 1 of the networks that the xCAT MN is on
|
|
$out = `ssh -o ConnectTimeout=5 $::SUDOER\@$node "/sbin/vmcp q v nic" | egrep -i "$searchStr"`;
|
|
if ( !$out ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Failed to find MAC address" );
|
|
return;
|
|
}
|
|
|
|
@lines = split( '\n', $out );
|
|
@words = split( ' ', $lines[0] );
|
|
$mac = $words[1];
|
|
|
|
# Replace - with :
|
|
$mac = xCAT::zvmUtils->replaceStr( $mac, "-", ":" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: $mac" );
|
|
|
|
# Save MAC address and network interface into 'mac' table
|
|
xCAT::zvmUtils->setNodeProp( 'mac', $node, 'mac', $mac );
|
|
|
|
return;
|
|
}
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 netBoot
|
|
|
|
Description : Boot from network
|
|
Arguments : Node
|
|
Address to IPL from
|
|
Returns : Nothing
|
|
Example : netBoot($callback, $node, $args);
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
sub netBoot {
|
|
|
|
# Get inputs
|
|
my ( $callback, $node, $args ) = @_;
|
|
|
|
# Get node properties from 'zvm' table
|
|
my @propNames = ( 'hcp', 'userid' );
|
|
my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
|
|
|
|
# Get zHCP
|
|
my $hcp = $propVals->{'hcp'};
|
|
if ( !$hcp ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing node HCP" );
|
|
return;
|
|
}
|
|
|
|
# Get node user ID
|
|
my $userId = $propVals->{'userid'};
|
|
if ( !$userId ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing user ID" );
|
|
return;
|
|
}
|
|
# Capitalize user ID
|
|
$userId =~ tr/a-z/A-Z/;
|
|
|
|
xCAT::zvmUtils->printSyslog("sudoer:$::SUDOER zHCP:$hcp sudo:$::SUDO");
|
|
|
|
# Get IPL
|
|
my @ipl = split( '=', $args->[0] );
|
|
if ( !( $ipl[0] eq "ipl" ) ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing IPL" );
|
|
return;
|
|
}
|
|
|
|
# Boot node
|
|
my $out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Activate -T $userId"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Activate -T $userId");
|
|
xCAT::zvmUtils->printSyslog("$out");
|
|
|
|
# IPL when virtual server is online
|
|
sleep(5);
|
|
$out = xCAT::zvmCPUtils->sendCPCmd( $::SUDOER, $hcp, $userId, "IPL $ipl[1]" );
|
|
xCAT::zvmUtils->printSyslog("IPL $ipl[1]");
|
|
xCAT::zvmUtils->printSyslog("$out");
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Booting from $ipl[1]... Done" );
|
|
|
|
return;
|
|
}
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 updateNode (No longer supported)
|
|
|
|
Description : Update node
|
|
Arguments : Node
|
|
Option
|
|
Returns : Nothing
|
|
Example : updateNode($callback, $node, $args);
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
sub updateNode {
|
|
|
|
# Get inputs
|
|
my ( $callback, $node, $args ) = @_;
|
|
|
|
# Get node properties from 'zvm' table
|
|
my @propNames = ( 'hcp', 'userid' );
|
|
my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
|
|
|
|
# Get zHCP
|
|
my $hcp = $propVals->{'hcp'};
|
|
if ( !$hcp ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing node HCP" );
|
|
return;
|
|
}
|
|
|
|
# Get node user ID
|
|
my $userId = $propVals->{'userid'};
|
|
if ( !$userId ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing user ID" );
|
|
return;
|
|
}
|
|
# Capitalize user ID
|
|
$userId =~ tr/a-z/A-Z/;
|
|
|
|
# Get install directory
|
|
my @entries = xCAT::TableUtils->get_site_attribute("installdir");
|
|
my $installDir = $entries[0];
|
|
|
|
# Get host IP and hostname from /etc/hosts
|
|
my $out = `cat /etc/hosts | egrep -i "$node |$node."`;
|
|
my @words = split( ' ', $out );
|
|
my $hostIP = $words[0];
|
|
my $hostname = $words[2];
|
|
if (!($hostname =~ m/./i)) {
|
|
$hostname = $words[1];
|
|
}
|
|
|
|
if ( !$hostIP || !$hostname ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing IP for $node in /etc/hosts" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Solution) Verify that the node's IP address is specified in the hosts table and then run makehosts" );
|
|
return;
|
|
}
|
|
|
|
# Get first 3 octets of node IP (IPv4)
|
|
@words = split( /\./, $hostIP );
|
|
my $octets = "$words[0].$words[1].$words[2]";
|
|
|
|
# Get networks in 'networks' table
|
|
my $entries = xCAT::zvmUtils->getAllTabEntries('networks');
|
|
|
|
# Go through each network
|
|
my $network;
|
|
foreach (@$entries) {
|
|
|
|
# Get network
|
|
$network = $_->{'net'};
|
|
|
|
# If networks contains the first 3 octets of the node IP
|
|
if ( $network =~ m/$octets/i ) {
|
|
|
|
# Exit loop
|
|
last;
|
|
} else {
|
|
$network = "";
|
|
}
|
|
}
|
|
|
|
# If no network found
|
|
if ( !$network ) {
|
|
|
|
# Exit
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Node does not belong to any network in the networks table" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Solution) Specify the subnet in the networks table. The mask, gateway, tftpserver, and nameservers must be specified for the subnet." );
|
|
return;
|
|
}
|
|
|
|
# Get FTP server
|
|
@propNames = ('tftpserver');
|
|
$propVals = xCAT::zvmUtils->getTabPropsByKey( 'networks', 'net', $network, @propNames );
|
|
my $nfs = $propVals->{'tftpserver'};
|
|
if ( !$nfs ) {
|
|
|
|
# It is acceptable to not have a gateway
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing FTP server" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Solution) Specify the tftpserver for the subnet in the networks table" );
|
|
return;
|
|
}
|
|
|
|
# Update node operating system
|
|
if ( $args->[0] eq "--release" ) {
|
|
my $version = $args->[1];
|
|
|
|
if ( !$version ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing operating system release. Please specify one." );
|
|
return;
|
|
}
|
|
|
|
# Get node operating system
|
|
my $os = xCAT::zvmUtils->getOs($::SUDOER, $node);
|
|
|
|
# Check node OS is the same as the version OS given
|
|
# You do not want to update a SLES with a RHEL
|
|
if ( ( ( $os =~ m/SUSE/i ) && !( $version =~ m/sles/i ) ) || ( ( $os =~ m/Red Hat/i ) && !( $version =~ m/rhel/i ) ) ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Node operating system is different from the operating system given to upgrade to. Please correct." );
|
|
return;
|
|
}
|
|
|
|
# Generate FTP path to operating system image
|
|
my $path;
|
|
if ( $version =~ m/sles/i ) {
|
|
|
|
# The following only applies to SLES 10
|
|
# SLES 11 requires zypper
|
|
|
|
# SuSE Enterprise Linux path - ftp://10.0.0.1/sles10.3/s390x/1/
|
|
$path = "http://$nfs/install/$version/s390x/1/";
|
|
|
|
# Add installation source using rug
|
|
$out = `ssh $::SUDOER\@$node "rug sa -t zypp $path $version"`;
|
|
xCAT::zvmUtils->printLn( $callback, "$node: $out" );
|
|
|
|
# Subscribe to catalog
|
|
$out = `ssh $::SUDOER\@$node "rug sub $version"`;
|
|
xCAT::zvmUtils->printLn( $callback, "$node: $out" );
|
|
|
|
# Refresh services
|
|
$out = `ssh $::SUDOER\@$node "rug ref"`;
|
|
xCAT::zvmUtils->printLn( $callback, "$node: $out" );
|
|
|
|
# Update
|
|
$out = `ssh $::SUDOER\@$node "rug up -y"`;
|
|
xCAT::zvmUtils->printLn( $callback, "$node: $out" );
|
|
} else {
|
|
|
|
# Red Hat Enterprise Linux path - ftp://10.0.0.1/rhel5.4/s390x/Server/
|
|
$path = "http://$nfs/install/$version/s390x/Server/";
|
|
|
|
# Check if file.repo already has this repository location
|
|
$out = `ssh $::SUDOER\@$node "cat /etc/yum.repos.d/file.repo"`;
|
|
if ( $out =~ m/[$version]/i ) {
|
|
|
|
# Send over release key
|
|
my $key = "$installDir/$version/s390x/RPM-GPG-KEY-redhat-release";
|
|
my $tmp = "/tmp/RPM-GPG-KEY-redhat-release";
|
|
xCAT::zvmUtils->sendFile( $::SUDOER, $node, $key, $tmp );
|
|
|
|
# Import key
|
|
$out = `ssh $::SUDOER\@$node "rpm --import /tmp/$key"`;
|
|
|
|
# Upgrade
|
|
$out = `ssh $::SUDOER\@$node "yum upgrade -y"`;
|
|
xCAT::zvmUtils->printLn( $callback, "$node: $out" );
|
|
} else {
|
|
|
|
# Create repository
|
|
$out = xCAT::zvmUtils->rExecute($::SUDOER, $node, "echo [$version] >> /etc/yum.repos.d/file.repo");
|
|
$out = xCAT::zvmUtils->rExecute($::SUDOER, $node, "echo baseurl=$path >> /etc/yum.repos.d/file.repo");
|
|
$out = xCAT::zvmUtils->rExecute($::SUDOER, $node, "echo enabled=1 >> /etc/yum.repos.d/file.repo");
|
|
|
|
# Send over release key
|
|
my $key = "$installDir/$version/s390x/RPM-GPG-KEY-redhat-release";
|
|
my $tmp = "/tmp/RPM-GPG-KEY-redhat-release";
|
|
xCAT::zvmUtils->sendFile( $::SUDOER, $node, $key, $tmp );
|
|
|
|
# Import key
|
|
$out = `ssh $::SUDOER\@$node "rpm --import $tmp"`;
|
|
|
|
# Upgrade
|
|
$out = `ssh $::SUDOER\@$node "yum upgrade -y"`;
|
|
xCAT::zvmUtils->printLn( $callback, "$node: $out" );
|
|
}
|
|
}
|
|
}
|
|
|
|
# Otherwise, print out error
|
|
else {
|
|
$out = "$node: (Error) Option not supported";
|
|
}
|
|
|
|
xCAT::zvmUtils->printLn( $callback, "$out" );
|
|
return;
|
|
}
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 listTree
|
|
|
|
Description : Show the nodes hierarchy tree
|
|
Arguments : Node range (zHCP)
|
|
Returns : Nothing
|
|
Example : listHierarchy($callback, $nodes, $args);
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
sub listTree {
|
|
|
|
# Get inputs
|
|
my ( $callback, $nodes, $args ) = @_;
|
|
my @nodes = @$nodes;
|
|
|
|
# Directory where executables are on zHCP
|
|
$::DIR = "/opt/zhcp/bin";
|
|
|
|
# Use sudo or not
|
|
# This looks in the passwd table for a key = sudoer
|
|
($::SUDOER, $::SUDO) = xCAT::zvmUtils->getSudoer();
|
|
|
|
# In order for this command to work, issue under /opt/xcat/bin:
|
|
# ln -s /opt/xcat/bin/xcatclient lstree
|
|
|
|
my %tree;
|
|
my $node;
|
|
my $hcp;
|
|
my $parent;
|
|
my %ssi = {};
|
|
my $found;
|
|
|
|
# Create hierachy structure: CEC -> LPAR -> zVM -> VM
|
|
# Get table
|
|
my $tab = xCAT::Table->new( 'zvm', -create => 1, -autocommit => 0 );
|
|
|
|
# Get CEC entries
|
|
# There should be few of these nodes
|
|
my @entries = $tab->getAllAttribsWhere( "nodetype = 'cec'", 'node', 'parent' );
|
|
foreach (@entries) {
|
|
$node = $_->{'node'};
|
|
|
|
# Make CEC the tree root
|
|
$tree{$node} = {};
|
|
}
|
|
|
|
# Get LPAR entries
|
|
# There should be a couple of these nodes
|
|
@entries = $tab->getAllAttribsWhere( "nodetype = 'lpar'", 'node', 'parent' );
|
|
foreach (@entries) {
|
|
$node = $_->{'node'}; # LPAR
|
|
$parent = $_->{'parent'}; # CEC
|
|
|
|
# Add LPAR branch
|
|
$tree{$parent}{$node} = {};
|
|
}
|
|
|
|
# Get zVM entries
|
|
# There should be a couple of these nodes
|
|
$found = 0;
|
|
@entries = $tab->getAllAttribsWhere( "nodetype = 'zvm'", 'node', 'hcp', 'parent' );
|
|
foreach (@entries) {
|
|
$node = $_->{'node'}; # zVM
|
|
$hcp = $_->{'hcp'}; # zHCP
|
|
$parent = $_->{'parent'}; # LPAR
|
|
|
|
# Find out if this z/VM belongs to an SSI cluster
|
|
$ssi{$node} = xCAT::zvmUtils->querySSI($::SUDOER, $hcp);
|
|
|
|
# Find CEC root based on LPAR
|
|
# CEC -> LPAR
|
|
$found = 0;
|
|
foreach my $cec(sort keys %tree) {
|
|
foreach my $lpar(sort keys %{$tree{$cec}}) {
|
|
if ($lpar eq $parent) {
|
|
# Add LPAR branch
|
|
$tree{$cec}{$parent}{$node} = {};
|
|
$found = 1;
|
|
last;
|
|
}
|
|
|
|
# Handle second level zVM
|
|
foreach my $vm(sort keys %{$tree{$cec}{$lpar}}) {
|
|
if ($vm eq $parent) {
|
|
# Add VM branch
|
|
$tree{$cec}{$lpar}{$parent}{$node} = {};
|
|
$found = 1;
|
|
last;
|
|
}
|
|
} # End of foreach zVM
|
|
} # End of foreach LPAR
|
|
|
|
# Exit loop if LPAR branch added
|
|
if ($found) {
|
|
last;
|
|
}
|
|
} # End of foreach CEC
|
|
}
|
|
|
|
# Get VM entries
|
|
# There should be many of these nodes
|
|
$found = 0;
|
|
@entries = $tab->getAllAttribsWhere( "nodetype = 'vm'", 'node', 'parent', 'userid' );
|
|
foreach (@entries) {
|
|
$node = $_->{'node'}; # VM
|
|
$parent = $_->{'parent'}; # zVM
|
|
|
|
# Skip node if it is not in noderange
|
|
if (!xCAT::zvmUtils->inArray($node, @nodes)) {
|
|
next;
|
|
}
|
|
|
|
# Find CEC/LPAR root based on zVM
|
|
# CEC -> LPAR -> zVM
|
|
$found = 0;
|
|
foreach my $cec(sort keys %tree) {
|
|
foreach my $lpar(sort keys %{$tree{$cec}}) {
|
|
foreach my $zvm(sort keys %{$tree{$cec}{$lpar}}) {
|
|
if ($zvm eq $parent) {
|
|
# Add zVM branch
|
|
$tree{$cec}{$lpar}{$parent}{$node} = $_->{'userid'};
|
|
$found = 1;
|
|
last;
|
|
}
|
|
|
|
# Handle second level zVM
|
|
foreach my $vm(sort keys %{$tree{$cec}{$lpar}{$zvm}}) {
|
|
if ($vm eq $parent) {
|
|
# Add VM branch
|
|
$tree{$cec}{$lpar}{$zvm}{$parent}{$node} = $_->{'userid'};
|
|
$found = 1;
|
|
last;
|
|
}
|
|
} # End of foreach VM
|
|
} # End of foreach zVM
|
|
|
|
# Exit loop if zVM branch added
|
|
if ($found) {
|
|
last;
|
|
}
|
|
} # End of foreach LPAR
|
|
|
|
# Exit loop if zVM branch added
|
|
if ($found) {
|
|
last;
|
|
}
|
|
} # End of foreach CEC
|
|
} # End of foreach VM node
|
|
|
|
# Print tree
|
|
# Loop through CECs
|
|
foreach my $cec(sort keys %tree) {
|
|
xCAT::zvmUtils->printLn( $callback, "CEC: $cec" );
|
|
|
|
# Loop through LPARs
|
|
foreach my $lpar(sort keys %{$tree{$cec}}) {
|
|
xCAT::zvmUtils->printLn( $callback, "|__LPAR: $lpar" );
|
|
|
|
# Loop through zVMs
|
|
foreach my $zvm(sort keys %{$tree{$cec}{$lpar}}) {
|
|
if ($ssi{$zvm}) {
|
|
xCAT::zvmUtils->printLn( $callback, " |__zVM: $zvm ($ssi{$zvm})" );
|
|
} else {
|
|
xCAT::zvmUtils->printLn( $callback, " |__zVM: $zvm" );
|
|
}
|
|
|
|
# Loop through VMs
|
|
foreach my $vm(sort keys %{$tree{$cec}{$lpar}{$zvm}}) {
|
|
# Handle second level zVM
|
|
if (ref($tree{$cec}{$lpar}{$zvm}{$vm}) eq 'HASH') {
|
|
if ($ssi{$zvm}) {
|
|
xCAT::zvmUtils->printLn( $callback, " |__zVM: $vm ($ssi{$zvm})" );
|
|
} else {
|
|
xCAT::zvmUtils->printLn( $callback, " |__zVM: $vm" );
|
|
}
|
|
|
|
foreach my $vm2(sort keys %{$tree{$cec}{$lpar}{$zvm}{$vm}}) {
|
|
xCAT::zvmUtils->printLn( $callback, " |__VM: $vm2 ($tree{$cec}{$lpar}{$zvm}{$vm}{$vm2})" );
|
|
}
|
|
} else {
|
|
xCAT::zvmUtils->printLn( $callback, " |__VM: $vm ($tree{$cec}{$lpar}{$zvm}{$vm})" );
|
|
}
|
|
} # End of foreach VM
|
|
} # End of foreach zVM
|
|
} # End of foreach LPAR
|
|
} # End of foreach CEC
|
|
return;
|
|
}
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 changeHypervisor
|
|
|
|
Description : Configure the virtualization hosts
|
|
Arguments : Node
|
|
Arguments
|
|
Returns : Nothing
|
|
Example : changeHypervisor($callback, $node, $args);
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
sub changeHypervisor {
|
|
|
|
# Get inputs
|
|
my ( $callback, $node, $args ) = @_;
|
|
|
|
# Get node properties from 'zvm' table
|
|
my @propNames = ( 'hcp' );
|
|
my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
|
|
|
|
# Get zHCP
|
|
my $hcp = $propVals->{'hcp'};
|
|
if ( !$hcp ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing node HCP" );
|
|
return;
|
|
}
|
|
|
|
# Get zHCP shortname because $hcp could be zhcp.endicott.ibm.com
|
|
my $hcpNode = $hcp;
|
|
if ($hcp =~ /./) {
|
|
my @tmp = split(/\./, $hcp);
|
|
$hcpNode = $tmp[0]; # Short hostname of zHCP
|
|
}
|
|
|
|
# Get zHCP user ID
|
|
my $hcpUserId = xCAT::zvmCPUtils->getUserId($::SUDOER, $hcp);
|
|
$hcpUserId =~ tr/a-z/A-Z/;
|
|
|
|
xCAT::zvmUtils->printSyslog("sudoer:$::SUDOER zHCP:$hcp sudo:$::SUDO");
|
|
|
|
# Output string
|
|
my $out = "";
|
|
|
|
# adddisk2pool [function] [region] [volume] [group]
|
|
if ( $args->[0] eq "--adddisk2pool" ) {
|
|
my $funct = $args->[1];
|
|
my $region = $args->[2];
|
|
my $volume = "";
|
|
my $group = "";
|
|
|
|
# Create an array for regions
|
|
my @regions;
|
|
if ( $region =~ m/,/i ) {
|
|
@regions = split( ',', $region );
|
|
} else {
|
|
push( @regions, $region );
|
|
}
|
|
|
|
my $tmp;
|
|
foreach (@regions) {
|
|
$_ = xCAT::zvmUtils->trimStr($_);
|
|
|
|
# Define region as full volume and add to group
|
|
if ($funct eq "4") {
|
|
$volume = $args->[3];
|
|
# In case multiple regions/volumes are specified, just use the same name
|
|
if (scalar(@regions) > 1) {
|
|
$volume = $_;
|
|
}
|
|
|
|
$group = $args->[4];
|
|
$tmp = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Volume_Space_Define_DM -T $hcpUserId -f $funct -g $_ -v $volume -p $group -y 0"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Volume_Space_Define_DM -T $hcpUserId -f $funct -g $_ -v $volume -p $group -y 0");
|
|
}
|
|
|
|
# Add existing region to group
|
|
elsif($funct eq "5") {
|
|
$group = $args->[3];
|
|
$tmp = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Volume_Space_Define_DM -T $hcpUserId -f $funct -g $_ -p $group -y 0"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Volume_Space_Define_DM -T $hcpUserId -f $funct -g $_ -p $group -y 0");
|
|
}
|
|
|
|
$out .= $tmp;
|
|
}
|
|
}
|
|
|
|
# addeckd [dev_no]
|
|
elsif ( $args->[0] eq "--addeckd" ) {
|
|
my $argsSize = @{$args};
|
|
if ($argsSize != 2) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Wrong number of parameters" );
|
|
return;
|
|
}
|
|
|
|
my $devNo = "dev_num=" . $args->[1];
|
|
|
|
# Add an ECKD disk to a running z/VM system
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli System_Disk_Add -T $hcpUserId -k $devNo"`;
|
|
xCAT::zvmUtils->printSyslog("smcli System_Disk_Add -T $hcpUserId -k $devNo");
|
|
}
|
|
|
|
# addscsi [dev_no] [dev_path] [option] [persist]
|
|
elsif ( $args->[0] eq "--addscsi" ) {
|
|
# Sample command would look like: chhypervisor zvm62 --addscsi 12A3 "1,0x123,0x100;2,0x123,0x101" 1 NO
|
|
my $argsSize = @{$args};
|
|
if ($argsSize < 3 && $argsSize > 5) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Wrong number of parameters" );
|
|
return;
|
|
}
|
|
|
|
# Option can be: (1) Add new SCSI (default), (2) Add new path, or (3) Delete path
|
|
if ($args->[3] != 1 && $args->[3] !=2 && $args->[3] !=3) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Options can be one of the following:\n (1) Add new SCSI disk (default)\n (2) Add new path to existing disk\n (3) Delete path from existing disk" );
|
|
return;
|
|
}
|
|
|
|
# Persist can be: (YES) SCSI device updated in active and configured system, or (NO) SCSI device updated only in active system
|
|
if ($argsSize > 3 && $args->[4] ne "YES" && $args->[4] ne "NO") {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Persist can be one of the following:\n (YES) SCSI device updated in active and configured system\n (NO) SCSI device updated only in active system" );
|
|
return;
|
|
}
|
|
|
|
my $devNo = "dev_num=" . $args->[1];
|
|
|
|
# Device path array, each device separated by semi-colon
|
|
# e.g. fcp_devno1 fcp_wwpn1 fcp_lun1; fcp_devno2 fcp_wwpn2 fcp_lun2;
|
|
my @fcps;
|
|
if ($args->[2] =~ m/;/i) {
|
|
@fcps = split( ';', $args->[2] );
|
|
} else {
|
|
push( @fcps, $args->[2] );
|
|
}
|
|
|
|
# Append the correct prefix
|
|
my @fields;
|
|
my $pathStr = "";
|
|
foreach (@fcps) {
|
|
@fields = split( ',', $_ );
|
|
$pathStr .= "fcp_dev_num=$fields[0] fcp_wwpn=$fields[1] fcp_lun=$fields[2];";
|
|
}
|
|
|
|
|
|
my $devPath = "dev_path_array='" . $pathStr . "'";
|
|
|
|
my $option = "option=" . $args->[3];
|
|
my $persist = "persist=" . $args->[4];
|
|
|
|
# Add disk to running system
|
|
$out .= `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli System_SCSI_Disk_Add -T $hcpUserId -k $devNo -k $devPath -k $option -k $persist"`;
|
|
xCAT::zvmUtils->printSyslog("smcli System_SCSI_Disk_Add -T $hcpUserId -k $devNo -k $devPath -k $option -k $persist");
|
|
}
|
|
|
|
# addvlan [name] [owner] [type] [transport]
|
|
elsif ( $args->[0] eq "--addvlan" ) {
|
|
my $name = $args->[1];
|
|
my $owner = $args->[2];
|
|
my $type = $args->[3];
|
|
my $transport = $args->[4];
|
|
|
|
my $argsSize = @{$args};
|
|
if ($argsSize != 5) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Wrong number of parameters" );
|
|
return;
|
|
}
|
|
|
|
$out .= `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Virtual_Network_LAN_Create -T $hcpUserId -n $name -o $owner -t $type -p $transport"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Virtual_Network_LAN_Create -T $hcpUserId -n $name -o $owner -t $type -p $transport");
|
|
}
|
|
|
|
# addvswitch [name] [osa_dev_addr] [port_name] [controller] [connect (0, 1, or 2)] [memory_queue] [router] [transport] [vlan_id] [port_type] [update] [gvrp] [native_vlan]
|
|
elsif ( $args->[0] eq "--addvswitch" ) {
|
|
my $i;
|
|
my $argStr = "";
|
|
|
|
my $argsSize = @{$args};
|
|
if ($argsSize < 5) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Wrong number of parameters" );
|
|
return;
|
|
}
|
|
|
|
my @options = ("", "-n", "-r", "-a", "-i", "-c", "-q", "-e", "-t", "-v", "-p", "-u", "-G", "-V");
|
|
foreach $i ( 1 .. $argsSize ) {
|
|
if ( $args->[$i] ) {
|
|
# Prepend options prefix to argument
|
|
$argStr .= "$options[$i] $args->[$i] ";
|
|
}
|
|
}
|
|
|
|
$out .= `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Virtual_Network_Vswitch_Create -T $hcpUserId $argStr"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Virtual_Network_Vswitch_Create -T $hcpUserId $argStr");
|
|
}
|
|
|
|
# addzfcp2pool [pool] [status] [wwpn] [lun] [size] [range (optional)] [owner (optional)]
|
|
elsif ( $args->[0] eq "--addzfcp2pool" ) {
|
|
# zFCP disk pool located on zHCP at /var/opt/zhcp/zfcp/{pool}.conf
|
|
# Entries contain: status,wwpn,lun,size,range,owner,channel,tag
|
|
my $pool = $args->[1];
|
|
my $status = $args->[2];
|
|
my $wwpn = $args->[3];
|
|
my $lun = $args->[4];
|
|
my $size = $args->[5];
|
|
|
|
my $argsSize = @{$args};
|
|
if ($argsSize < 6 || $argsSize > 8) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Wrong number of parameters" );
|
|
return;
|
|
}
|
|
|
|
# Size can be M(egabytes) or G(igabytes)
|
|
if ($size =~ m/G/i || $size =~ m/M/i || !$size) {
|
|
# Do nothing
|
|
} else {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Size not recognized. Size can be M(egabytes) or G(igabytes).");
|
|
return;
|
|
}
|
|
|
|
# Status can be free/used/reserved
|
|
chomp($status);
|
|
if ($status !~ m/^(free|used|reserved)$/i) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Status not recognized. Status can be free, used, or reserved.");
|
|
return;
|
|
}
|
|
|
|
# Make sure WWPN and LUN do not have 0x prefix
|
|
$wwpn = xCAT::zvmUtils->replaceStr($wwpn, '"', ""); # Strip off enclosing quotes
|
|
$wwpn = xCAT::zvmUtils->replaceStr($wwpn, "0x", "");
|
|
$lun = xCAT::zvmUtils->replaceStr($lun, "0x", "");
|
|
if ($wwpn =~ /[^0-9a-f;"]/i) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Invalid world wide portname $wwpn." );
|
|
return;
|
|
}
|
|
if ($lun =~ /[^0-9a-f]/i) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Invalid logical unit number $lun." );
|
|
return;
|
|
}
|
|
|
|
# You cannot have a unique SCSI/FCP device in multiple pools
|
|
my @pools = split("\n", `ssh $::SUDOER\@$hcp "$::SUDO grep -i -l \",$wwpn,$lun\" $::ZFCPPOOL/*.conf"`);
|
|
if (scalar(@pools)) {
|
|
foreach (@pools) {
|
|
my $otherPool = basename($_);
|
|
$otherPool =~ s/\.[^.]+$//; # Do not use extension
|
|
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) zFCP device $wwpn/$lun already exists in $otherPool." );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
# Optional parameters
|
|
my $range = "";
|
|
my $owner = "";
|
|
if ($argsSize > 6) {
|
|
$range = $args->[6];
|
|
} if ($argsSize > 7) {
|
|
$owner = $args->[7];
|
|
}
|
|
|
|
# Verify syntax of FCP channel range
|
|
if ($range =~ /[^0-9a-f\-;]/i) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Invalid FCP device range. An acceptable range can be specified as 1A80-1B90 or 1A80-1B90;2A80-2B90." );
|
|
return;
|
|
}
|
|
|
|
# Owner must be specified if status is used
|
|
if ($status =~ m/used/i && !$owner) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Owner must be specified if status is used." );
|
|
return;
|
|
}
|
|
|
|
# Find disk pool (create one if non-existent)
|
|
if (!(`ssh $::SUDOER\@$hcp "$::SUDO test -d $::ZFCPPOOL && echo Exists"`)) {
|
|
# Create pool directory
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO mkdir -p $::ZFCPPOOL"`;
|
|
}
|
|
|
|
# Change the file owner if using a sudoer
|
|
if ($::SUDOER ne "root") {
|
|
my $priv = xCAT::zvmUtils->trimStr(`ssh $::SUDOER\@$hcp "$::SUDO /usr/bin/stat -c \"%G:%U\" /var/opt/zhcp"`);
|
|
if (!($priv =~ m/$::SUDOER:users/i)) {
|
|
`ssh $::SUDOER\@$hcp "$::SUDO chown -R $::SUDOER:users /var/opt/zhcp"`;
|
|
}
|
|
}
|
|
|
|
if (!(`ssh $::SUDOER\@$hcp "$::SUDO test -e $::ZFCPPOOL/$pool.conf && echo Exists"`)) {
|
|
# Create pool configuration file
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO echo '#status,wwpn,lun,size,range,owner,channel,tag' > $::ZFCPPOOL/$pool.conf"`;
|
|
xCAT::zvmUtils->printLn( $callback, "$node: New zFCP device pool $pool created" );
|
|
}
|
|
|
|
# Update file with given WWPN, LUN, size, and owner
|
|
my $entry = "'" . "$status,$wwpn,$lun,$size,$range,$owner,," . "'";
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO echo $entry >> $::ZFCPPOOL/$pool.conf"`;
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Adding zFCP device to $pool pool... Done" );
|
|
$out = "";
|
|
}
|
|
|
|
# copyzfcp [device address (or auto)] [source wwpn] [source lun] [target wwpn (optional)] [target lun (option)]
|
|
elsif ( $args->[0] eq "--copyzfcp" ) {
|
|
my $fcpDevice = $args->[1];
|
|
my $srcWwpn = $args->[2];
|
|
my $srcLun = $args->[3];
|
|
|
|
my $argsSize = @{$args};
|
|
if ($argsSize != 4 && $argsSize != 6) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Wrong number of parameters" );
|
|
return;
|
|
}
|
|
|
|
# Check if WWPN and LUN are given
|
|
my $useWwpnLun = 0;
|
|
my $tgtWwpn;
|
|
my $tgtLun;
|
|
if ($argsSize == 6) {
|
|
$useWwpnLun = 1;
|
|
$tgtWwpn = $args->[4];
|
|
$tgtLun = $args->[5];
|
|
|
|
# Make sure WWPN and LUN do not have 0x prefix
|
|
$tgtWwpn = xCAT::zvmUtils->replaceStr($tgtWwpn, "0x", "");
|
|
$tgtLun = xCAT::zvmUtils->replaceStr($tgtLun, "0x", "");
|
|
}
|
|
|
|
# Find the pool that contains the SCSI/FCP device
|
|
my $pool = xCAT::zvmUtils->findzFcpDevicePool($::SUDOER, $hcp, $srcWwpn, $srcLun);
|
|
if (!$pool) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Failed to find FCP device in any zFCP storage pool" );
|
|
return;
|
|
} else {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Found FCP device in $pool" );
|
|
}
|
|
|
|
# Get source device's attributes
|
|
my $srcDiskRef = xCAT::zvmUtils->findzFcpDeviceAttr($::SUDOER, $hcp, $pool, $srcWwpn, $srcLun);
|
|
my %srcDisk = %$srcDiskRef;
|
|
if (!defined($srcDisk{'lun'}) && !$srcDisk{'lun'}) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Source zFCP device $srcWwpn/$srcLun does not exists" );
|
|
return;
|
|
}
|
|
my $srcSize = $srcDisk{'size'};
|
|
|
|
# If target disk is specified, check whether it is large enough
|
|
my $tgtSize;
|
|
if ($useWwpnLun) {
|
|
my $tgtDiskRef = xCAT::zvmUtils->findzFcpDeviceAttr($::SUDOER, $hcp, $pool, $tgtWwpn, $tgtLun);
|
|
my %tgtDisk = %$tgtDiskRef;
|
|
if (!defined($tgtDisk{'lun'}) && !$tgtDisk{'lun'}) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Target zFCP device $tgtWwpn/$tgtLun does not exists" );
|
|
return;
|
|
}
|
|
$tgtSize = $tgtDisk{'size'};
|
|
|
|
# Convert size unit to M for comparision
|
|
if ($srcSize =~ m/G/i) {
|
|
$srcSize =~ s/\D//g;
|
|
$srcSize = int($srcSize) * 1024
|
|
}
|
|
if ($tgtSize =~ m/G/i) {
|
|
$tgtSize =~ s/\D//g;
|
|
$tgtSize = int($srcSize) * 1024
|
|
}
|
|
|
|
if ($tgtSize < $srcSize) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Target zFCP device $tgtWwpn/$tgtLun is not large enough" );
|
|
return;
|
|
}
|
|
}
|
|
|
|
# Attach source disk to zHCP
|
|
$out = `/opt/xcat/bin/chvm $hcpNode --addzfcp $pool $fcpDevice 0 $srcSize "" $srcWwpn $srcLun | sed 1d`;
|
|
if ($out !~ /Done/) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Source zFCP device $srcWwpn/$srcLun cannot be attached");
|
|
return;
|
|
}
|
|
|
|
# Obtain source FCP channel
|
|
$out =~ /Adding zFCP device ([0-9a-f]*)\/([0-9a-f]*)\/([0-9a-f]*).*/;
|
|
my $srcFcpDevice = lc($1);
|
|
|
|
# Attach target disk to zHCP
|
|
my $isTgtAttached = 0;
|
|
if ($useWwpnLun) {
|
|
$out = `/opt/xcat/bin/chvm $hcpNode --addzfcp $pool $fcpDevice 0 $tgtSize "" $tgtWwpn $tgtLun | sed 1d`;
|
|
if ($out !~ /Done/) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Target zFCP device $tgtWwpn/$tgtLun cannot be attached");
|
|
} else {
|
|
$isTgtAttached = 1;
|
|
}
|
|
} else {
|
|
# Try to obtain a target disk automatically if target disk is not specified
|
|
$out = `/opt/xcat/bin/chvm $hcpNode --addzfcp $pool $fcpDevice 0 $srcSize | sed 1d`;
|
|
if ($out !~ /Done/) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Cannot find a suitable target zFCP device");
|
|
} else {
|
|
$isTgtAttached = 1;
|
|
}
|
|
}
|
|
|
|
# Obtain target disk FCP channel, WWPN, and LUN
|
|
$out =~ /Adding zFCP device ([0-9a-f]*)\/([0-9a-f]*)\/([0-9a-f]*).*/;
|
|
my $tgtFcpDevice = lc($1);
|
|
$tgtWwpn = lc($2);
|
|
$tgtLun = lc($3);
|
|
|
|
if (!$isTgtAttached) {
|
|
# Release source disk from zHCP
|
|
$out = `/opt/xcat/bin/chvm $hcpNode --removezfcp $fcpDevice $srcWwpn $srcLun 0`;
|
|
return;
|
|
}
|
|
|
|
# Get device node of source disk and target disk
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /usr/bin/readlink /dev/disk/by-path/ccw-0.0.$srcFcpDevice-zfcp-0x$srcWwpn:0x$srcLun"`;
|
|
chomp($out);
|
|
my @srcDiskInfo = split('/', $out);
|
|
my $srcDiskNode = pop(@srcDiskInfo);
|
|
chomp($out);
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Device name of $tgtFcpDevice/$srcWwpn/$srcLun is $srcDiskNode");
|
|
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /usr/bin/readlink /dev/disk/by-path/ccw-0.0.$tgtFcpDevice-zfcp-0x$tgtWwpn:0x$tgtLun"`;
|
|
chomp($out);
|
|
my @tgtDiskInfo = split('/', $out);
|
|
my $tgtDiskNode = pop(@tgtDiskInfo);
|
|
chomp($tgtDiskNode);
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Device name of $tgtFcpDevice/$tgtWwpn/$tgtLun is $tgtDiskNode");
|
|
|
|
my $presist = 0;
|
|
my $rc = "Failed";
|
|
if (!$srcDiskNode || !$tgtDiskNode) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Could not find device nodes for source or target disk.");
|
|
} else {
|
|
# Copy source disk to target disk (512 block size)
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Copying source disk ($srcDiskNode) to target disk ($tgtDiskNode)" );
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /bin/dd if=/dev/$srcDiskNode of=/dev/$tgtDiskNode bs=512 oflag=sync && $::SUDO echo $?"`;
|
|
$out = xCAT::zvmUtils->trimStr($out);
|
|
if (int($out) != 0) {
|
|
# If $? is not 0 then there was an error during Linux dd
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Failed to copy /dev/$srcDiskNode");
|
|
}
|
|
|
|
$presist = 1; # Keep target device as reserved
|
|
$rc = "Done";
|
|
|
|
# Sleep 2 seconds to let the system settle
|
|
sleep(2);
|
|
}
|
|
|
|
# Detatch source and target disks
|
|
xCAT::zvmUtils->printLn($callback, "$node: Detatching source and target disks");
|
|
$out = `/opt/xcat/bin/chvm $hcpNode --removezfcp $srcFcpDevice $srcWwpn $srcLun $presist`;
|
|
$out = `/opt/xcat/bin/chvm $hcpNode --removezfcp $tgtFcpDevice $tgtWwpn $tgtLun $presist`;
|
|
|
|
# Restore original source device attributes
|
|
my %criteria = (
|
|
'status' => $srcDisk{'status'},
|
|
'wwpn' => $srcDisk{'wwpn'},
|
|
'lun' => $srcDisk{'lun'},
|
|
'size' => $srcDisk{'size'},
|
|
'range' => $srcDisk{'range'},
|
|
'owner' => $srcDisk{'owner'},
|
|
'fcp' => $srcDisk{'fcp'},
|
|
'tag' => $srcDisk{'tag'}
|
|
);
|
|
my $resultsRef = xCAT::zvmUtils->findAndUpdatezFcpPool($callback, $node, $::SUDOER, $hcp, $pool, \%criteria);
|
|
my %results = %$resultsRef;
|
|
if ($results{'rc'} == -1) {
|
|
# Unable to reserve the volume and FCP channel
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Source disk attributes cannot be restored in table");
|
|
}
|
|
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Copying zFCP device... $rc");
|
|
if ($rc eq "Done") {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Source disk copied onto zFCP device $tgtWwpn/$tgtLun");
|
|
}
|
|
$out = "";
|
|
}
|
|
|
|
# capturezfcp [profile] [wwpn] [lun]
|
|
elsif ( $args->[0] eq "--capturezfcp" ) {
|
|
my $profile = $args->[1];
|
|
my $wwpn = $args->[2];
|
|
my $lun = $args->[3];
|
|
|
|
# Verify required properties are defined
|
|
if (!defined($profile) || !defined($wwpn) || !defined($lun)) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing one or more of the required parameters: profile, wwpn, or lun" );
|
|
return;
|
|
}
|
|
|
|
# Make sure WWPN and LUN do not have 0x prefix
|
|
$wwpn = xCAT::zvmUtils->replaceStr($wwpn, "0x", "");
|
|
$lun = xCAT::zvmUtils->replaceStr($lun, "0x", "");
|
|
|
|
# Obtain the location of the install root directory
|
|
my $installRoot = xCAT::TableUtils->getInstallDir();
|
|
|
|
xCAT::zvmUtils->printSyslog("changeHypervisor() Preparing the staging directory");
|
|
|
|
# Create the staging area location for the image
|
|
my $os = "unknown"; # Since we do not inspect the disk contents nor care
|
|
my $provMethod = "raw";
|
|
my $arch = "s390x";
|
|
my $stagingImgDir = "$installRoot/staging/$os/$arch/$profile";
|
|
|
|
if(-d $stagingImgDir) {
|
|
unlink $stagingImgDir;
|
|
}
|
|
mkpath($stagingImgDir);
|
|
|
|
# Prepare the staging mount point on zHCP, if they need to be established.
|
|
my $remoteStagingDir;
|
|
my $rc = xCAT::zvmUtils->establishMount($callback, $::SUDOER, $::SUDO, $hcp, "$installRoot/staging", "rw", \$remoteStagingDir);
|
|
if ($rc) {
|
|
# Mount failed.
|
|
rmtree "$stagingImgDir";
|
|
return;
|
|
}
|
|
|
|
# Find the pool that contains the SCSI/FCP device
|
|
my $pool = xCAT::zvmUtils->findzFcpDevicePool($::SUDOER, $hcp, $wwpn, $lun);
|
|
if (!$pool) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Failed to find FCP device in any zFCP storage pool");
|
|
return;
|
|
} else {
|
|
xCAT::zvmUtils->printLn($callback, "$node: Found FCP device in $pool");
|
|
}
|
|
|
|
# Get source device's attributes
|
|
my $srcDiskRef = xCAT::zvmUtils->findzFcpDeviceAttr($::SUDOER, $hcp, $pool, $wwpn, $lun);
|
|
my %srcDisk = %$srcDiskRef;
|
|
if (!defined($srcDisk{'lun'}) && !$srcDisk{'lun'}) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Source zFCP device $wwpn/$lun does not exists");
|
|
return;
|
|
}
|
|
|
|
# Reserve the volume and associated FCP channel for the zHCP node
|
|
my %criteria = (
|
|
'status' => 'used',
|
|
'fcp' => 'auto',
|
|
'wwpn' => $wwpn,
|
|
'lun' => $lun,
|
|
'owner' => $hcpNode
|
|
);
|
|
my $resultsRef = xCAT::zvmUtils->findAndUpdatezFcpPool($callback, $node, $::SUDOER, $hcp, $pool, \%criteria);
|
|
my %results = %$resultsRef;
|
|
|
|
my $device = $results{'fcp'};
|
|
$wwpn = $results{'wwpn'};
|
|
$lun = $results{'lun'};
|
|
|
|
if ($results{'rc'} == -1) {
|
|
# Unable to reserve the volume and FCP channel
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) zFCP device cannot be reserved");
|
|
rmtree "$stagingImgDir";
|
|
return;
|
|
}
|
|
|
|
xCAT::zvmUtils->printLn($callback, "$node: Capturing volume using zHCP node");
|
|
|
|
# Drive the capture on the zHCP node
|
|
xCAT::zvmUtils->printSyslog("changeHypervisor() creatediskimage $device 0x$wwpn/0x$lun $remoteStagingDir/$os/$arch/$profile/0x${wwpn}_0x${lun}.img");
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/creatediskimage $device 0x$wwpn 0x$lun $remoteStagingDir/$os/$arch/$profile/${wwpn}_${lun}.img"`;
|
|
$rc = $?;
|
|
|
|
# Check for capture errors
|
|
my $reasonString = "";
|
|
$rc = xCAT::zvmUtils->checkOutputExtractReason($callback, $out, \$reasonString);
|
|
if ($rc != 0) {
|
|
my $reason = "Reason: $reasonString";
|
|
xCAT::zvmUtils->printSyslog("changeHypervisor() creatediskimage of volume 0x$wwpn/0x$lun failed. $reason");
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Image capture of volume 0x$wwpn/0x$lun failed on the zHCP node. $reason");
|
|
rmtree "$stagingImgDir" ;
|
|
return;
|
|
}
|
|
|
|
# Restore original source device attributes
|
|
my %criteria = (
|
|
'status' => $srcDisk{'status'},
|
|
'wwpn' => $srcDisk{'wwpn'},
|
|
'lun' => $srcDisk{'lun'},
|
|
'size' => $srcDisk{'size'},
|
|
'range' => $srcDisk{'range'},
|
|
'owner' => $srcDisk{'owner'},
|
|
'fcp' => $srcDisk{'fcp'},
|
|
'tag' => $srcDisk{'tag'}
|
|
);
|
|
my $resultsRef = xCAT::zvmUtils->findAndUpdatezFcpPool($callback, $node, $::SUDOER, $hcp, $pool, \%criteria);
|
|
my %results = %$resultsRef;
|
|
if ($results{'rc'} == -1) {
|
|
# Unable to reserve the volume and FCP channel
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Source disk attributes cannot be restored in table");
|
|
}
|
|
|
|
my $imageName = "$os-$arch-$provMethod-$profile";
|
|
my $deployImgDir = "$installRoot/$provMethod/$os/$arch/$profile";
|
|
|
|
xCAT::zvmUtils->printLn($callback, "$node: Moving the image files to the deployable directory: $deployImgDir");
|
|
|
|
# Move the image directory to the deploy directory
|
|
mkpath($deployImgDir);
|
|
|
|
my @stagedFiles = glob "$stagingImgDir/*";
|
|
foreach my $oldFile (@stagedFiles) {
|
|
move($oldFile, $deployImgDir) or die "$node: (Error) Could not move $oldFile to $deployImgDir: $!\n";
|
|
}
|
|
|
|
# Remove the staging directory
|
|
rmtree "$stagingImgDir" ;
|
|
|
|
xCAT::zvmUtils->printSyslog("changeHypervisor() Updating the osimage table");
|
|
|
|
my $osTab = xCAT::Table->new('osimage',-create => 1,-autocommit => 0);
|
|
my %keyHash;
|
|
|
|
unless ($osTab) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Unable to open table 'osimage'");
|
|
return 0;
|
|
}
|
|
|
|
$keyHash{provmethod} = $provMethod;
|
|
$keyHash{profile} = $profile;
|
|
$keyHash{osvers} = $os;
|
|
$keyHash{osarch} = $arch;
|
|
$keyHash{imagetype} = 'linux';
|
|
$keyHash{imagename} = $imageName;
|
|
|
|
$osTab->setAttribs({imagename => $imageName }, \%keyHash);
|
|
$osTab->commit;
|
|
|
|
xCAT::zvmUtils->printSyslog("changeHypervisor() Updating the linuximage table");
|
|
|
|
my $linuxTab = xCAT::Table->new('linuximage',-create => 1,-autocommit => 0);
|
|
|
|
%keyHash = ();
|
|
$keyHash{imagename} = $imageName;
|
|
$keyHash{rootimgdir} = $deployImgDir;
|
|
|
|
$linuxTab->setAttribs({imagename => $imageName }, \%keyHash );
|
|
$linuxTab->commit;
|
|
|
|
xCAT::zvmUtils->printLn($callback, "$node: Completed capturing the volume. Image($imageName) is stored at $deployImgDir");
|
|
$out = "";
|
|
}
|
|
|
|
# deployzfcp [imageName] [wwpn] [lun]
|
|
elsif ( $args->[0] eq "--deployzfcp" ) {
|
|
my $imageName = $args->[1];
|
|
my $wwpn = $args->[2];
|
|
my $lun = $args->[3];
|
|
|
|
# Verify required properties are defined
|
|
if ( !defined($imageName) || !defined($wwpn) || !defined($lun)) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Missing one or more arguments: image name, wwpn, or lun");
|
|
return;
|
|
}
|
|
|
|
# Make sure WWPN and LUN do not have 0x prefix
|
|
$wwpn = xCAT::zvmUtils->replaceStr($wwpn, "0x", "");
|
|
$lun = xCAT::zvmUtils->replaceStr($lun, "0x", "");
|
|
|
|
# Obtain the location of the install root directory
|
|
my $installRoot = xCAT::TableUtils->getInstallDir();
|
|
|
|
# Build the image location from the image name
|
|
my @nameParts = split('-', $imageName);
|
|
if (!defined $nameParts[3]) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) The image name is not valid");
|
|
return;
|
|
}
|
|
my $profile = $nameParts[3];
|
|
my $os = "unknown";
|
|
my $provMethod = "raw";
|
|
my $arch = "s390x";
|
|
|
|
my $deployImgDir = "$installRoot/$provMethod/$os/$arch/$profile";
|
|
|
|
# Find the image filename.
|
|
my $imageFile;
|
|
my @imageFiles = glob "$deployImgDir/*.img";
|
|
if (@imageFiles == 0) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) $deployImgDir does not contain image files");
|
|
return;
|
|
} elsif (@imageFiles > 1) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) $deployImgDir contains more than the expected number of image files");
|
|
return;
|
|
} else {
|
|
$imageFile = (split( '/', $imageFiles[0]))[-1];
|
|
}
|
|
|
|
# Prepare the deployable netboot mount point on zHCP, if they need to be established.
|
|
my $remoteDeployDir;
|
|
my $rc = xCAT::zvmUtils->establishMount($callback, $::SUDOER, $::SUDO, $hcp, "$installRoot/$provMethod", "ro", \$remoteDeployDir);
|
|
if ($rc) {
|
|
# Mount failed.
|
|
return;
|
|
}
|
|
|
|
# Find the pool that contains the SCSI/FCP device
|
|
my $pool = xCAT::zvmUtils->findzFcpDevicePool($::SUDOER, $hcp, $wwpn, $lun);
|
|
if (!$pool) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Failed to find FCP device in any zFCP storage pool");
|
|
return;
|
|
} else {
|
|
xCAT::zvmUtils->printLn($callback, "$node: Found FCP device in $pool");
|
|
}
|
|
|
|
# Reserve the volume and associated FCP channel for the zHCP node.
|
|
my %criteria = (
|
|
'status' => 'used',
|
|
'fcp' => 'auto',
|
|
'wwpn' => $wwpn,
|
|
'lun' => $lun,
|
|
'owner' => $hcpNode
|
|
);
|
|
my $resultsRef = xCAT::zvmUtils->findAndUpdatezFcpPool($callback, $node, $::SUDOER, $hcp, $pool, \%criteria);
|
|
my %results = %$resultsRef;
|
|
|
|
# Obtain the device assigned by xCAT
|
|
my $device = $results{'fcp'};
|
|
$wwpn = $results{'wwpn'};
|
|
$lun = $results{'lun'};
|
|
|
|
if ($results{'rc'} == -1) {
|
|
# Unable to reserve the volume and FCP channel
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) zFCP device cannot be reserved");
|
|
return;
|
|
}
|
|
|
|
xCAT::zvmUtils->printLn($callback, "$node: Deploying volume using zHCP node");
|
|
|
|
# Drive the deploy on the zHCP node
|
|
xCAT::zvmUtils->printSyslog("changeHypervisor() unpackdiskimage $device 0x$wwpn 0x$lun $remoteDeployDir/$os/$arch/$profile/$imageFile");
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/unpackdiskimage $device 0x$wwpn 0x$lun $remoteDeployDir/$os/$arch/$profile/$imageFile"`;
|
|
$rc = $?;
|
|
|
|
# Release the volume from the zHCP node
|
|
%criteria = (
|
|
'status' => 'reserved',
|
|
'wwpn' => $wwpn,
|
|
'lun' => $lun
|
|
);
|
|
$resultsRef = xCAT::zvmUtils->findAndUpdatezFcpPool($callback, $node, $::SUDOER, $hcp, $pool, \%criteria);
|
|
if ($results{'rc'} == -1) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) zFCP device cannot be released");
|
|
}
|
|
|
|
# Check for deploy errors
|
|
my $reasonString = "";
|
|
$rc = xCAT::zvmUtils->checkOutputExtractReason($callback, $out, \$reasonString);
|
|
if ($rc != 0) {
|
|
my $reason = "Reason: $reasonString";
|
|
xCAT::zvmUtils->printSyslog("changeHypervisor() unpackdiskimage of volume 0x$wwpn/0x$lun failed. $reason");
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Image deploy to volume 0x$wwpn/0x$lun failed on the zHCP node. $reason");
|
|
return;
|
|
}
|
|
|
|
xCAT::zvmUtils->printLn($callback, "$node: Completed deploying image($imageName)");
|
|
$out = "";
|
|
}
|
|
|
|
# removediskfrompool [function] [region] [group]
|
|
elsif ( $args->[0] eq "--removediskfrompool" ) {
|
|
my $funct = $args->[1];
|
|
my $region = $args->[2];
|
|
my $group = "";
|
|
|
|
# Create an array for regions
|
|
my @regions;
|
|
if ( $region =~ m/,/i ) {
|
|
@regions = split( ',', $region );
|
|
} else {
|
|
push( @regions, $region );
|
|
}
|
|
|
|
my $tmp;
|
|
foreach ( @regions ) {
|
|
$_ = xCAT::zvmUtils->trimStr($_);
|
|
|
|
# Remove region from group | Remove entire group
|
|
if ($funct eq "2" || $funct eq "7") {
|
|
$group = $args->[3];
|
|
$tmp = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Volume_Space_Remove_DM -T $hcpUserId -f $funct -r $_ -g $group"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Volume_Space_Remove_DM -T $hcpUserId -f $funct -r $_ -g $group");
|
|
}
|
|
|
|
# Remove region | Remove region from all groups
|
|
elsif ($funct eq "1" || $funct eq "3") {
|
|
$tmp = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Volume_Space_Remove_DM -T $hcpUserId -f $funct -r $_"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Volume_Space_Remove_DM -T $hcpUserId -f $funct -r $_");
|
|
}
|
|
|
|
$out .= $tmp;
|
|
}
|
|
}
|
|
|
|
# removescsi [device number] [persist (YES or NO)]
|
|
elsif ( $args->[0] eq "--removescsi" ) {
|
|
my $argsSize = @{$args};
|
|
if ($argsSize != 3) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Wrong number of parameters" );
|
|
return;
|
|
}
|
|
|
|
my $devNo = "dev_num=" . $args->[1];
|
|
my $persist = "persist=" . $args->[2];
|
|
|
|
# Delete a real SCSI disk
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli System_SCSI_Disk_Delete -T $hcpUserId -k $devNo -k $persist"`;
|
|
xCAT::zvmUtils->printSyslog("smcli System_SCSI_Disk_Delete -T $hcpUserId -k $devNo -k $persist");
|
|
}
|
|
|
|
# removevlan [name] [owner]
|
|
elsif ( $args->[0] eq "--removevlan" ) {
|
|
my $name = $args->[1];
|
|
my $owner = $args->[2];
|
|
|
|
# Delete a virtual network
|
|
$out = `ssh $hcp "$::DIR/smcli Virtual_Network_LAN_Delete -T $hcpUserId -n $name -o $owner"`;
|
|
xCAT::zvmUtils->printSyslog("ssh $hcp $::DIR/smcli Virtual_Network_LAN_Delete -T $hcpUserId -n $name -o $owner");
|
|
}
|
|
|
|
# removevswitch [name]
|
|
elsif ( $args->[0] eq "--removevswitch" ) {
|
|
my $name = $args->[1];
|
|
|
|
# Delete a VSWITCH
|
|
$out = `ssh $hcp "$::DIR/smcli Virtual_Network_Vswitch_Delete -T $hcpUserId -n $name"`;
|
|
xCAT::zvmUtils->printSyslog("ssh $hcp $::DIR/smcli Virtual_Network_Vswitch_Delete -T $hcpUserId -n $name");
|
|
}
|
|
|
|
# removezfcpfrompool [pool] [lun] [wwpn (optional)]
|
|
elsif ( $args->[0] eq "--removezfcpfrompool" ) {
|
|
my $pool = $args->[1];
|
|
my $lun = $args->[2];
|
|
|
|
my $wwpn;
|
|
my $argsSize = @{$args};
|
|
if ($argsSize == 4) {
|
|
$wwpn = $args->[3];
|
|
} elsif ($argsSize > 4) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Wrong number of parameters" );
|
|
return;
|
|
}
|
|
|
|
# Make sure WWPN and LUN do not have 0x prefix
|
|
$wwpn = xCAT::zvmUtils->replaceStr($wwpn, "0x", "");
|
|
$lun = xCAT::zvmUtils->replaceStr($lun, "0x", "");
|
|
|
|
# Verify WWPN and LUN have the correct syntax
|
|
if ($wwpn =~ /[^0-9a-f;"]/i) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Invalid world wide port name $wwpn." );
|
|
return;
|
|
}
|
|
if ($lun =~ /[^0-9a-f,]/i) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Invalid logical unit number $lun." );
|
|
return;
|
|
}
|
|
|
|
my @luns;
|
|
if ($lun =~ m/,/i) {
|
|
@luns = split( ',', $lun );
|
|
} else {
|
|
push(@luns, $lun);
|
|
}
|
|
|
|
# Find disk pool
|
|
if (!(`ssh $::SUDOER\@$hcp "$::SUDO test -e $::ZFCPPOOL/$pool.conf && echo Exists"`)) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) zFCP pool does not exist" );
|
|
return;
|
|
}
|
|
|
|
# Go through each LUN
|
|
my $entry;
|
|
my @args;
|
|
foreach (@luns) {
|
|
# Entry should contain: status, wwpn, lun, size, range, owner, channel, tag
|
|
$entry = xCAT::zvmUtils->trimStr(`ssh $::SUDOER\@$hcp "$::SUDO cat $::ZFCPPOOL/$pool.conf" | egrep -i $_`);
|
|
# Do not update if LUN does not exists
|
|
if (!$entry) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) zFCP device $_ does not exist" );
|
|
return;
|
|
}
|
|
|
|
# Do not update if WWPN/LUN combo does not exists
|
|
@args = split(',', $entry);
|
|
if ($wwpn && !($args[1] =~ m/$wwpn/i)) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) zFCP device $wwpn/$_ does not exists" );
|
|
return;
|
|
}
|
|
|
|
# Update file with given WWPN and LUN
|
|
$entry = "'" . $entry . "'";
|
|
$out = xCAT::zvmUtils->rExecute($::SUDOER, $hcp, "sed -i -e /$entry/d $::ZFCPPOOL/$pool.conf");
|
|
if ($wwpn) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Removing zFCP device $wwpn/$_ from $pool pool... Done" );
|
|
} else {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Removing zFCP device $_ from $pool pool... Done" );
|
|
}
|
|
}
|
|
$out = "";
|
|
}
|
|
|
|
# releasezfcp [pool] [wwpn] [lun]
|
|
elsif ( $args->[0] eq "--releasezfcp" ) {
|
|
my $pool = lc($args->[1]);
|
|
my $wwpn = lc($args->[2]);
|
|
my $lun = lc($args->[3]);
|
|
|
|
my $argsSize = @{$args};
|
|
if ($argsSize != 4) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: (Error) Wrong number of parameters");
|
|
return;
|
|
}
|
|
|
|
my $device = "";
|
|
|
|
# In case multiple LUNs are given, push LUNs into an array to be processed
|
|
my @luns;
|
|
if ($lun =~ m/,/i) {
|
|
@luns = split( ',', $lun );
|
|
} else {
|
|
push(@luns, $lun);
|
|
}
|
|
|
|
# Go through each LUN
|
|
foreach (@luns) {
|
|
my %criteria = (
|
|
'status' => 'free',
|
|
'wwpn' => $wwpn,
|
|
'lun' => $_
|
|
);
|
|
|
|
my $resultsRef = xCAT::zvmUtils->findAndUpdatezFcpPool($callback, $node, $::SUDOER, $hcp, $pool, \%criteria);
|
|
my %results = %$resultsRef;
|
|
if ($results{'rc'} == 0) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: Releasing FCP device... Done");
|
|
xCAT::zvmUtils->printLn($callback, "$node: FCP device 0x$wwpn/0x$_ was released");
|
|
} else {
|
|
xCAT::zvmUtils->printLn($callback, "$node: Releasing FCP device... Failed");
|
|
}
|
|
}
|
|
}
|
|
|
|
# reservezfcp [pool] [status] [owner] [device address (or auto)] [size] [wwpn (optional)] [lun (optional)]
|
|
elsif ( $args->[0] eq "--reservezfcp" ) {
|
|
my $pool = lc($args->[1]);
|
|
my $status = $args->[2];
|
|
my $owner = $args->[3];
|
|
my $device = $args->[4];
|
|
my $size = $args->[5];
|
|
|
|
my $argsSize = @{$args};
|
|
if ($argsSize != 6 && $argsSize != 8) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Wrong number of parameters" );
|
|
return;
|
|
}
|
|
|
|
# Obtain the FCP device, WWPN, and LUN (if any)
|
|
my $wwpn = "";
|
|
my $lun = "";
|
|
if ($argsSize == 8) {
|
|
$wwpn = lc($args->[6]);
|
|
$lun = lc($args->[7]);
|
|
|
|
# Ignore the size if the WWPN and LUN are given
|
|
$size = "";
|
|
}
|
|
|
|
my %criteria;
|
|
my $resultsRef;
|
|
if ($wwpn && $lun) {
|
|
%criteria = (
|
|
'status' => $status,
|
|
'fcp' => $device,
|
|
'wwpn' => $wwpn,
|
|
'lun' => $lun,
|
|
'owner' => $owner
|
|
);
|
|
$resultsRef = xCAT::zvmUtils->findAndUpdatezFcpPool($callback, $node, $::SUDOER, $hcp, $pool, \%criteria);
|
|
} else {
|
|
# Do not know the WWPN or LUN in this case
|
|
%criteria = (
|
|
'status' => $status,
|
|
'fcp' => $device,
|
|
'size' => $size,
|
|
'owner' => $owner
|
|
);
|
|
$resultsRef = xCAT::zvmUtils->findAndUpdatezFcpPool($callback, $node, $::SUDOER, $hcp, $pool, \%criteria);
|
|
}
|
|
|
|
my %results = %$resultsRef;
|
|
|
|
# Obtain the device assigned by xCAT
|
|
$device = $results{'fcp'};
|
|
$wwpn = $results{'wwpn'};
|
|
$lun = $results{'lun'};
|
|
|
|
if ($results{'rc'} == 0) {
|
|
xCAT::zvmUtils->printLn($callback, "$node: Reserving FCP device... Done");
|
|
xCAT::zvmUtils->printLn($callback, "$node: FCP device $device/0x$wwpn/0x$lun was reserved");
|
|
} else {
|
|
xCAT::zvmUtils->printLn($callback, "$node: Reserving FCP device... Failed");
|
|
}
|
|
}
|
|
|
|
# resetsmapi
|
|
elsif ( $args->[0] eq "--resetsmapi" ) {
|
|
# IMPORTANT:
|
|
# This option is only supported for class A privilege!
|
|
# We cannot change it to use SMAPI only because SMAPI cannot be used to restart itself.
|
|
|
|
# Check for VSMGUARD in z/VM 6.2 or newer
|
|
$out = `ssh -o ConnectTimeout=5 $::SUDOER\@$hcp "$::SUDO /sbin/vmcp q users VSMGUARD"`;
|
|
if (!($out =~ m/HCPCQU045E/i)) {
|
|
# Force VSMGUARD and log it back on using XAUTOLOG
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/vmcp force VSMGUARD logoff immediate"`;
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/vmcp xautolog VSMGUARD"`;
|
|
} else {
|
|
# Assuming zVM 6.1 or older
|
|
# Force each worker machine off
|
|
my @workers = ('VSMWORK1', 'VSMWORK2', 'VSMWORK3', 'VSMREQIN', 'VSMREQIU');
|
|
foreach ( @workers ) {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/vmcp force $_ logoff immediate"`;
|
|
}
|
|
|
|
# Log on VSMWORK1
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/vmcp xautolog VSMWORK1"`;
|
|
}
|
|
|
|
$out = "Resetting SMAPI... Done";
|
|
}
|
|
|
|
# smcli [api] [args]
|
|
elsif ( $args->[0] eq "--smcli" ) {
|
|
# Invoke SMAPI API directly through zHCP smcli
|
|
my $str = "@{$args}";
|
|
$str =~ s/$args->[0]//g;
|
|
$str = xCAT::zvmUtils->trimStr($str);
|
|
|
|
# Pass arguments directly to smcli
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli $str"`;
|
|
}
|
|
|
|
# Otherwise, print out error
|
|
else {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Option not supported" );
|
|
}
|
|
|
|
# Only print if there is content
|
|
if ($out) {
|
|
$out = xCAT::zvmUtils->appendHostname( $node, $out );
|
|
chomp($out);
|
|
xCAT::zvmUtils->printLn( $callback, "$out" );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 inventoryHypervisor
|
|
|
|
Description : Get hardware and software inventory of a given hypervisor
|
|
Arguments : Node
|
|
Type of inventory (config|all)
|
|
Returns : Nothing
|
|
Example : inventoryHypervisor($callback, $node, $args);
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
sub inventoryHypervisor {
|
|
|
|
# Get inputs
|
|
my ( $callback, $node, $args ) = @_;
|
|
|
|
# Set cache directory
|
|
my $cache = '/var/opt/zhcp/cache';
|
|
|
|
# Output string
|
|
my $str = "";
|
|
|
|
# Get node properties from 'zvm' table
|
|
my @propNames = ( 'hcp' );
|
|
my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
|
|
|
|
# Get zHCP
|
|
my $hcp = $propVals->{'hcp'};
|
|
if ( !$hcp ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing node zHCP" );
|
|
return;
|
|
}
|
|
|
|
xCAT::zvmUtils->printSyslog("sudoer:$::SUDOER zHCP:$hcp sudo:$::SUDO");
|
|
|
|
# Get the user Id of the zHCP
|
|
my $hcpUserId = xCAT::zvmCPUtils->getUserId($::SUDOER, $hcp);
|
|
|
|
# Load VMCP module
|
|
my $out = `ssh -o ConnectTimeout=5 $::SUDOER\@$hcp "$::SUDO /sbin/modprobe vmcp"`;
|
|
|
|
# Get configuration
|
|
if ( $args->[0] eq 'config' ) {
|
|
# Get total physical CPU in this LPAR
|
|
my $lparCpuTotal = xCAT::zvmUtils->getLparCpuTotal($::SUDOER, $hcp);
|
|
|
|
# Get used physical CPU in this LPAR
|
|
my $lparCpuUsed = xCAT::zvmUtils->getLparCpuUsed($::SUDOER, $hcp);
|
|
|
|
# Get LPAR memory total
|
|
my $lparMemTotal = xCAT::zvmUtils->getLparMemoryTotal($::SUDOER, $hcp);
|
|
|
|
# Get LPAR memory Offline
|
|
my $lparMemOffline = xCAT::zvmUtils->getLparMemoryOffline($::SUDOER, $hcp);
|
|
|
|
# Get LPAR memory Used
|
|
my $lparMemUsed = xCAT::zvmUtils->getLparMemoryUsed($::SUDOER, $hcp);
|
|
|
|
$str .= "z/VM Host: " . uc($node) . "\n";
|
|
$str .= "zHCP: $hcp\n";
|
|
$str .= "LPAR CPU Total: $lparCpuTotal\n";
|
|
$str .= "LPAR CPU Used: $lparCpuUsed\n";
|
|
$str .= "LPAR Memory Total: $lparMemTotal\n";
|
|
$str .= "LPAR Memory Used: $lparMemUsed\n";
|
|
$str .= "LPAR Memory Offline: $lparMemOffline\n";
|
|
} elsif ( $args->[0] eq 'all' ) {
|
|
# Get total physical CPU in this LPAR
|
|
my $lparCpuTotal = xCAT::zvmUtils->getLparCpuTotal($::SUDOER, $hcp);
|
|
|
|
# Get used physical CPU in this LPAR
|
|
my $lparCpuUsed = xCAT::zvmUtils->getLparCpuUsed($::SUDOER, $hcp);
|
|
|
|
# Get CEC model
|
|
my $cecModel = xCAT::zvmUtils->getCecModel($::SUDOER, $hcp);
|
|
|
|
# Get vendor of CEC
|
|
my $cecVendor = xCAT::zvmUtils->getCecVendor($::SUDOER, $hcp);
|
|
|
|
# Get hypervisor type and version
|
|
my $hvInfo = xCAT::zvmUtils->getHypervisorInfo($::SUDOER, $hcp);
|
|
|
|
# Get processor architecture
|
|
my $arch = xCAT::zvmUtils->getArch($::SUDOER, $hcp);
|
|
|
|
# Get hypervisor name
|
|
my $host = xCAT::zvmCPUtils->getHost($::SUDOER, $hcp);
|
|
|
|
# Get LPAR memory total
|
|
my $lparMemTotal = xCAT::zvmUtils->getLparMemoryTotal($::SUDOER, $hcp);
|
|
|
|
# Get LPAR memory Offline
|
|
my $lparMemOffline = xCAT::zvmUtils->getLparMemoryOffline($::SUDOER, $hcp);
|
|
|
|
# Get LPAR memory Used
|
|
my $lparMemUsed = xCAT::zvmUtils->getLparMemoryUsed($::SUDOER, $hcp);
|
|
|
|
# Create output string
|
|
$str .= "z/VM Host: " . uc($node) . "\n";
|
|
$str .= "zHCP: $hcp\n";
|
|
$str .= "Architecture: $arch\n";
|
|
$str .= "CEC Vendor: $cecVendor\n";
|
|
$str .= "CEC Model: $cecModel\n";
|
|
$str .= "Hypervisor OS: $hvInfo\n";
|
|
$str .= "Hypervisor Name: $host\n";
|
|
$str .= "LPAR CPU Total: $lparCpuTotal\n";
|
|
$str .= "LPAR CPU Used: $lparCpuUsed\n";
|
|
$str .= "LPAR Memory Total: $lparMemTotal\n";
|
|
$str .= "LPAR Memory Used: $lparMemUsed\n";
|
|
$str .= "LPAR Memory Offline: $lparMemOffline\n";
|
|
}
|
|
|
|
# diskpoolspace
|
|
elsif ( $args->[0] eq '--diskpoolspace' ) {
|
|
# Check whether disk pool was given
|
|
my @pools;
|
|
if (!$args->[1]) {
|
|
# Get all known disk pool names
|
|
$out = `rinv $node --diskpoolnames`;
|
|
$out =~ s/$node: //g;
|
|
$out = xCAT::zvmUtils->trimStr($out);
|
|
@pools = split('\n', $out);
|
|
} else {
|
|
my $pool = uc($args->[1]);
|
|
push(@pools, $pool);
|
|
|
|
# Check whether disk pool is a valid pool
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Volume_Space_Query_DM -q 1 -e 3 -n $pool -T $hcpUserId" | grep "Failed"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Image_Volume_Space_Query_DM -q 1 -e 3 -n $pool -T $hcpUserId");
|
|
if ($out) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Disk pool $pool does not exist" );
|
|
return;
|
|
}
|
|
}
|
|
|
|
# Go through each pool and find it's space
|
|
foreach(@pools) {
|
|
# Skip empty pool
|
|
if (!$_) {
|
|
next;
|
|
}
|
|
|
|
my $free = xCAT::zvmUtils->getDiskPoolFree($::SUDOER, $hcp, $_);
|
|
my $used = xCAT::zvmUtils->getDiskPoolUsed($::SUDOER, $hcp, $_);
|
|
my $total = $free + $used;
|
|
|
|
# Change the output format from cylinders to 'G' or 'M'
|
|
$total = xCAT::zvmUtils->getSizeFromCyl($total);
|
|
$used = xCAT::zvmUtils->getSizeFromCyl($used);
|
|
$free = xCAT::zvmUtils->getSizeFromCyl($free);
|
|
|
|
$str .= "$_ Total: $total\n";
|
|
$str .= "$_ Used: $used\n";
|
|
$str .= "$_ Free: $free\n";
|
|
}
|
|
}
|
|
|
|
# diskpool [pool] [all|free|used]
|
|
elsif ( $args->[0] eq "--diskpool" ) {
|
|
# Get disk pool configuration
|
|
my $pool = $args->[1];
|
|
my $space = $args->[2];
|
|
|
|
if ($space eq "all" || !$space) {
|
|
$str = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/getdiskpool $hcpUserId $pool free"`;
|
|
|
|
# Delete 1st line which is header
|
|
$str .= `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/getdiskpool $hcpUserId $pool used" | sed 1d`;
|
|
} else {
|
|
$str = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/getdiskpool $hcpUserId $pool $space"`;
|
|
}
|
|
}
|
|
|
|
# diskpoolnames
|
|
elsif ( $args->[0] eq "--diskpoolnames" ) {
|
|
# Get disk pool names
|
|
# If the cache directory does not exist
|
|
if (!(`ssh $::SUDOER\@$hcp "$::SUDO test -d $cache && echo Exists"`)) {
|
|
# Create cache directory
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO mkdir -p $cache"`;
|
|
}
|
|
|
|
my $file = "$cache/diskpoolnames";
|
|
|
|
# If a cache for disk pool names exists
|
|
if (`ssh $::SUDOER\@$hcp "$::SUDO ls $file"`) {
|
|
# Get current Epoch
|
|
my $curTime = time();
|
|
# Get time of last change as seconds since Epoch
|
|
my $fileTime = xCAT::zvmUtils->trimStr(`ssh $::SUDOER\@$hcp "$::SUDO stat -c %Z $file"`);
|
|
|
|
# If the current time is greater than 5 minutes of the file timestamp
|
|
my $interval = 300; # 300 seconds = 5 minutes * 60 seconds/minute
|
|
if ($curTime > $fileTime + $interval) {
|
|
# Get disk pool names and save it in a file
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/getdiskpoolnames $hcpUserId > $file"`;
|
|
}
|
|
} else {
|
|
# Get disk pool names and save it in a file
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/getdiskpoolnames $hcpUserId > $file"`;
|
|
}
|
|
|
|
# Print out the file contents
|
|
$str = `ssh $::SUDOER\@$hcp "$::SUDO cat $file"`;
|
|
}
|
|
|
|
# fcpdevices [active|free|offline] [details (optional)]
|
|
elsif ( $args->[0] eq "--fcpdevices" ) {
|
|
my $argsSize = @{$args};
|
|
my $space = $args->[1];
|
|
my $details = 0;
|
|
if ($argsSize == 3 && $args->[2] eq "details") {
|
|
$details = 1;
|
|
}
|
|
|
|
# Display the status of real FCP Adapter devices using System_WWPN_Query
|
|
my @devices;
|
|
my $i;
|
|
my $devNo;
|
|
my $status;
|
|
if ($space eq "active" || $space eq "free" || $space eq "offline") {
|
|
if ($details) {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli System_WWPN_Query -T $hcpUserId"`;
|
|
xCAT::zvmUtils->printSyslog("smcli System_WWPN_Query -T $hcpUserId");
|
|
|
|
@devices = split( "\n", $out );
|
|
for ($i = 0; $i < @devices; $i++) {
|
|
# Extract the device number and status
|
|
$devNo = $devices[$i];
|
|
$devNo =~ s/^FCP device number:(.*)/$1/;
|
|
$devNo =~ s/^\s+//;
|
|
$devNo =~ s/\s+$//;
|
|
|
|
$status = $devices[$i + 1];
|
|
$status =~ s/^Status:(.*)/$1/;
|
|
$status =~ s/^\s+//;
|
|
$status =~ s/\s+$//;
|
|
|
|
# Only print out devices matching query
|
|
if ($status =~ m/$space/i) {
|
|
$str .= "$devices[$i]\n";
|
|
$str .= "$devices[$i + 1]\n";
|
|
$str .= "$devices[$i + 2]\n";
|
|
$str .= "$devices[$i + 3]\n";
|
|
$str .= "$devices[$i + 4]\n";
|
|
$i = $i + 4;
|
|
}
|
|
}
|
|
} else {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli System_WWPN_Query -T $hcpUserId" | egrep -i "FCP device number|Status"`;
|
|
xCAT::zvmUtils->printSyslog("smcli System_WWPN_Query -T $hcpUserId | egrep -i FCP device number|Status");
|
|
|
|
@devices = split( "\n", $out );
|
|
for ($i = 0; $i < @devices; $i++) {
|
|
# Extract the device number and status
|
|
$devNo = $devices[$i];
|
|
$devNo =~ s/^FCP device number:(.*)/$1/;
|
|
$devNo =~ s/^\s+//;
|
|
$devNo =~ s/\s+$//;
|
|
|
|
$i++;
|
|
$status = $devices[$i];
|
|
$status =~ s/^Status:(.*)/$1/;
|
|
$status =~ s/^\s+//;
|
|
$status =~ s/\s+$//;
|
|
|
|
# Only print out devices matching query
|
|
if ($status =~ m/$space/i) {
|
|
$str .= "$devNo\n";
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Query supported on active, free, or offline devices" );
|
|
}
|
|
}
|
|
|
|
# luns [fcp_device] (supported only on z/VM 6.2)
|
|
elsif ( $args->[0] eq "--luns" ) {
|
|
# Find the LUNs accessible thru given zFCP device
|
|
my $fcp = lc($args->[1]);
|
|
my $argsSize = @{$args};
|
|
if ($argsSize < 2) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Wrong number of parameters" );
|
|
return;
|
|
}
|
|
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli System_FCP_Free_Query -T $hcpUserId -k fcp_dev=$fcp" | egrep -i "FCP device number:|World wide port number:|Logical unit number:|Number of bytes residing on the logical unit:"`;
|
|
xCAT::zvmUtils->printSyslog("smcli System_FCP_Free_Query -T $hcpUserId -k fcp_dev=$fcp | egrep -i FCP device number:|World wide port number:|Logical unit number:|Number of bytes residing on the logical unit:");
|
|
|
|
my @wwpns = split( "\n", $out );
|
|
my %map;
|
|
|
|
my $wwpn = "";
|
|
my $lun = "";
|
|
my $size = "";
|
|
foreach (@wwpns) {
|
|
# Extract the device number
|
|
if ($_ =~ "World wide port number:") {
|
|
$_ =~ s/^\s+World wide port number:(.*)/$1/;
|
|
$_ =~ s/^\s+//;
|
|
$_ =~ s/\s+$//;
|
|
$wwpn = $_;
|
|
|
|
if (!scalar($map{$wwpn})) {
|
|
$map{$wwpn} = {};
|
|
}
|
|
} elsif ($_ =~ "Logical unit number:") {
|
|
$_ =~ s/^\s+Logical unit number:(.*)/$1/;
|
|
$_ =~ s/^\s+//;
|
|
$_ =~ s/\s+$//;
|
|
$lun = $_;
|
|
|
|
$map{$wwpn}{$lun} = "";
|
|
} elsif ($_ =~ "Number of bytes residing on the logical unit:") {
|
|
$_ =~ s/^\s+Number of bytes residing on the logical unit:(.*)/$1/;
|
|
$_ =~ s/^\s+//;
|
|
$_ =~ s/\s+$//;
|
|
$size = $_;
|
|
|
|
$map{$wwpn}{$lun} = $size;
|
|
}
|
|
}
|
|
|
|
xCAT::zvmUtils->printLn($callback, "#status,wwpn,lun,size,range,owner,channel,tag");
|
|
foreach $wwpn (sort keys %map) {
|
|
foreach $lun (sort keys %{$map{$wwpn}}) {
|
|
# status, wwpn, lun, size, range, owner, channel, tag
|
|
$size = sprintf("%.1f", $map{$wwpn}{$lun}/1073741824); # Convert size to GB
|
|
|
|
if ($size > 0) {
|
|
$size .= "G";
|
|
xCAT::zvmUtils->printLn($callback, "unknown,$wwpn,$lun,$size,,,,");
|
|
}
|
|
}
|
|
}
|
|
|
|
$str = "";
|
|
}
|
|
|
|
# networknames
|
|
elsif ( $args->[0] eq "--networknames" || $args->[0] eq "--getnetworknames" ) {
|
|
$str = xCAT::zvmCPUtils->getNetworkNames($::SUDOER, $hcp);
|
|
}
|
|
|
|
# network [name]
|
|
elsif ( $args->[0] eq "--network" || $args->[0] eq "--getnetwork" ) {
|
|
my $netName = $args->[1];
|
|
$str = xCAT::zvmCPUtils->getNetwork( $::SUDOER, $hcp, $netName );
|
|
}
|
|
|
|
# responsedata [failed Id]
|
|
elsif ( $args->[0] eq "--responsedata" ) {
|
|
# This has not be completed!
|
|
my $failedId = $args->[1];
|
|
$str = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Response_Recovery -T $hcpUserId -k $failedId"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Response_Recovery -T $hcpUserId -k $failedId");
|
|
}
|
|
|
|
# freefcp [fcp_dev]
|
|
elsif ( $args->[0] eq "--freefcp" ) {
|
|
my $argsSize = @{$args};
|
|
if ($argsSize != 2) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Wrong number of parameters" );
|
|
return;
|
|
}
|
|
|
|
my $fcp = "fcp_dev=" . $args->[1];
|
|
|
|
$str = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli System_FCP_Free_Query -T $hcpUserId -k $fcp"`;
|
|
xCAT::zvmUtils->printSyslog("smcli System_FCP_Free_Query -T $hcpUserId -k $fcp");
|
|
}
|
|
|
|
# scsidisk [dev_no]
|
|
elsif ( $args->[0] eq "--scsidisk" ) {
|
|
my $argsSize = @{$args};
|
|
if ($argsSize != 2) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Wrong number of parameters" );
|
|
return;
|
|
}
|
|
|
|
my $devNo = "dev_num=" . $args->[1];
|
|
|
|
$str = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli System_SCSI_Disk_Query -T $hcpUserId -k $devNo"`;
|
|
xCAT::zvmUtils->printSyslog("smcli System_SCSI_Disk_Query -T $hcpUserId -k $devNo");
|
|
}
|
|
|
|
# ssi
|
|
elsif ( $args->[0] eq "--ssi" ) {
|
|
$str = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli SSI_Query"`;
|
|
xCAT::zvmUtils->printSyslog("smcli SSI_Query");
|
|
}
|
|
|
|
# smapilevel
|
|
elsif ( $args->[0] eq "--smapilevel" ) {
|
|
$str = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Query_API_Functional_Level -T $hcpUserId"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Query_API_Functional_Level -T $hcpUserId");
|
|
}
|
|
|
|
# systemdisk [dev_no]
|
|
elsif ( $args->[0] eq "--systemdisk" ) {
|
|
my $argsSize = @{$args};
|
|
if ($argsSize != 2) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Wrong number of parameters" );
|
|
return;
|
|
}
|
|
|
|
my $devNo = "dev_num=" . $args->[1];
|
|
|
|
$str = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli System_Disk_Query -T $hcpUserId -k $devNo"`;
|
|
xCAT::zvmUtils->printSyslog("smcli System_Disk_Query -T $hcpUserId -k $devNo");
|
|
}
|
|
|
|
# systemdiskaccessibility [dev_no]
|
|
elsif ( $args->[0] eq "--systemdiskaccessibility" ) {
|
|
my $argsSize = @{$args};
|
|
if ($argsSize != 2) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Wrong number of parameters" );
|
|
return;
|
|
}
|
|
|
|
my $devNo = "dev_num=" . $args->[1];
|
|
|
|
$str = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli System_Disk_Accessibility -T $hcpUserId -k $devNo"`;
|
|
xCAT::zvmUtils->printSyslog("smcli System_Disk_Accessibility -T $hcpUserId -k $devNo");
|
|
}
|
|
|
|
# userprofilenames
|
|
elsif ( $args->[0] eq "--userprofilenames" ) {
|
|
my $argsSize = @{$args};
|
|
if ($argsSize != 1) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Wrong number of parameters" );
|
|
return;
|
|
}
|
|
|
|
# Use Directory_Manager_Search_DM to find user profiles
|
|
my $tmp = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Directory_Manager_Search_DM -T $hcpUserId -s PROFILE"`;
|
|
my @profiles = split('\n', $tmp);
|
|
foreach (@profiles) {
|
|
# Extract user profile
|
|
if ($_) {
|
|
$_ =~ /([a-zA-Z]*):*/;
|
|
$str .= "$1\n";
|
|
}
|
|
}
|
|
|
|
xCAT::zvmUtils->printSyslog("smcli Directory_Manager_Search_DM -T $hcpUserId -s PROFILE");
|
|
}
|
|
|
|
# vlanstats [vlan_id] [user_id] [device] [version]
|
|
elsif ( $args->[0] eq "--vlanstats" ) {
|
|
# This is not completed!
|
|
my $argsSize = @{$args};
|
|
if ($argsSize < 4 && $argsSize > 5) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Wrong number of parameters" );
|
|
return;
|
|
}
|
|
|
|
my $vlanId = "VLAN_id=" . $args->[1];
|
|
my $tgtUserId = "userid=" . $args->[2];
|
|
my $device = "device=" . $args->[3];
|
|
my $fmtVersion = "fmt_version=" . $args->[4]; # Optional
|
|
|
|
my $argStr = "-k $vlanId -k $tgtUserId -k $device";
|
|
if ($argsSize == 5) {
|
|
$argStr .= " -k $fmtVersion"
|
|
}
|
|
|
|
$str = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Virtual_Network_VLAN_Query_Stats -T $hcpUserId $argStr"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Virtual_Network_VLAN_Query_Stats -T $hcpUserId $argStr");
|
|
}
|
|
|
|
# vswitchstats [name] [version]
|
|
elsif ( $args->[0] eq "--vswitchstats" ) {
|
|
my $argsSize = @{$args};
|
|
if ($argsSize < 2 && $argsSize > 3) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Wrong number of parameters" );
|
|
return;
|
|
}
|
|
|
|
my $switchName = "switch_name=" . $args->[1];
|
|
my $fmtVersion = "fmt_version=" . $args->[2]; # Optional
|
|
my $argStr = "-k $switchName";
|
|
|
|
if ($argsSize == 3) {
|
|
$argStr .= " -k $fmtVersion"
|
|
}
|
|
|
|
$str = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Virtual_Network_Vswitch_Query_Stats -T $hcpUserId $argStr"`;
|
|
xCAT::zvmUtils->printSyslog("smcli Virtual_Network_Vswitch_Query_Stats -T $hcpUserId $argStr");
|
|
}
|
|
|
|
# wwpn [fcp_device] (supported only on z/VM 6.2)
|
|
elsif ( $args->[0] eq "--wwpns" ) {
|
|
my $fcp = lc($args->[1]);
|
|
my $argsSize = @{$args};
|
|
if ($argsSize < 2) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Wrong number of parameters" );
|
|
return;
|
|
}
|
|
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli System_FCP_Free_Query -T $hcpUserId -k fcp_dev=$fcp" | egrep -i "World wide port number:"`;
|
|
xCAT::zvmUtils->printSyslog("smcli System_FCP_Free_Query -T $hcpUserId -k fcp_dev=$fcp | egrep -i World wide port number:");
|
|
|
|
my @wwpns = split( "\n", $out );
|
|
my %uniqueWwpns;
|
|
foreach (@wwpns) {
|
|
# Extract the device number
|
|
if ($_ =~ "World wide port number:") {
|
|
$_ =~ s/^\s+World wide port number:(.*)/$1/;
|
|
$_ =~ s/^\s+//;
|
|
$_ =~ s/\s+$//;
|
|
|
|
# Save only unique WWPNs
|
|
$uniqueWwpns{$_} = 1;
|
|
}
|
|
}
|
|
|
|
my $wwpn;
|
|
for $wwpn ( keys %uniqueWwpns ) {
|
|
$str .= "$wwpn\n";
|
|
}
|
|
}
|
|
|
|
# zfcppool [pool] [space]
|
|
elsif ( $args->[0] eq "--zfcppool" ) {
|
|
# Get zFCP disk pool configuration
|
|
my $pool = lc($args->[1]);
|
|
my $space = $args->[2];
|
|
|
|
if ($space eq "all" || !$space) {
|
|
$str = `ssh $::SUDOER\@$hcp "$::SUDO cat $::ZFCPPOOL/$pool.conf"`;
|
|
} else {
|
|
$str = "#status,wwpn,lun,size,range,owner,channel,tag\n";
|
|
$str .= `ssh $::SUDOER\@$hcp "$::SUDO cat $::ZFCPPOOL/$pool.conf" | egrep -i $space`;
|
|
}
|
|
}
|
|
|
|
# zfcppoolnames
|
|
elsif ( $args->[0] eq "--zfcppoolnames") {
|
|
# Get zFCP disk pool names
|
|
# Go through each zFCP pool
|
|
my @pools = split("\n", `ssh $::SUDOER\@$hcp "$::SUDO ls $::ZFCPPOOL"`);
|
|
foreach (@pools) {
|
|
$_ = xCAT::zvmUtils->replaceStr( $_, ".conf", "" );
|
|
$str .= "$_\n";
|
|
}
|
|
}
|
|
|
|
else {
|
|
$str = "$node: (Error) Option not supported";
|
|
xCAT::zvmUtils->printLn( $callback, "$str" );
|
|
return;
|
|
}
|
|
|
|
# Append hostname (e.g. pokdev61) in front
|
|
$str = xCAT::zvmUtils->appendHostname( $node, $str );
|
|
|
|
xCAT::zvmUtils->printLn( $callback, "$str" );
|
|
return;
|
|
}
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 migrateVM
|
|
|
|
Description : Migrate a virtual machine
|
|
Arguments : Node
|
|
Destination
|
|
Immediate
|
|
Action (optional)
|
|
Max_total
|
|
Max_quiesce
|
|
Force (optional)
|
|
Returns : Nothing
|
|
Example : migrateVM($callback, $node, $args);
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
sub migrateVM {
|
|
|
|
# Get inputs
|
|
my ( $callback, $node, $args ) = @_;
|
|
|
|
# Get node properties from 'zvm' table
|
|
my @propNames = ( 'hcp', 'userid' );
|
|
my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
|
|
|
|
# Get HCP
|
|
my $hcp = $propVals->{'hcp'};
|
|
if ( !$hcp ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing node HCP" );
|
|
return;
|
|
}
|
|
|
|
# Get node user ID
|
|
my $userId = $propVals->{'userid'};
|
|
if ( !$userId ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing user ID" );
|
|
return;
|
|
}
|
|
# Capitalize user ID
|
|
$userId =~ tr/a-z/A-Z/;
|
|
|
|
xCAT::zvmUtils->printSyslog("sudoer:$::SUDOER zHCP:$hcp sudo:$::SUDO");
|
|
|
|
# Get zHCP user ID
|
|
my $hcpUserId = xCAT::zvmCPUtils->getUserId($::SUDOER, $hcp);
|
|
$hcpUserId =~ tr/a-z/A-Z/;
|
|
|
|
# Check required keys: target_identifier, destination, action, immediate, and max_total
|
|
# Optional keys: max_quiesce, and force
|
|
if (!$args || @{$args} < 4) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Wrong number of parameters" );
|
|
return;
|
|
}
|
|
|
|
# Output string
|
|
my $out;
|
|
my $migrateCmd = "VMRELOCATE -T $userId";
|
|
|
|
my $i;
|
|
my $destination;
|
|
my $action;
|
|
my $value;
|
|
foreach $i ( 0 .. 5 ) {
|
|
if ( $args->[$i] ) {
|
|
# Find destination key
|
|
if ( $args->[$i] =~ m/destination=/i ) {
|
|
$destination = $args->[$i];
|
|
$destination =~ s/destination=//g;
|
|
$destination =~ s/"//g;
|
|
$destination =~ s/'//g;
|
|
} elsif ( $args->[$i] =~ m/action=/i ) {
|
|
$action = $args->[$i];
|
|
$action =~ s/action=//g;
|
|
} elsif ( $args->[$i] =~ m/max_total=/i ) {
|
|
$value = $args->[$i];
|
|
$value =~ s/max_total=//g;
|
|
|
|
# Strip leading zeros
|
|
if (!($value =~ m/[^0-9.]/ )) {
|
|
$value =~ s/^0+//;
|
|
$args->[$i] = "max_total=$value";
|
|
}
|
|
} elsif ( $args->[$i] =~ m/max_quiesce=/i ) {
|
|
$value = $args->[$i];
|
|
$value =~ s/max_quiesce=//g;
|
|
|
|
# Strip leading zeros
|
|
if (!($value =~ m/[^0-9.]/ )) {
|
|
$value =~ s/^0+//;
|
|
$args->[$i] = "max_quiesce=$value";
|
|
}
|
|
}
|
|
|
|
# Keys passed directly to smcli
|
|
$migrateCmd .= " -k $args->[$i]";
|
|
}
|
|
}
|
|
|
|
my $destHcp;
|
|
if ($action =~ m/MOVE/i) {
|
|
# Find the zHCP for the destination host and set the node zHCP as it
|
|
# Otherwise, it is up to the user to manually change the zHCP
|
|
@propNames = ( 'hcp' );
|
|
$propVals = xCAT::zvmUtils->getNodeProps( 'zvm', lc($destination), @propNames );
|
|
$destHcp = $propVals->{'hcp'};
|
|
if ( !$destHcp ) {
|
|
|
|
# Try upper-case
|
|
$propVals = xCAT::zvmUtils->getNodeProps( 'zvm', uc($destination), @propNames );
|
|
$destHcp = $propVals->{'hcp'};
|
|
}
|
|
|
|
if (!$destHcp) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Failed to find zHCP of $destination" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Solution) Set the hcp appropriately in the zvm table" );
|
|
return;
|
|
}
|
|
}
|
|
|
|
# Begin migration
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli $migrateCmd"`;
|
|
xCAT::zvmUtils->printSyslog("smcli $migrateCmd");
|
|
xCAT::zvmUtils->printLn( $callback, "$node: $out" );
|
|
|
|
# Check for errors on migration only
|
|
my $rc = xCAT::zvmUtils->checkOutput( $callback, $out );
|
|
if ( $rc != -1 && $action =~ m/MOVE/i) {
|
|
|
|
# Check the migration status
|
|
my $check = 4;
|
|
my $isMigrated = 0;
|
|
while ($check > 0) {
|
|
$out = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli VMRELOCATE_Status -T $hcpUserId" -k status_target=$userId`;
|
|
xCAT::zvmUtils->printSyslog("smcli VMRELOCATE_Status -T $hcpUserId -k status_target=$userId");
|
|
if ( $out =~ m/No active relocations found/i ) {
|
|
$isMigrated = 1;
|
|
last;
|
|
}
|
|
|
|
$check--;
|
|
sleep(10);
|
|
}
|
|
|
|
# Change the zHCP if migration successful
|
|
if ($isMigrated) {
|
|
`/opt/xcat/bin/nodech $node zvm.hcp=$destHcp zvm.parent=$destination`;
|
|
} else {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Could not determine progress of relocation" );
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 evacuate
|
|
|
|
Description : Evacuate all virtual machines off a hypervisor
|
|
Arguments : Node (hypervisor)
|
|
Returns : Nothing
|
|
Example : evacuate($callback, $node, $args);
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
sub evacuate {
|
|
|
|
# Get inputs, e.g. revacuate pokdev62 poktst62
|
|
my ( $callback, $node, $args ) = @_;
|
|
|
|
# In order for this command to work, issue under /opt/xcat/bin:
|
|
# ln -s /opt/xcat/bin/xcatclient revacuate
|
|
|
|
my $destination = $args->[0];
|
|
if (!$destination) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing z/VM SSI cluster name of the destination system" );
|
|
return;
|
|
}
|
|
|
|
# Get node properties from 'zvm' table
|
|
my @propNames = ( 'hcp', 'nodetype' );
|
|
my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
|
|
|
|
# Get zHCP of hypervisor
|
|
my $srcHcp = $propVals->{'hcp'};
|
|
if ( !$srcHcp ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing node HCP" );
|
|
return;
|
|
}
|
|
|
|
my $type = $propVals->{'nodetype'};
|
|
if ($type ne 'zvm') {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Invalid nodetype" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Solution) Set the nodetype appropriately in the zvm table" );
|
|
return;
|
|
}
|
|
|
|
my $destHcp;
|
|
|
|
# Find the zHCP for the destination host and set the node zHCP as it
|
|
# Otherwise, it is up to the user to manually change the zHCP
|
|
@propNames = ( 'hcp' );
|
|
$propVals = xCAT::zvmUtils->getNodeProps( 'zvm', lc($destination), @propNames );
|
|
$destHcp = $propVals->{'hcp'};
|
|
if ( !$destHcp ) {
|
|
# Try upper-case
|
|
$propVals = xCAT::zvmUtils->getNodeProps( 'zvm', uc($destination), @propNames );
|
|
$destHcp = $propVals->{'hcp'};
|
|
}
|
|
|
|
if (!$destHcp) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Failed to find zHCP of $destination" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Solution) Set the hcp appropriately in the zvm table" );
|
|
return;
|
|
}
|
|
|
|
# Get nodes managed by this zHCP
|
|
# Look in 'zvm' table
|
|
my $tab = xCAT::Table->new( 'zvm', -create => 1, -autocommit => 0 );
|
|
my @entries = $tab->getAllAttribsWhere( "hcp like '%" . $srcHcp . "%' and nodetype=='vm'", 'node', 'userid' );
|
|
|
|
my $out;
|
|
my $iNode;
|
|
my $iUserId;
|
|
my $smcliArgs;
|
|
my $nodes = "";
|
|
foreach (@entries) {
|
|
$iNode = $_->{'node'};
|
|
$iUserId = $_->{'userid'};
|
|
|
|
# Skip zHCP entry
|
|
if ($srcHcp =~ m/$iNode./i || $srcHcp eq $iNode) {
|
|
next;
|
|
}
|
|
|
|
$nodes .= $iNode . ",";
|
|
}
|
|
|
|
# Strip last comma
|
|
$nodes = substr($nodes, 0, -1);
|
|
|
|
# Do not continue if no nodes to migrate
|
|
if (!$nodes) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: No nodes to evacuate" );
|
|
return;
|
|
}
|
|
|
|
# Begin migration
|
|
# Required keys: target_identifier, destination, action, immediate, and max_total
|
|
$out = `/opt/xcat/bin/rmigrate $nodes action=MOVE destination=$destination immediate=NO max_total=NOLIMIT`;
|
|
xCAT::zvmUtils->printLn( $callback, "$out" );
|
|
|
|
return;
|
|
}
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 eventLog
|
|
|
|
Description : Retrieve, clear, or set logging options for event logs
|
|
Arguments : Node
|
|
Location of source log
|
|
Location to place log
|
|
Returns : Nothing
|
|
Example : eventLog($callback, $node, $args);
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
sub eventLog {
|
|
|
|
# Get inputs
|
|
my ( $callback, $node, $args ) = @_;
|
|
|
|
my $srcLog = '';
|
|
my $tgtLog = '';
|
|
my $clear = 0;
|
|
my $options = '';
|
|
if ($args) {
|
|
@ARGV = @$args;
|
|
|
|
# Parse options
|
|
GetOptions(
|
|
's=s' => \$srcLog,
|
|
't=s' => \$tgtLog, # Optional
|
|
'c' => \$clear,
|
|
'o=s' => \$options); # Set logging options
|
|
}
|
|
|
|
# Event log required
|
|
if (!$srcLog) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing event log" );
|
|
return;
|
|
}
|
|
|
|
# Limit to logs in /var/log/* and configurations in /var/opt/*
|
|
my $tmp = substr($srcLog, 0, 9);
|
|
if ($tmp ne "/var/opt/" && $tmp ne "/var/log/") {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Files are restricted to those in /var/log and /var/opt" );
|
|
return;
|
|
}
|
|
|
|
# Check if node is the management node
|
|
my @entries = xCAT::TableUtils->get_site_attribute("master");
|
|
my $master = xCAT::zvmUtils->trimStr($entries[0]);
|
|
my $ip = xCAT::NetworkUtils->getipaddr($node);
|
|
$ip = xCAT::zvmUtils->trimStr($ip);
|
|
my $mn = 0;
|
|
if ($master eq $ip) {
|
|
# If the master IP and node IP match, then it is the management node
|
|
xCAT::zvmUtils->printLn( $callback, "$node: This is the management node" );
|
|
$mn = 1;
|
|
}
|
|
|
|
# Just clear the log
|
|
my $out = '';
|
|
if ($clear) {
|
|
if ($mn) {
|
|
$out = `cat /dev/null > $srcLog`;
|
|
} else {
|
|
$out = `ssh $::SUDOER\@$node "cat /dev/null > $srcLog"`;
|
|
}
|
|
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Clearing event log ($srcLog)... Done" );
|
|
return;
|
|
}
|
|
|
|
# Just set the logging options
|
|
if ($options) {
|
|
if ($mn) {
|
|
$out = `echo -e \"$options\" > $srcLog`;
|
|
} else {
|
|
$out = `echo -e \"$options\" > /tmp/$node.tracing`;
|
|
$out = `ssh $::SUDOER\@$node "rm -rf $srcLog"`;
|
|
$out = `cat /tmp/$node.tracing | ssh $::SUDOER\@$node "cat > /tmp/$node.tracing"`;
|
|
$out = `ssh $::SUDOER\@$node "mv /tmp/$node.tracing $srcLog"`;
|
|
$out = `rm -rf /tmp/$node.tracing`;
|
|
}
|
|
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Setting event logging options... Done" );
|
|
return;
|
|
}
|
|
|
|
# Default log location is /install/logs
|
|
if (!$tgtLog) {
|
|
my @entries = xCAT::TableUtils->get_site_attribute("installdir");
|
|
my $install = $entries[0];
|
|
|
|
$tgtLog = "$install/logs/";
|
|
$out = `mkdir -p $tgtLog`;
|
|
}
|
|
|
|
# Copy over event log onto xCAT
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Retrieving event log ($srcLog)" );
|
|
if ($mn) {
|
|
if (!(`test -e $srcLog && echo Exists`)) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Specified log does not exist" );
|
|
return;
|
|
}
|
|
|
|
$out = `cp $srcLog $tgtLog`;
|
|
} else {
|
|
if (!(`ssh $::SUDOER\@$node "test -e $srcLog && echo Exists"`)) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Specified log does not exist" );
|
|
return;
|
|
}
|
|
|
|
$out = `scp $::SUDOER\@$node:$srcLog $tgtLog`;
|
|
}
|
|
|
|
if ( -e $tgtLog ) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Log copied to $tgtLog" );
|
|
$out = `chmod -R 644 $tgtLog/*`;
|
|
} else {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Failed to copy log" );
|
|
}
|
|
}
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 imageCapture
|
|
|
|
Description : Capture a disk image from a Linux system on z/VM.
|
|
Arguments : Node
|
|
OS
|
|
Archictecture
|
|
Profile
|
|
Device information
|
|
Returns : Nothing
|
|
Example : imageCapture( $callback, $node, $os, $arch, $profile, $osimg, $device );
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
sub imageCapture {
|
|
my ($class, $callback, $node, $os, $arch, $profile, $osimg, $device) = @_;
|
|
my $rc;
|
|
my $out = '';
|
|
my $reason = "";
|
|
|
|
xCAT::zvmUtils->printSyslog( "imageCapture() $node:$node os:$os arch:$arch profile:$profile osimg:$osimg device:$device" );
|
|
|
|
# Verify required properties are defined
|
|
if (!defined($os) || !defined($arch) || !defined($profile)) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) One or more of the required properties is not specified: os version, architecture or profile" );
|
|
return;
|
|
}
|
|
|
|
# Ensure the architecture property is 's390x'
|
|
if ($arch ne 's390x') {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Architecture was $arch instead of 's390x'. 's390x' will be used instead of the specified value." );
|
|
$arch = 's390x';
|
|
}
|
|
|
|
# Obtain the location of the install root directory
|
|
my $installRoot = xCAT::TableUtils->getInstallDir();
|
|
|
|
# Directory where executables are on zHCP.
|
|
# Using a local variable to hold the directory information because this routine is called from another module.
|
|
my $dir = "/opt/zhcp/bin";
|
|
|
|
# Use sudo or not
|
|
# This looks in the passwd table for a key = sudoer
|
|
my ($sudoer, $sudo) = xCAT::zvmUtils->getSudoer();
|
|
|
|
# Get node properties from 'zvm' table
|
|
my @propNames = ( 'hcp', 'userid' );
|
|
my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
|
|
|
|
# Get zHCP
|
|
my $hcp = $propVals->{'hcp'};
|
|
if (!$hcp) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing node HCP" );
|
|
return;
|
|
}
|
|
|
|
# Get zHCP user ID
|
|
my $hcpUserId = xCAT::zvmCPUtils->getUserId($::SUDOER, $hcp);
|
|
$hcpUserId =~ tr/a-z/A-Z/;
|
|
|
|
# Get capture target's user ID
|
|
my $targetUserId = $propVals->{'userid'};
|
|
$targetUserId =~ tr/a-z/A-Z/;
|
|
|
|
# Get node properties from 'zvm' table
|
|
@propNames = ( 'ip', 'hostnames' );
|
|
$propVals = xCAT::zvmUtils->getNodeProps('hosts', $node, @propNames);
|
|
|
|
# Check if node is pingable
|
|
if (`/opt/xcat/bin/pping $node | egrep -i "noping"`) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Host is unreachable" );
|
|
return;
|
|
}
|
|
|
|
my $vaddr;
|
|
my $devName;
|
|
# Set the default is device option was specified without any parameters.
|
|
if (!$device) {
|
|
$devName = "/dev/root";
|
|
}
|
|
|
|
# Obtain the device number from the target system.
|
|
if ($devName eq '/dev/root') {
|
|
# Determine which Linux device is associated with the root directory
|
|
$out = `ssh $sudoer\@$node $sudo cat /proc/cmdline | tr " " "\\n" | grep "^root=" | cut -c6-`;
|
|
if ($out) {
|
|
$out = `ssh $sudoer\@$node $sudo "/usr/bin/readlink -f $out"`;
|
|
if ($out) {
|
|
$devName = substr($out, 5);
|
|
$devName =~ s/\s+$//;
|
|
$devName =~ s/\d+$//;
|
|
} else {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Unable locate the device associated with the root directory" );
|
|
return;
|
|
}
|
|
} else {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Unable locate the device associated with the root directory" );
|
|
return;
|
|
}
|
|
} else {
|
|
$devName = substr $devName, 5;
|
|
}
|
|
|
|
$vaddr = xCAT::zvmUtils->getDeviceNodeAddr($sudoer, $node, $devName);
|
|
if (!$vaddr) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Unable determine the device being captured" );
|
|
return 0;
|
|
}
|
|
|
|
# Shutdown and logoff the virtual machine so that its disks are stable for the capture step.
|
|
xCAT::zvmUtils->printSyslog( "imageCapture() Shutting down $node prior to disk capture" );
|
|
$out = `ssh -o ConnectTimeout=10 $node "shutdown -h now"`;
|
|
sleep(15); # Wait 15 seconds to let shutdown start before logging user off
|
|
|
|
# If the OS is not shutdown and the machine is enabled for shutdown signals
|
|
# then deactivate will cause CP to send the shutdown signal and
|
|
# wait an additional (z/VM installation configurable) time before forcing
|
|
# the virtual machine off the z/VM system.
|
|
xCAT::zvmUtils->printSyslog( "$sudo $dir/smcli Image_Deactivate -T $targetUserId" );
|
|
$out = `ssh $sudoer\@$hcp "$sudo $dir/smcli Image_Deactivate -T $targetUserId"`;
|
|
xCAT::zvmUtils->printSyslog( "imageCapture() smcli response: $out" );
|
|
|
|
xCAT::zvmUtils->printSyslog( "imageCapture() Preparing the staging directory" );
|
|
|
|
# Create the staging area location for the image
|
|
my $stagingImgDir = "$installRoot/staging/$os/$arch/$profile";
|
|
if(-d $stagingImgDir) {
|
|
unlink $stagingImgDir;
|
|
}
|
|
mkpath($stagingImgDir);
|
|
|
|
# Prepare the staging mount point on zHCP, if they need to be established.
|
|
my $remoteStagingDir;
|
|
$rc = xCAT::zvmUtils->establishMount( $callback, $sudoer, $sudo, $hcp, "$installRoot/staging", "rw", \$remoteStagingDir );
|
|
if ($rc) {
|
|
# Mount failed
|
|
rmtree "$stagingImgDir";
|
|
return;
|
|
}
|
|
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Capturing the image using zHCP node" );
|
|
|
|
# Drive the capture on the zHCP node
|
|
xCAT::zvmUtils->printSyslog( "imageCapture() creatediskimage $targetUserId $vaddr $remoteStagingDir/$os/$arch/$profile/${vaddr}.img" );
|
|
$out = `ssh $sudoer\@$hcp "$sudo $dir/creatediskimage $targetUserId $vaddr $remoteStagingDir/$os/$arch/$profile/${vaddr}.img"`;
|
|
$rc = $?;
|
|
|
|
# If the capture failed then clean up and return
|
|
my $reasonString = "";
|
|
$rc = xCAT::zvmUtils->checkOutputExtractReason( $callback, $out, \$reasonString );
|
|
if ($rc != 0) {
|
|
$reason = "Reason: $reasonString";
|
|
xCAT::zvmUtils->printSyslog( "imageCapture() creatediskimage of $targetUserId $vaddr failed. $reason" );
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Image capture of $targetUserId $vaddr failed on the zHCP node. $reason" );
|
|
rmtree "$stagingImgDir" ;
|
|
return;
|
|
}
|
|
|
|
# Now that all image files have been successfully created, move them to the deployable directory.
|
|
my $imageName = "$os-$arch-netboot-$profile";
|
|
my $deployImgDir = "$installRoot/netboot/$os/$arch/$profile";
|
|
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Moving the image files to the deployable directory: $deployImgDir" );
|
|
|
|
my @stagedFiles = glob "$stagingImgDir/*.img";
|
|
if (!@stagedFiles) {
|
|
rmtree "$stagingImgDir";
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) No image files were created" );
|
|
return 0;
|
|
}
|
|
|
|
mkpath($deployImgDir);
|
|
|
|
foreach my $oldFile (@stagedFiles) {
|
|
$rc = move($oldFile, $deployImgDir);
|
|
$reason = $!;
|
|
if ($rc == 0) {
|
|
# Move failed
|
|
rmtree "$stagingImgDir";
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Could not move $oldFile to $deployImgDir. $reason" );
|
|
return;
|
|
}
|
|
}
|
|
|
|
# Remove the staging directory and files
|
|
rmtree "$stagingImgDir";
|
|
|
|
xCAT::zvmUtils->printSyslog( "imageCapture() Updating the osimage table" );
|
|
|
|
# Update osimage table
|
|
my $osTab = xCAT::Table->new('osimage',-create => 1,-autocommit => 0);
|
|
my %keyHash;
|
|
|
|
unless ($osTab) {
|
|
xCAT::zvmUtils->printLn( $callback, "$node: (Error) Unable to open table 'osimage'" );
|
|
return;
|
|
}
|
|
|
|
$keyHash{provmethod} = 'netboot';
|
|
$keyHash{profile} = $profile;
|
|
$keyHash{osvers} = $os;
|
|
$keyHash{osarch} = $arch;
|
|
$keyHash{imagetype} = 'linux';
|
|
$keyHash{osname} = 'Linux';
|
|
$keyHash{imagename} = $imageName;
|
|
|
|
$osTab->setAttribs({imagename => $imageName}, \%keyHash);
|
|
$osTab->commit;
|
|
|
|
xCAT::zvmUtils->printSyslog( "imageCapture() Updating the linuximage table" );
|
|
|
|
# Update linuximage table
|
|
my $linuxTab = xCAT::Table->new('linuximage',-create => 1,-autocommit => 0);
|
|
|
|
%keyHash = ();
|
|
$keyHash{imagename} = $imageName;
|
|
$keyHash{rootimgdir} = $deployImgDir;
|
|
|
|
$linuxTab->setAttribs({imagename => $imageName}, \%keyHash);
|
|
$linuxTab->commit;
|
|
|
|
xCAT::zvmUtils->printLn( $callback, "$node: Completed capturing the image($imageName) and stored at $deployImgDir" );
|
|
|
|
return;
|
|
}
|