2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2025-05-29 09:13:08 +00:00
xcat-core/perl-xCAT/xCAT/zvmUtils.pm

5204 lines
173 KiB
Perl

# IBM(c) 2013-2016 EPL license http://www.eclipse.org/legal/epl-v10.html
#-------------------------------------------------------
=head1
This is a utility plugin for z/VM.
=cut
#-------------------------------------------------------
package xCAT::zvmUtils;
use xCAT::MsgUtils;
use xCAT::Utils;
use xCAT::Table;
use xCAT::NetworkUtils;
use File::Basename;
use Net::Ping;
use strict;
use warnings;
use Encode;
use JSON;
use Data::Dumper;
use Cwd;
1;
my $locOpenStackUpdateName = '/var/lib/sspmod/setnewname.py';
# Files which contain OS distribution and version information.
my $locEtcDebianVersion = '/etc/debian_version';
my $locEtcFedoraRelease = '/etc/fedora-release';
my $locEtcIssue = '/etc/issue';
my $locEtcLsbRelease = '/etc/lsb-release';
my $locEtcOsRelease = '/etc/os-release';
my $locEtcRedhatRelease = '/etc/redhat-release';
my $locEtcStarRelease = '/etc/*-release';
my $locEtcSuseRelease = '/etc/SuSE-release';
my $locEtcUnitedLinux = '/etc/UnitedLinux-release';
my $locAllEtcVerFiles = "/etc/*-release /etc/issue /etc/debian_version";
# Supported Operating System distros and versions
my %supportedVersions = (
rhel5 => 1,
rhel6 => 1,
sles10 => 1,
sles11 => 1,
);
#-------------------------------------------------------
=head3 getNodeProps
Description : Get node properties
Arguments : Table
Node
Properties
Returns : Node properties from given table
Example : my $propVals = xCAT::zvmUtils->getNodeProps($tabName, $node, $propNames);
=cut
#-------------------------------------------------------
sub getNodeProps {
# Get inputs
my ( $class, $tabName, $node, @propNames ) = @_;
# Get table
my $tab = xCAT::Table->new($tabName);
# Get property values
my $propVals = $tab->getNodeAttribs( $node, [@propNames] );
return ($propVals);
}
#-------------------------------------------------------
=head3 getTabPropsByKey
Description : Get table entry properties by key
Arguments : Table
Key name
Key value
Requested properties
Returns : Table entry properties
Example : my $propVals = xCAT::zvmUtils->getTabPropsByKey($tabName, $key, $keyValue, @reqProps);
=cut
#-------------------------------------------------------
sub getTabPropsByKey {
# Get inputs
my ( $class, $tabName, $key, $keyVal, @propNames ) = @_;
# Get table
my $tab = xCAT::Table->new($tabName);
my $propVals;
# Get table attributes matching given key
$propVals = $tab->getAttribs( { $key => $keyVal }, @propNames );
return ($propVals);
}
#-------------------------------------------------------
=head3 getAllTabEntries
Description : Get all entries within given table
Arguments : Table name
Returns : All table entries
Example : my $entries = xCAT::zvmUtils->getAllTabEntries($tabName);
=cut
#-------------------------------------------------------
sub getAllTabEntries {
# Get inputs
my ( $class, $tabName ) = @_;
# Get table
my $tab = xCAT::Table->new($tabName);
my $entries;
# Get all entries within given table
$entries = $tab->getAllEntries();
return ($entries);
}
#-------------------------------------------------------
=head3 setNodeProp
Description : Set a node property in a given table
Arguments : Table
Node
Property name
Property value
Returns : Nothing
Example : xCAT::zvmUtils->setNodeProp($tabName, $node, $propName, $propVal);
=cut
#-------------------------------------------------------
sub setNodeProp {
# Get inputs
my ( $class, $tabName, $node, $propName, $propVal ) = @_;
# Get table
my $tab = xCAT::Table->new( $tabName, -create => 1, -autocommit => 0 );
# Set property
$tab->setAttribs( { 'node' => $node }, { $propName => $propVal } );
# Save table
$tab->commit;
return;
}
#-------------------------------------------------------
=head3 setNodeProps
Description : Set node properties in a given table
Arguments : Table
Node
Reference to property name/value hash
Returns : Nothing
Example : xCAT::zvmUtils->setNodeProps($tabName, $node, \%propHash);
=cut
#-------------------------------------------------------
sub setNodeProps {
# Get inputs
my ( $class, $tabName, $node, $propHash ) = @_;
# Get table
my $tab = xCAT::Table->new( $tabName, -create => 1, -autocommit => 0 );
# Set property
$tab->setAttribs( { 'node' => $node }, $propHash );
# Save table
$tab->commit;
return;
}
#-------------------------------------------------------
=head3 delTabEntry
Description : Delete a table entry
Arguments : Table
Key name
Key value
Returns : Nothing
Example : xCAT::zvmUtils->delTabEntry($tabName, $keyName, $keyVal);
=cut
#-------------------------------------------------------
sub delTabEntry {
# Get inputs
my ( $class, $tabName, $keyName, $keyVal ) = @_;
# Get table
my $tab = xCAT::Table->new( $tabName, -create => 1, -autocommit => 0 );
# Delete entry from table
my %key = ( $keyName => $keyVal );
$tab->delEntries( \%key );
# Save table
$tab->commit;
return;
}
#-------------------------------------------------------
=head3 tabStr
Description : Tab a string (4 spaces)
Arguments : String
Returns : Tabbed string
Example : my $str = xCAT::zvmUtils->tabStr($str);
=cut
#-------------------------------------------------------
sub tabStr {
# Get inputs
my ( $class, $inStr ) = @_;
my @lines = split( "\n", $inStr );
# Tab output
my $outStr;
foreach (@lines) {
$outStr .= " $_\n";
}
return ($outStr);
}
#-------------------------------------------------------
=head3 trimStr
Description : Trim the whitespaces in a string
Arguments : String
Returns : Trimmed string
Example : my $str = xCAT::zvmUtils->trimStr($str);
=cut
#-------------------------------------------------------
sub trimStr {
# Get string
my ( $class, $str ) = @_;
# Trim right
$str =~ s/\s*$//;
# Trim left
$str =~ s/^\s*//;
return ($str);
}
#-------------------------------------------------------
=head3 replaceStr
Description : Replace a given pattern in a string
Arguments : String
Returns : New string
Example : my $str = xCAT::zvmUtils->replaceStr($str, $pattern, $replacement);
=cut
#-------------------------------------------------------
sub replaceStr {
# Get string
my ( $class, $str, $pattern, $replacement ) = @_;
# Replace string
$str =~ s/$pattern/$replacement/g;
return ($str);
}
#-------------------------------------------------------
=head3 printLn
Description : Print a string to stdout
Arguments : String
Returns : Nothing
Example : xCAT::zvmUtils->printLn($callback, $str);
=cut
#-------------------------------------------------------
sub printLn {
# Get inputs
my ( $class, $callback, $str ) = @_;
# Print string
my $rsp;
my $type = "I";
if ($str =~ m/(\(error\)|\s*failed)/i) { # Set to print error if the string contains (error) or starts with failed
$type = "E";
}
$rsp->{data}->[0] = "$str";
xCAT::MsgUtils->message( $type, $rsp, $callback );
# xCAT::MsgUtils->message( "S", $str ); # Print to syslog
return;
}
#-------------------------------------------------------
=head3 printSyslog
Description : Print a string to syslog
Arguments : String
Returns : Nothing
Example : xCAT::zvmUtils->printSyslog($str);
=cut
#-------------------------------------------------------
sub printSyslog {
# Get inputs
my ( $class, $str ) = @_;
# Prepend where this message came from
$str = $class . " " . $str;
# Print string
xCAT::MsgUtils->message( "S", $str );
return;
}
#-------------------------------------------------------
=head3 isZvmNode
Description : Determines if a given node is in the 'zvm' table
Arguments : Node
Returns : TRUE Node exists
FALSE Node does not exists
Example : my $out = xCAT::zvmUtils->isZvmNode($node);
=cut
#-------------------------------------------------------
sub isZvmNode {
# Get inputs
my ( $class, $node ) = @_;
# Look in 'zvm' table
my $tab = xCAT::Table->new( 'zvm', -create => 1, -autocommit => 0 );
my @results = $tab->getAllAttribsWhere( "node = '" . $node . "'", 'userid' );
foreach (@results) {
# Return 'TRUE' if given node is in the table
if ($_->{'userid'}) {
return 1;
}
}
return 0;
}
#-------------------------------------------------------
=head3 getHwcfg
Description : Get the hardware configuration file path (SUSE only)
e.g. /etc/sysconfig/hardwarehwcfg-qeth-bus-ccw-0.0.0600
Arguments : User (root or non-root)
Node
Returns : Hardware configuration file path
Example : my $hwcfg = xCAT::zvmUtils->getHwcfg($user, $node);
=cut
#-------------------------------------------------------
sub getHwcfg {
# Get inputs
my ( $class, $user, $node ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Get OS
my $os = xCAT::zvmUtils->getOs($user, $node);
# Get network configuration file path
my $out;
my @parms;
# If it is SUSE - hwcfg-qeth file is in /etc/sysconfig/hardware
if ( $os =~ m/SUSE/i ) {
#$out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo ls /etc/sysconfig/hardware/hwcfg-qeth*"`;
my $cmd = "$sudo ls /etc/sysconfig/hardware/hwcfg-qeth*";
$out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
return $out;
}
@parms = split( '\n', $out );
return ( $parms[0] );
}
# If no file is found - Return nothing
return;
}
#-------------------------------------------------------
=head3 getIp
Description : Get the IP address of a given node
Arguments : Node
Returns : IP address of given node
Example : my $ip = xCAT::zvmUtils->getIp($node);
=cut
#-------------------------------------------------------
sub getIp {
# Get inputs
my ( $class, $node ) = @_;
# Get IP address
# You need the extra space in the pattern,
# else it will confuse gpok2 with gpok21
my $out = `cat /etc/hosts | egrep -i "$node | $node."`;
my @parms = split( ' ', $out );
return $parms[0];
}
#-------------------------------------------------------
=head3 getIfcfg
Description : Get the network configuration file path of a given node
* Red Hat - /etc/sysconfig/network-scripts/ifcfg-eth
* SUSE - /etc/sysconfig/network/ifcfg-qeth
Arguments : User (root or non-root)
Node
Returns : Network configuration file path
Example : my $ifcfg = xCAT::zvmUtils->getIfcfg($user, $node);
=cut
#-------------------------------------------------------
sub getIfcfg {
# Get inputs
my ( $class, $user, $node ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Get OS
my $os = xCAT::zvmUtils->getOs($user, $node);
# Get network configuration file path
my $out;
my @parms;
# If it is Red Hat - ifcfg-qeth file is in /etc/sysconfig/network-scripts
if ( $os =~ m/Red Hat/i ) {
#$out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo ls /etc/sysconfig/network-scripts/ifcfg-eth*"`;
my $cmd = "$sudo ls /etc/sysconfig/network-scripts/ifcfg-eth*";
$out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
return $out;
}
@parms = split( '\n', $out );
return ( $parms[0] );
}
# If it is SUSE - ifcfg-qeth file is in /etc/sysconfig/network
elsif ( $os =~ m/SUSE/i ) {
#$out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo ls /etc/sysconfig/network/ifcfg-qeth*"`;
my $cmd = "$sudo ls /etc/sysconfig/network/ifcfg-qeth*";
$out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
return $out;
}
@parms = split( '\n', $out );
return ( $parms[0] );
}
# If no file is found - Return nothing
return;
}
#-------------------------------------------------------
=head3 getIfcfgByNic
Description : Get the network configuration file path of a given node
Arguments : User (root or non-root)
Node
NIC address
Returns : Network configuration file path
Example : my $ifcfg = xCAT::zvmUtils->getIfcfgByNic($user, $node, $nic);
=cut
#-------------------------------------------------------
sub getIfcfgByNic {
# Get inputs
my ( $class, $user, $node, $nic ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Get OS
my $os = xCAT::zvmUtils->getOs($user, $node);
# Get network configuration file path
my $out;
my @parms;
# If it is Red Hat - ifcfg-qeth file is in /etc/sysconfig/network-scripts
if ( $os =~ m/Red Hat/i ) {
#$out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo ls /etc/sysconfig/network-scripts/ifcfg-eth*"`;
my $cmd = "$sudo ls /etc/sysconfig/network-scripts/ifcfg-eth*";
$out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
return $out;
}
@parms = split( '\n', $out );
# Go through each line
foreach (@parms) {
my $filename = $_;
# If the network file contains the NIC address
#$out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo cat $_" | egrep -i "$nic"`;
my $cmd = $sudo . ' cat $filename';
$out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
return $out;
}
$out = `echo "$out" | egrep -a -i "$nic"`;
if ($out) {
# Return network file path
return ($filename);
}
}
}
# If it is SLES 10 - ifcfg-qeth file is in /etc/sysconfig/network
elsif ( $os =~ m/SUSE Linux Enterprise Server 10/i ) {
#$out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo ls /etc/sysconfig/network/ifcfg-qeth*" | grep -i "$nic"`;
my $cmd = $sudo . ' ls /etc/sysconfig/network/ifcfg-qeth*';
$out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
return $out;
}
$out = `echo "$out" | egrep -a -i "$nic"`;
@parms = split( '\n', $out );
return ( $parms[0] );
}
# If it is SLES 11 - ifcfg-qeth file is in /etc/sysconfig/network
elsif ( $os =~ m/SUSE Linux Enterprise Server 11/i ) {
# Get a list of ifcfg-eth files found
#$out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo ls /etc/sysconfig/network/ifcfg-eth*"`;
my $cmd = "$sudo ls /etc/sysconfig/network/ifcfg-eth*";
$out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
return $out;
}
my @file = split( '\n', $out );
# Go through each ifcfg-eth file
foreach (@file) {
# If the network file contains the NIC address
#$out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo cat $_" | grep -i "$nic"`;
my $cmd = $sudo . ' cat $_';
$out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
return $out;
}
$out = `echo "$out" | egrep -a -i "$nic"`;
if ($out) {
# Return ifcfg-eth file path
return ($_);
}
}
}
# If no file is found - Return nothing
return;
}
#-------------------------------------------------------
=head3 sendFile
Description : SCP a file to a given node
Arguments : User (root or non-root)
Node
Source file
Target file
Returns : Return code from SCP
Example : $rc = xCAT::zvmUtils->sendFile($user, $node, $srcFile, $trgtFile);
=cut
#-------------------------------------------------------
sub sendFile {
# Get inputs
my ( $class, $user, $node, $srcFile, $trgtFile ) = @_;
my $out;
my $rc;
# Create destination string
my $dest = "$user\@$node";
# SCP directory entry file over to HCP
foreach my $wait ( 1, 2, 3, 5, 8, 15, 22, 34, 60 ) {
$out = `/usr/bin/scp $srcFile $dest:$trgtFile 2>&1`;
$rc = $?;
if ( $rc == 0 ) {
last;
}
xCAT::zvmUtils->printSyslog("SCP $srcFile $dest:$trgtFile - failed with rc: $rc, out: $out");
sleep( $wait );
}
return $rc;
}
#-------------------------------------------------------
=head3 getRootDeviceAddr
Description : Get the root device address of a given node
Arguments : User (root or non-root)
Node
Returns : Root device address
Example : my $deviceAddr = xCAT::zvmUtils->getRootDeviceAddr($user, $node);
=cut
#-------------------------------------------------------
sub getRootDeviceAddr {
# Get inputs
my ( $class, $user, $node ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Get the root device node
# LVM is not supported
#my $out = `ssh $user\@$node "mount" | grep "/ type" | sed 's/1//'`;
my $cmd = $sudo . ' mount';
my $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
return $out;
}
$out = `echo "$out" | egrep -a -i "/ type" | sed \'s/1//\'`;
my @parms = split( " ", $out );
@parms = split( "/", xCAT::zvmUtils->trimStr( $parms[0] ) );
my $devNode = $parms[0];
# Get disk address
#$out = `ssh $user\@$node "cat /proc/dasd/devices" | grep "$devNode" | sed 's/(ECKD)//' | sed 's/(FBA )//' | sed 's/0.0.//'`;
$cmd = $sudo . ' cat /proc/dasd/devices';
$out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
return $out;
}
$out = `echo "$out" | egrep -a -i "$devNode" | sed "s/(ECKD)//" | sed "s/(FBA )//" | sed \'s/0.0.//\'`;
@parms = split( " ", $out );
return ( $parms[0] );
}
#-------------------------------------------------------
=head3 disableEnableDisk
Description : Disable/enable a disk for a given node
Arguments : User (root or non-root)
Node
Device address
Option (-d|-e)
Returns : successful: String indicating the enable was performed and ending with "Done".
unsuccessful: Error message from the last attempt
Example : my $out = xCAT::zvmUtils->disableEnableDisk($callback, $user, $node, $option, $devAddr);
=cut
#-------------------------------------------------------
sub disableEnableDisk {
# Get inputs
my ( $class, $user, $node, $option, $devAddr ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Disable/enable disk
my $out = '';
if ( $option eq "-d" || $option eq "-e" ) {
# Can't guarantee the success of online/offline disk, need to wait
# Until it's done because we may detach the disk after -d option
# or use the disk after the -e option
my @sleepTime = (1,2,3,5,8,15,22,34,60,60,60,60,60,90,120);
foreach (@sleepTime) {
my $cmd = "$sudo /sbin/chccwdev $option $devAddr 2>&1";
$out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
if (xCAT::zvmUtils->checkOutput( $out ) == -1) { # try again if an error
xCAT::zvmUtils->printSyslog( "$node: Error received on cmd: $cmd, output: $out" );
sleep($_);
} else {
return "ssh $user\@$node $sudo /sbin/chccwdev $option $devAddr... Done";
}
}
}
return "Error: failed to ssh $user\@$node $sudo /sbin/chccwdev $option $devAddr, Output: $out";
}
#-------------------------------------------------------
=head3 getMdisks
Description : Get the MDISK statements in the user entry of a given node
Arguments : User (root or non-root)
Node
Returns : MDISK statements array or or string containing (Error)...
Example : my @mdisks = xCAT::zvmUtils->getMdisks($callback, $user, $node);
=cut
#-------------------------------------------------------
sub getMdisks {
# Get inputs
my ( $class, $callback, $user, $node ) = @_;
# Directory where executables are
my $dir = '/opt/zhcp/bin';
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Get HCP
my @propNames = ( 'hcp', 'userid' );
my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
my $hcp = $propVals->{'hcp'};
# Get node userID
my $userId = $propVals->{'userid'};
my $outmsg;
my $rc;
my $out = `ssh $user\@$hcp "$sudo $dir/getuserentry $userId"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo $dir/getuserentry $userId\"", $hcp, "getMdisks", $out, $node );
if ($rc != 0) {
return $outmsg;
}
$out = `echo "$out" | egrep -a -i "MDISK"`;
# Get MDISK statements
my @lines = split( '\n', $out );
my @disks;
foreach (@lines) {
# skip comment lines that start with * or whitespace *
if ( $_ =~ m/^\s*\*/) {
next;
}
$_ = xCAT::zvmUtils->trimStr($_);
# Save MDISK statements
push( @disks, $_ );
}
return (@disks);
}
#-------------------------------------------------------
=head3 getDedicates
Description : Get the DEDICATE statements in the user entry of a given node
Arguments : User (root or non-root)
Node
Returns : DEDICATE statements array or string containing (Error)...
Example : my @dedicates = xCAT::zvmUtils->getDedicates($callback, $user, $node);
=cut
#-------------------------------------------------------
sub getDedicates {
# Get inputs
my ( $class, $callback, $user, $node ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Directory where executables are
my $dir = '/opt/zhcp/bin';
# Get zHCP
my @propNames = ( 'hcp', 'userid' );
my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
my $hcp = $propVals->{'hcp'};
# Get node userId
my $userId = $propVals->{'userid'};
my $outmsg;
my $rc;
my $out = `ssh $user\@$hcp "$sudo $dir/smcli Image_Query_DM -T $userId"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "commandString", $hcp, "getMdisks", $out, $node );
if ($rc != 0) {
return $outmsg;
}
$out = `echo "$out" | egrep -a -i "DEDICATE"`;
# Get DEDICATE statements
my @lines = split( '\n', $out );
my @dedicates;
foreach (@lines) {
$_ = xCAT::zvmUtils->trimStr($_);
# Save statements
push( @dedicates, $_ );
}
return (@dedicates);
}
#-------------------------------------------------------
=head3 getCommands
Description : Get the COMMAND statements in the user entry of a given node
Arguments : User (root or non-root)
Node
Returns : COMMAND statements array or or string containing (Error)...
Example : my @commands = xCAT::zvmUtils->getCommands($callback, $user, $node);
=cut
#-------------------------------------------------------
sub getCommands {
# Get inputs
my ( $class, $callback, $user, $node ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Directory where executables are
my $dir = '/opt/zhcp/bin';
# Get zHCP
my @propNames = ( 'hcp', 'userid' );
my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
my $hcp = $propVals->{'hcp'};
# Get node userId
my $userId = $propVals->{'userid'};
my $outmsg;
my $rc;
my $out = `ssh $user\@$hcp "$sudo $dir/smcli Image_Query_DM -T $userId"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo $dir/smcli Image_Query_DM -T $userId\"", $hcp, "getCommands", $out, $node );
if ($rc != 0) {
return $outmsg;
}
$out = `echo "$out" | egrep -a -i "COMMAND"`;
# Get COMMAND statements
my @lines = split( '\n', $out );
my @commands;
foreach (@lines) {
$_ = xCAT::zvmUtils->trimStr($_);
# Save statements
push( @commands, $_ );
}
return (@commands);
}
#-------------------------------------------------------
=head3 getUserEntryWODisk
Description : Get the user entry of a given node without MDISK statments,
and save it to a file
Arguments : User (root or non-root)
Node
File name to save user entry under
Returns : Nothing, or string containing (Error)...
Example : my $out = xCAT::zvmUtils->getUserEntryWODisk($callback, $user, $node, $file);
=cut
#-------------------------------------------------------
sub getUserEntryWODisk {
# Get inputs
my ( $class, $callback, $user, $node, $file ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Directory where executables are
my $dir = '/opt/zhcp/bin';
# 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, "Error: Missing node HCP" );
return;
}
# Get node userID
my $userId = $propVals->{'userid'};
if ( !$userId ) {
xCAT::zvmUtils->printLn( $callback, "Error: Missing node ID" );
return;
}
my $outmsg;
my $rc;
my $out = `ssh $user\@$hcp "$sudo $dir/smcli Image_Query_DM -T $userId"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo $dir/smcli Image_Query_DM -T $userId\"", $hcp, "getUserEntryWODisk", $out, $node );
if ($rc != 0) {
return $outmsg;
}
$out = `echo "$out" | sed '\$d' | grep -a -i -v "MDISK"`;
# Create a file to save output
open( DIRENTRY, ">$file" );
# Save output
my @lines = split( '\n', $out );
foreach (@lines) {
# Trim line
$_ = xCAT::zvmUtils->trimStr($_);
# Write directory entry into file
print DIRENTRY "$_\n";
}
close(DIRENTRY);
return;
}
#-------------------------------------------------------
=head3 appendHostname
Description : Append a hostname in front of a given string
Arguments : Hostname
String
Returns : String appended with hostname
Example : my $str = xCAT::zvmUtils->appendHostname($hostname, $str);
=cut
#-------------------------------------------------------
sub appendHostname {
my ( $class, $hostname, $str ) = @_;
# Append hostname to every line
my @outLn = split( "\n", $str );
$str = "";
foreach (@outLn) {
$str .= "$hostname: " . $_ . "\n";
}
return $str;
}
#-------------------------------------------------------
=head3 checkOutput
Description : Check the return of given output
Arguments : Output string
Returns : 0 Good output
-1 Bad output
Example : my $rtn = xCAT::zvmUtils->checkOutput( $out );
=cut
#-------------------------------------------------------
sub checkOutput {
my ( $class, $out ) = @_;
# Check output string
my @outLn = split( "\n", $out );
foreach (@outLn) {
# If output contains 'Failed', or Error return -1
if ( $_ =~ m/Failed/i || $_ =~ m/Error/i ) {
return -1;
}
}
return 0;
}
#-------------------------------------------------------
=head3 checkOutputExtractReason
Description : Check the return of given output. If bad, extract the reason.
Arguments : Output string
Reason (passed as a reference)
Returns : 0 Good output
-1 Bad output
Example : my $rtn = xCAT::zvmUtils->checkOutput( $out, \$reason );
=cut
#-------------------------------------------------------
sub checkOutputExtractReason {
my ( $class, $out, $reason ) = @_;
# Check output string
my @outLn = split("\n", $out);
foreach (@outLn) {
# If output contains 'ERROR: ', return -1 and pass back the reason.
if ($_ =~ /(.*?ERROR: )/) {
$$reason = substr($_, index($_, "ERROR: ") + length("ERROR: "));
return -1;
}
}
return 0;
}
#-------------------------------------------------------
=head3 checkSSH_Rc
Description : Check for SSH errors, and command return code failure
Arguments : $?
command that was issued (do not pass in a password in cmd string, just mask it out)
node the SSH is targeting
function name the SSH call was done in
optional command output
optional final target node (used to prefix "Node: " to error message. Helps in tracing hcp calls on behalf of a node)
optional syslog supression, "NONE", "SSHONLY" defaults to syslog message of any SSH or command error
Returns : rc = 0 Good output
rc = 255 Error occurred in SSH
rc > 0 Command error
$outmsg = error message string if $rc !=0
plus syslog entry for non zero errors
Example : ($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "Command being issued", $hcp, "testfunc", $out, $node, "NONE");
=cut
#-------------------------------------------------------
sub checkSSH_Rc {
my ( $class, $rc, $cmd, $tgtNode, $functionName, $cmdOutput, $finalTargetNode, $syslogOptions ) = @_;
my $msgTxt = '';
my $logit = 2;
if (!defined $cmdOutput) {
$cmdOutput = '';
} elsif ( $cmdOutput ne '' ) {
$cmdOutput = " Output: " . $cmdOutput . " ";
}
if (!defined $finalTargetNode) {
$finalTargetNode = '';
} else {
$finalTargetNode = "Node: " . $finalTargetNode . " ";
}
if (defined $syslogOptions) {
if ( $syslogOptions =~ m/NONE/i ) {
$logit = 0;
} elsif ( $syslogOptions =~ m/SSHONLY/i ) {
$logit = 1;
}
}
$rc = $rc >> 8;
if ( $rc == 255 ) {
# SSH failure to communicate with $tgtNode.
$msgTxt = "$finalTargetNode" . "(Error) In $functionName(), SSH communication to $tgtNode failed for command: $cmd$cmdOutput";
if ($logit > 0 ) {
xCAT::zvmUtils->printSyslog("$msgTxt");
}
return ($rc, $msgTxt);
} elsif ( $rc != 0 ) {
# Generic failure of the command.
$msgTxt = "$finalTargetNode" . "(Error) In $functionName(), command to $tgtNode failed with return code $rc for: $cmd$cmdOutput";
if ($logit > 1 ) {
xCAT::zvmUtils->printSyslog("$msgTxt");
}
return ($rc, $msgTxt);
}
return 0;
}
#-------------------------------------------------------
=head3 getDeviceNode
Description : Get the device node for a given address
Arguments : User (root or non-root)
Node
Disk address
Returns : Device node
Example : my $devNode = xCAT::zvmUtils->getDeviceNode($user, $node, $tgtAddr);
=cut
#-------------------------------------------------------
sub getDeviceNode {
my ( $class, $user, $node, $tgtAddr ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Determine device node
#my $out = `ssh $user\@$node "$sudo cat /proc/dasd/devices" | grep ".$tgtAddr("`;
my $cmd = $sudo . ' cat /proc/dasd/devices';
my $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
return $out;
}
$out = `echo "$out" | egrep -a -i ".$tgtAddr("`;
my @words = split(' ', $out);
my $tgtDevNode;
# /proc/dasd/devices look similar to this:
# 0.0.0100(ECKD) at ( 94: 0) is dasda : active at blocksize: 4096, 1802880 blocks, 7042 MB
# Look for the string 'is'
my $i = 0;
while ($tgtDevNode ne 'is') {
$tgtDevNode = $words[$i];
$i++;
}
return $words[$i];
}
#-------------------------------------------------------
=head3 getDeviceNodeAddr
Description : Get the virtual device address for a given device node
Arguments : User (root or non-root)
Node
Device node
Returns : Virtual device address
Example : my $addr = xCAT::zvmUtils->getDeviceNodeAddr($user, $node, $deviceNode);
=cut
#-------------------------------------------------------
sub getDeviceNodeAddr {
my ( $class, $user, $node, $deviceNode ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Find device node and determine virtual address
# /proc/dasd/devices look similar to this:
# 0.0.0100(ECKD) at ( 94: 0) is dasda : active at blocksize: 4096, 1802880 blocks, 7042 MB
#my $addr = `ssh $user\@$node "$sudo cat /proc/dasd/devices" | grep -i "is $deviceNode"`;
my $cmd = $sudo . ' cat /proc/dasd/devices';
my $addr = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
if (xCAT::zvmUtils->checkOutput( $addr ) == -1) {
return $addr;
}
$addr = `echo "$addr" | egrep -a -i "is $deviceNode"`;
$addr =~ s/ +/ /g;
$addr =~ s/^0.0.([0-9a-f]*).*/$1/;
chomp($addr);
return $addr;
}
#-------------------------------------------------------
=head3 isAddressUsed
Description : Check if a given address is used
Arguments : User (root or non-root)
Node
Disk address
Returns : 0 Address used
-1 Address not used
Example : my $ans = xCAT::zvmUtils->isAddressUsed($user, $node, $address);
=cut
#-------------------------------------------------------
sub isAddressUsed {
my ( $class, $user, $node, $address ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Search for disk address
#my $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q v dasd" | grep "DASD $address"`;
my $cmd = $sudo . ' /sbin/vmcp q v dasd';
my $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
return $out;
}
$out = `echo "$out" | egrep -a -i "DASD $address"`;
if ($out) {
return 0;
}
return -1;
}
#-------------------------------------------------------
=head3 getMacID
Description : Get the MACID from /opt/zhcp/conf/next_macid on the HCP
Arguments : User (root or non-root)
zHCP
Returns : MACID
Example : my $macId = xCAT::zvmUtils->getMacID($user, $hcp);
=cut
#-------------------------------------------------------
sub getMacID {
my ( $class, $user, $hcp ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Check /opt/zhcp/conf directory on HCP
my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo test -d /opt/zhcp/conf && echo 'Directory exists'"`;
if ( $out =~ m/Directory exists/i ) {
# Check next_macid file
$out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo test -e /opt/zhcp/conf/next_macid && echo 'File exists'"`;
if ( $out =~ m/File exists/i ) {
# Do nothing
} else {
# Create next_macid file
$out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo echo 'FFFFF0' > /opt/zhcp/conf/next_macid"`;
}
} else {
# Create /opt/zhcp/conf directory
# Create next_mac - Contains next MAC address to use
$out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo mkdir /opt/zhcp/conf"`;
$out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo echo 'FFFFF0' > /opt/zhcp/conf/next_macid"`;
}
# Read /opt/zhcp/conf/next_macid file
$out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo cat /opt/zhcp/conf/next_macid"`;
my $macId = xCAT::zvmUtils->trimStr($out);
return $macId;
}
#-------------------------------------------------------
=head3 generateMacId
Description : Generate a new MACID
Arguments : User (root or non-root)
zHCP
Returns : Nothing
Example : my $macId = xCAT::zvmUtils->generateMacId($user, $hcp);
=cut
#-------------------------------------------------------
sub generateMacId {
my ( $class, $user, $hcp ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Check /opt/zhcp/conf directory on HCP
my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo test -d /opt/zhcp/conf && echo 'Directory exists'"`;
if ( $out =~ m/Directory exists/i ) {
# Check next_macid file
$out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo test -e /opt/zhcp/conf/next_macid && echo 'File exists'"`;
if ( $out =~ m/File exists/i ) {
# Do nothing
} else {
# Create next_macid file
$out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo echo 'FFFFF0' > /opt/zhcp/conf/next_macid"`;
$out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo /bin/chmod 666 /opt/zhcp/conf/next_macid"`;
}
} else {
# Create /opt/zhcp/conf directory
# Create next_mac - Contains next MAC address to use
$out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo mkdir /opt/zhcp/conf"`;
$out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo echo 'FFFFF0' > /opt/zhcp/conf/next_macid"`;
$out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo /bin/chmod 666 /opt/zhcp/conf/next_macid"`;
}
# Read /opt/zhcp/conf/next_macid file
$out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo cat /opt/zhcp/conf/next_macid"`;
my $macId = xCAT::zvmUtils->trimStr($out);
my $int;
if ($macId) {
# Convert hexadecimal - decimal
$int = hex($macId);
$macId = sprintf( "%d", $int );
# Generate new MAC suffix
$macId = $macId - 1;
# Convert decimal - hexadecimal
$macId = sprintf( "%X", $macId );
# Save new MACID
$out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo echo $macId > /opt/zhcp/conf/next_macid"`;
}
return;
}
#-------------------------------------------------------
=head3 createMacAddr
Description : Create a MAC address using the HCP MAC prefix and a given MAC suffix
Arguments : User (root or non-root)
Node
MAC suffix
Returns : MAC address or string containing (Error)...
Example : my $mac = xCAT::zvmUtils->createMacAddr($user, $node, $suffix);
=cut
#-------------------------------------------------------
sub createMacAddr {
my ( $class, $user, $node, $suffix ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Get node properties from 'zvm' table
my @propNames = ('hcp');
my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
# Get HCP
my $hcp = $propVals->{'hcp'};
if ( !$hcp ) {
return -1;
}
# Get USER Prefix
my $outmsg;
my $rc;
my $prefix;
my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo /sbin/vmcp q vmlan"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh -o ConnectTimeout=5 $user\@$hcp \"$sudo /sbin/vmcp q vmlan\"", $hcp, "createMacAddr", $out, $node );
if ($rc != 0) {
return $outmsg;
}
$prefix = `echo "$out" | egrep -a -i "USER Prefix:"`;
$prefix =~ s/(.*?)USER Prefix:(.*)/$2/;
$prefix =~ s/^\s+//;
$prefix =~ s/\s+$//;
# Get MACADDR Prefix instead if USER Prefix is not defined, use saved out data
if (!$prefix) {
$prefix = `echo "$out" | egrep -a -i "MACADDR Prefix:"`;
$prefix =~ s/(.*?)MACADDR Prefix:(.*)/$2/;
$prefix =~ s/^\s+//;
$prefix =~ s/\s+$//;
if (!$prefix) {
return -1;
}
}
# Generate MAC address of source node
my $mac = $prefix . $suffix;
# 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 );
return $mac;
}
#-------------------------------------------------------
=head3 getOs
Description : Get the operating system of a given node
Arguments : User (root or non-root)
Node
Returns : Operating system name
Example : my $osName = xCAT::zvmUtils->getOs($user, $node);
=cut
#-------------------------------------------------------
sub getOs {
# Get inputs
my ( $class, $user, $node ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Get operating system
#my $out = `ssh -o ConnectTimeout=10 $user\@$node "$sudo cat /etc/*release" | egrep -v "LSB_VERSION"`;
my $cmd = $sudo . ' cat /etc/*release';
my $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
return $out;
}
$out = `echo "$out" | egrep -a -i -v "LSB_VERSION"`;
my @results = split( '\n', $out );
return ( xCAT::zvmUtils->trimStr( $results[0] ) );
}
#-------------------------------------------------------
=head3 getArch
Description : Get the architecture of a given node
Arguments : User (root or non-root)
Node
Returns : Architecture of node
Example : my $arch = xCAT::zvmUtils->getArch($user, $node);
=cut
#-------------------------------------------------------
sub getArch {
# Get inputs
my ( $class, $user, $node ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Get host using VMCP
#my $arch = `ssh $user\@$node "$sudo uname -m"`;
my $cmd = "$sudo uname -m";
my $arch = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
if (xCAT::zvmUtils->checkOutput( $arch ) == -1) {
return $arch;
}
return ( xCAT::zvmUtils->trimStr($arch) );
}
#-------------------------------------------------------
=head3 getUserProfile
Description : Get the user profile
Arguments : User (root or non-root)
Profile name
Returns : User profile
Example : my $profile = xCAT::zvmUtils->getUserProfile($user, $hcp, $name);
=cut
#-------------------------------------------------------
sub getUserProfile {
# Get inputs
my ( $class, $user, $hcp, $profile ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Set directory where executables are on zHCP
my $hcpDir = "/opt/zhcp/bin";
my $out;
# Set directory for cache
my $cache = '/var/opt/zhcp/cache';
# If the cache directory does not exist
if (!(`ssh $user\@$hcp "$sudo test -d $cache && echo Exists"`)) {
# Create cache directory
$out = `ssh $user\@$hcp "$sudo mkdir -p $cache"`;
}
# Set output file name
my $file = "$cache/$profile.profile";
# If a cache for the user profile exists
if (`ssh $user\@$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 $user\@$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 user profiles and save it in a file
$out = `ssh $user\@$hcp "$sudo $hcpDir/smcli Profile_Query_DM -T $profile > $file"`;
}
} else {
# Get user profiles and save it in a file
$out = `ssh $user\@$hcp "$sudo $hcpDir/smcli Profile_Query_DM -T $profile > $file"`;
}
# Return the file contents
$out = `ssh $user\@$hcp "$sudo cat $file"`;
return $out;
}
#-------------------------------------------------------
=head3 getVswitchIdsFromDirectory
Description : Get the nicdef switch names of a given node
Arguments : User (root or non-root)
zHCP
Userid
Returns : Vswitch names array or or string containing (Error)...
Example : my $vSwitchNamers = xCAT::zvmCPUtils->getVswitchIdsFromDirectory($user, $hcp, $userId);
=cut
#-------------------------------------------------------
sub getVswitchIdsFromDirectory {
# Get inputs
my ( $class, $user, $hcp ,$userId ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
my @vswitch;
# Get VSwitchs in directory
# only get lines that have SYSTEM switchname in them
# smcli Image_Definition_Query_DM -T xcat -k nicdef
# NICDEF=VDEV=0600 TYPE=QDIO LAN=SYSTEM SWITCHNAME=XCATVSW1
# NICDEF=VDEV=0700 TYPE=QDIO LAN=SYSTEM SWITCHNAME=XCATVSW2
#
my $outmsg;
my $rc;
xCAT::zvmUtils->printSyslog("Calling: ssh $user\@$hcp $sudo /opt/zhcp/bin/smcli Image_Definition_Query_DM -T $userId -k NICDEF | egrep -i 'SWITCHNAME'");
my $out = `ssh $user\@$hcp "$sudo /opt/zhcp/bin/smcli Image_Definition_Query_DM -T $userId -k NICDEF"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo /opt/zhcp/bin/smcli Image_Definition_Query_DM -T $userId -k NICDEF\"", $hcp, "getVswitchIdsFromDirectory", $out );
if ($rc != 0) {
return $outmsg;
}
$out = `echo "$out" | egrep -a -i 'SWITCHNAME'`;
# if there is nothing found, log that and return;
if ( !length($out) ) {
xCAT::zvmUtils->printSyslog("No SWITCHNAME found in NICDEF statement for userid $userId");
return (@vswitch);
}
xCAT::zvmUtils->printSyslog("$userId output: $out");
my @lines = split( '\n', $out );
my @parms;
my $vswitchToken = '';
foreach (@lines) {
@parms = split( ' ', $_ );
$vswitchToken = $parms[3];
@parms = split( '=', $vswitchToken );
push( @vswitch, $parms[1] );
}
return (@vswitch);
}
#-------------------------------------------------------
=head3 inArray
Description : Checks if a value exists in an array
Arguments : Search value
Search array
Returns : The searched expression
Example : my $rtn = xCAT::zvmUtils->inArray($needle, @haystack);
=cut
#-------------------------------------------------------
sub inArray {
# Get inputs
my ( $class, $needle, @haystack ) = @_;
return grep{ $_ eq $needle } @haystack;
}
#-------------------------------------------------------
=head3 getOsVersion
Description : Get the operating system of a given node
Arguments : User (root or non-root)
Node or IP Address
Callback handle (optional). Allows the routine,
to write error messages when SSH fails.
Returns : Operating system name & version as a single word.
Otherwise, an empty string.
Example : my $os = xCAT::zvmUtils->getOsVersion($user, $node);
my $os = xCAT::zvmUtils->getOsVersion($user, $node, $callback);
=cut
#-------------------------------------------------------
sub getOsVersion {
# Get inputs
my ( $class, $user, $node, $callback ) = @_;
my $osVer = '';
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Contact the system to extract the possible files which contain pertinent data.
#my $releaseInfo = `ssh -qo ConnectTimeout=2 $user\@$node "$sudo ls /dev/null $locAllEtcVerFiles 2>/dev/null | xargs grep ''"`;
my $cmd = $sudo . ' ls /dev/null '. $locAllEtcVerFiles . ' 2>/dev/null';
my $releaseInfo = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd);
if (xCAT::zvmUtils->checkOutput( $releaseInfo ) == -1) {
return '';
}
$releaseInfo = `echo "$releaseInfo" | xargs grep ''`;
$osVer = buildOsVersion( $callback, $releaseInfo, 'all' );
return $osVer;
}
#-------------------------------------------------------
=head3 getOSFromIP
Description : Get the operating system name and
version for the system at the specified
IP Address.
Arguments : Callback handle
z/VM userid of the system
IP Address
Type of IP address (not currently used)
Returns : Operating system name & version as a single word.
Otherwise, an empty string.
Example : my $os = xCAT::zvmUtils->getOSFromIP( $callback, $userid, $ipAddr, $ipVersion };
=cut
#-------------------------------------------------------
sub getOSFromIP {
my ( $class, $callback, $activeSystem, $ipAddr, $ipVersion ) = @_;
my $osVer = '';
my $rc = 0;
# Get operating system
my $releaseInfo = `ssh -qo ConnectTimeout=2 $ipAddr "ls /dev/null $locAllEtcVerFiles 2>/dev/null"`;
$rc = $? >> 8;
if ( $rc == 0 ) {
$releaseInfo = `echo "$releaseInfo" | xargs grep ''`;
$osVer = buildOsVersion( $callback, $releaseInfo, 'all' );
} else {
if ( $callback ) {
# We have a callback so we can write an error message.
if ( $rc == 255 ) {
my $rsp;
push @{$rsp->{data}}, "Unable to communicate with $activeSystem at $ipAddr using ssh.";
xCAT::MsgUtils->message( "E", $rsp, $callback );
} else {
my $rsp;
push @{$rsp->{data}}, "Received an unexpected ssh return code $rc from $activeSystem at $ipAddr.";
xCAT::MsgUtils->message( "E", $rsp, $callback );
}
}
}
return $osVer;
}
#-------------------------------------------------------
=head3 stripHeader
Description : Scans an input string to find only
lines that match a specified header string
and return an array of those lines without
the prefix.
Arguments : Multi-line string to scan
String to match
Returns : Array of matching lines.
Example : my @lines = stripHeader( $releaseInfo, '^/etc/os-release:' );
($ver) = stripHeader( $releaseInfo, "^$locEtcUnitedLinux:" );
=cut
#-------------------------------------------------------
sub stripHeader {
my ( $inputLines, $matchString ) = @_;
my @outputLines;
my @lines = split( /\n/, $inputLines );
foreach my $line ( @lines ){
if ( $line =~ m/$matchString/ ) {
$line =~ s/$matchString//g;
chomp $line;
if ( $line eq '' ) { next }
push @outputLines, $line;
}
}
return @outputLines;
}
#-------------------------------------------------------
=head3 buildOsVersion
Description : Build the OS version string from the
provided data files.
Note: Only RHEL and SLES are supported
z/VM xCAT supported distributions.
This routine has code for other distributions
supported by common xCAT. If z/VM
ever supports another distribution
then we need to verify that the code
gets the correct version information.
Arguments : Callback (or undef)
Operating system data file(s) output
Type of data to return:
'all' - $os$ver.$rel
'all_comma' - $os,$ver.$rel
'os' - $os
'version' - $ver
'release' - $rel
'' - $os$ver
Returns : Operating system name & version as a
single word.
Example : my $osVer = buildOsVersion( $callback, $releaseInfo, $type );
=cut
#-------------------------------------------------------
sub buildOsVersion {
my $callback = shift;
my $releaseInfo = shift;
my $type = shift;
my $os = 'unknown'; # OS indicator, e.g. "rhel", "SLES"
my $ver = ''; # Version indicator, e.g. "7.1",
my $version = '';
my $rel = '';
my $line = '';
my @lines;
# Test strings that were used when we added the original support. These
# strings are what we used to simulate the other common Linux distros.
#$releaseInfo = "$locEtcSuseRelease:SUSE Linux Enterprise Server 11 (s390x)\n$locEtcSuseRelease:VERSION = 11\n$locEtcSuseRelease:PATCHLEVEL = 4.32";
#$releaseInfo = "$locEtcDebianVersion:1.0\n$locEtcIssue:debian release";
#$releaseInfo = "$locEtcUnitedLinux:2.1a";
#$releaseInfo = "$locEtcLsbRelease:Ubuntu\n$locEtcLsbRelease: DISTRIB_ID=Ubuntu\n$locEtcLsbRelease: DISTRIB_RELEASE=4.1";
my @relOut = split('\n', $releaseInfo);
if ( grep( /^$locEtcOsRelease:/, @relOut ) ) {
my $version = '';
my $version_id;
my $id;
my $id_like;
my $name;
my $prettyname;
my $verrel = '';
my @text = stripHeader( $releaseInfo, "^$locEtcOsRelease:" );
foreach my $line ( @text ) {
if ( $line =~ /^\s*VERSION=\"?([0-9\.]+).*/ ) {
$version = $1;
}
if($line =~ /^\s*VERSION_ID=\"?([0-9\.]+).*/){
$version_id = $1;
}
if ( $line =~ /^\s*Base release\s?([0-9\.]+).*/ ) {
$version = $1;
$id = 'BASE';
}
if ( $line =~ /^\s*ID=\"?([0-9a-z\_\-\.]+).*/ ) {
$id = $1;
}
if ( $line =~ /^\s*ID_LIKE=\"?([0-9a-z\_\-\.]+).*/ ) {
$id_like = $1;
}
if ( $line =~ /^\s*NAME=\"?(.*)/ ) {
$name = $1;
}
if($line =~ /^\s*PRETTY_NAME=\"?(.*)/){
$prettyname = $1;
}
}
$os = $id;
if ( !$os and $id_like ) {
$os = $id_like;
}
$verrel = $version;
if ( !$verrel and $version_id ) {
$verrel = $version_id;
}
if( !$name and $prettyname ){
$name = $prettyname;
}
# Note: xcat::Utils->osver() sets this value with an 's' but zvm.pm
# does not use it. So for now, we don't set 's'.
#if ( $os =~ /rhel/ and $name =~ /Server/i ) {
# # $os = "rhels";
#}
if ( $verrel =~ /([0-9]+)\.?(.*)/ ) {
$ver = $1;
$rel = $2;
}
} elsif ( grep( /^$locEtcRedhatRelease:/, @relOut ) ) {
my @text = stripHeader( $releaseInfo, "^$locEtcRedhatRelease:" );
my $line = $text[0];
chomp( $line );
$os = "rh";
my $verrel = $line;
$ver = $line;
if ( $type ) {
$verrel =~ s/[^0-9]*([0-9.]+).*/$1/;
($ver,$rel) = split /\./, $verrel;
} else {
$ver=~ tr/\.//;
$ver =~ s/[^0-9]*([0-9]+).*/$1/;
}
if ( $line =~ /AS/ ) { $os = 'rhas' }
elsif ( $line =~ /ES/ ) { $os = 'rhes' }
elsif ( $line =~ /WS/ ) { $os = 'rhws' }
elsif ( $line =~ /Server/ ) {
if ( $type ) {
$os = 'rhel';
# Note: xcat::Utils->osver() sets this value with an 's' but zvm.pm
# does not use it. So for now, we don't set 's'.
#$os = 'rhels';
} else {
$os = 'rhserver';
}
} elsif ( $line =~ /Client/ ) {
if ( $type ) {
$os = 'rhel';
} else {
$os = 'rhclient';
}
} elsif ( grep( /$locEtcFedoraRelease:/, @relOut ) ) { $os = 'rhfc' }
} elsif ( grep( /^$locEtcSuseRelease:/, @relOut ) ) {
my @lines = stripHeader( $releaseInfo, "^$locEtcSuseRelease:" );
if ( grep /SLES|Enterprise Server/, @lines ) { $os = "sles" }
if ( grep /SLEC/, @lines ) { $os = "slec" }
$ver = $lines[0];
$ver =~ tr/\.//;
$ver =~ s/[^0-9]*([0-9]+).*/$1/;
$rel = $lines[2];
$rel =~ tr/\.//;
$rel =~ s/[^0-9]*([0-9]+).*/$1/;
} elsif ( grep( /^$locEtcUnitedLinux:/, @relOut ) ) {
# Note: Not a z/VM xCAT supported distribution.
# If we ever support this then we need to verify this code
# gets the correct version information.
($ver) = stripHeader( $releaseInfo, "^$locEtcUnitedLinux:" );
$os = "ul";
$ver =~ tr/\.//;
$ver =~ s/[^0-9]*([0-9]+).*/$1/;
} elsif ( grep( /$locEtcLsbRelease:/, @relOut ) ) {
# Ubuntu release
my @text = stripHeader( $releaseInfo, "^$locEtcLsbRelease:" );
chomp( @text );
my $distrib_id = '';
my $distrib_rel = '';
foreach ( @text ) {
if ( $_ =~ /^\s*DISTRIB_ID=(.*)$/ ) {
$distrib_id = $1; # last DISTRIB_ID value in file used
} elsif ( $_ =~ /^\s*DISTRIB_RELEASE=(.*)$/ ) {
$distrib_rel = $1; # last DISTRIB_RELEASE value in file used
}
}
if ( $distrib_id =~ /^(Ubuntu|"Ubuntu")\s*$/ ) {
$os = "ubuntu";
if ( $distrib_rel =~ /^(.*?)\s*$/ ) { # eliminate trailing blanks, if any
$distrib_rel = $1;
}
if ( $distrib_rel =~ /^"(.*?)"$/ ) { # eliminate enclosing quotes, if any
$distrib_rel = $1;
}
$ver = $distrib_rel;
}
} elsif ( grep( /^$locEtcDebianVersion:/, @relOut ) ) {
# Debian release
if ( grep( /^$locEtcIssue:/, @relOut ) ) {
($line) = stripHeader( $releaseInfo, "^$locEtcIssue:" );
if ( $line =~ /debian.*/i ) {
$os = "debian";
($ver) = stripHeader( $releaseInfo, "^$locEtcDebianVersion:" );
}
}
}
my $outString = '';
if ( $type eq 'all_comma' ) {
if ( $rel ne "") {
$outString = "$os,$ver.$rel";
} else {
$outString = "$os,$ver";
}
} elsif ( $type eq 'all' ) {
if ( $rel ne "") {
$outString = "$os$ver.$rel";
} else {
$outString = "$os$ver";
}
} elsif ( $type eq 'os' ) {
$outString = $os;
} elsif ( $type eq 'version' ) {
$outString = $ver;
} elsif ( $type eq 'release' ) {
$outString = $os;
} else {
$outString = "$os$ver";
}
return $outString;
}
#-------------------------------------------------------
=head3 getZfcpInfo
Description : Get the zFCP device info
Arguments : User (root or non-root)
Node
Returns : zFCP device info
Example : my $info = xCAT::zvmUtils->getZfcpInfo($user, $node);
=cut
#-------------------------------------------------------
sub getZfcpInfo {
# Get inputs
my ( $class, $user, $node ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Get zFCP device info
#my $info = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/lszfcp -D"`;
my $cmd = "$sudo /sbin/lszfcp -D";
my $info = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
# will not check for connection errors here
my @zfcp = split("\n", $info);
if (!$info || $info =~ m/No zfcp support/i || $info =~ m/No fcp devices found/i) {
return;
}
# Get SCSI device and their attributes
#my $scsi = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /usr/bin/lsscsi"`;
$cmd = "$sudo /usr/bin/lsscsi";
my $scsi = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
if (xCAT::zvmUtils->checkOutput( $info ) == -1) {
return $info;
}
$info = "";
my @args;
my $tmp;
my $id;
my $device;
my $wwpn;
my $lun;
my $size;
foreach (@zfcp) {
@args = split(" ", $_);
$id = $args[1];
@args = split("/", $args[0]);
$device = $args[0];
$wwpn = $args[1];
$lun = $args[2];
# Make sure WWPN and LUN do not have 0x prefix
$wwpn = xCAT::zvmUtils->replaceStr($wwpn, "0x", "");
$lun = xCAT::zvmUtils->replaceStr($lun, "0x", "");
# Find the device name
$tmp = `echo "$scsi" | egrep -i $id`;
$tmp = substr($tmp, index($tmp, "/dev/"));
chomp($tmp);
# Find the size in MiB
#$size = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /usr/bin/sg_readcap $tmp" | egrep -i "Device[[:space:]]size:"`;
my $cmd = $sudo . ' /usr/bin/sg_readcap ' . $tmp;
$size = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
if (xCAT::zvmUtils->checkOutput( $size ) == -1) {
return $size;
}
$size = `echo "$size" | egrep -a -i "Device[[:space:]]size:"`;
$size =~ s/Device size: //g;
@args = split(",", $size);
$size = xCAT::zvmUtils->trimStr($args[1]);
$info .= "Device: $device WWPN: 0x$wwpn LUN: 0x$lun Size: $size\n";
}
$info = xCAT::zvmUtils->tabStr($info);
return ($info);
}
#-------------------------------------------------------
=head3 isHypervisor
Description : Determines if a given node is in the 'hypervisor' table
Arguments : Node
Returns : 1 Node exists
0 Node does not exists
Example : my $out = xCAT::zvmUtils->isHypervisor($node);
=cut
#-------------------------------------------------------
sub isHypervisor {
# Get inputs
my ( $class, $node ) = @_;
# Look in 'zvm' table
my $tab = xCAT::Table->new( "hypervisor", -create => 1, -autocommit => 0 );
my @results = $tab->getAllAttribsWhere( "node = '" . $node . "'", 'type' );
foreach (@results) {
# Return 'TRUE' if given node is in the table
if ($_->{"type"} eq "zvm") {
return 1;
}
}
return 0;
}
#-------------------------------------------------------
=head3 isOSVerSupported
Description : Determine if the specified OS version supported.
Arguments : OS version string (e.g. RHEL6, RHEL6.1, SLES11sp2)
Returns : 1 - version is supported
0 - version is not supported
Example : my $supported = xCAT::zvmUtils->isOSVerSupported( $os );
=cut
#-------------------------------------------------------
sub isOSVerSupported {
my ( $class, $osVer ) = @_;
# Keep just the OS distro name and the version, ie. drop any release info.
$osVer = lc( $osVer );
if ( $osVer =~ /([a-z]+[0-9]+)/ ) {
$osVer = $1;
}
# Check against our list of supported versions.
if ( $supportedVersions{$osVer} ) {
return 1;
} else {
return 0;
}
}
#-------------------------------------------------------
=head3 getSudoer
Description : Retrieve sudoer user name
Arguments : Node
Returns : Sudoer user name
Sudo keyword
Example : my ($sudoer, $sudo) = xCAT::zvmUtils->getSudoer();
=cut
#-------------------------------------------------------
sub getSudoer {
# Get inputs
my ( $class ) = @_;
# Use sudo or not on zHCP
my @propNames = ('username');
my $propVals = xCAT::zvmUtils->getTabPropsByKey( 'passwd', 'key', 'sudoer', @propNames );
my $sudo = "sudo";
my $user = $propVals->{'username'};
if (!$user) {
$user = "root";
}
if ($user eq "root") {
$sudo = "";
}
return ($user, $sudo);
}
#-------------------------------------------------------
=head3 getFreeAddress
Description : Get a free(unused) virtual address
Arguments : User (root or non-root)
Node
Type (vmcp or non-vmcp)
Returns : vdev An address which is free to use
-1 No free address is left
Example : my $vdev = xCAT::zvmUtils->getFreeAddress($user, $node, $type);
=cut
#-------------------------------------------------------
sub getFreeAddress {
my ( $class, $user, $node, $type ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Although 0000 maybe is free, we do not use it
my $freeAddress = 1;
my $freeAddressHex = sprintf('%04X', $freeAddress);
# All device type names in VM, do not contain CPU
#my $deviceTypesVm = 'CONS|CTCA|DASD|FCP|GRAF|LINE|MSGD|OSA|PRT|PUN|RDR|SWCH|TAPE';
my $deviceTypesVm = '^CONS|^CTCA|^DASD|^FCP|^GRAF|^LINE|^MSGD|^OSA|^PRT|^PUN|^RDR|^SWCH|^TAPE';
# All device type names in user directory, do not contain CPU
my $deviceTypesUserDir = 'CONSOLE|MDISK|NICDEF|SPOOL|RDEVICE';
# Search for all address that is in use
my $allUsedAddr;
if ($type eq 'vmcp') {
# When the node is up, vmcp can be used
#$allUsedAddr = `ssh -o ConnectTimeout=5 $user\@$node "$sudo /sbin/vmcp q v all | awk '\$1 ~/^($deviceTypesVm)/ {print \$2}' | sort"`;
my $cmd = $sudo . '/sbin/vmcp q v all';
my $allUsedAddr = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
if (xCAT::zvmUtils->checkOutput( $allUsedAddr ) == -1) {
return -1;
}
$allUsedAddr = `echo '$allUsedAddr' | egrep -a -i "$deviceTypesVm"`;
} else {
# When the node is down, use zHCP to get its user directory entry
# Get HCP
my @propNames = ('hcp', 'userid');
my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
my $hcp = $propVals->{'hcp'};
# Get node userID
my $userId = $propVals->{'userid'};
# Get user directory entry
my $userDirEntry = `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Query_DM -T $userId"`;
# Get profile if user directory entry include a profile
if ($userDirEntry =~ "INCLUDE ") {
my $profileName = `cat $userDirEntry | awk '\$1 ~/^(INCLUDE)/ {print \$2}'`;
$profileName = xCAT::zvmUtils->trimStr($profileName);
$userDirEntry .= `ssh $::SUDOER\@$hcp "$::SUDO $::DIR/smcli Image_Query_DM -T $profileName"`;
}
# Get all defined device address
$allUsedAddr = `cat $userDirEntry | awk '\$1 ~/^($deviceTypesUserDir)/ {print \$2}' | sort`;
# Get all linked device address
$allUsedAddr .= `cat $userDirEntry | awk '\$1 ~/^(LINK)/ {print \$4}' | sort`;
}
# Loop to get the lowest free address
while ($freeAddress < 65536 && $allUsedAddr =~ $freeAddressHex) {
$freeAddress++;
$freeAddressHex = sprintf('%04X', $freeAddress);
}
if ($freeAddress < 65536) {
return $freeAddressHex;
}
return -1;
}
#-------------------------------------------------------
=head3 getUsedCpuTime
Description : Get used CPU time of instance
Arguments : User (root or non-root)
zHCP (to query on)
node
Returns : In nanoseconds for used CPU time or string containing (Error)...
Example : my $out = xCAT::zvmUtils->getUsedCpuTime($hcp, $node);
=cut
#-------------------------------------------------------
sub getUsedCpuTime {
my ( $class, $user, $hcp , $node ) = @_;
# Directory where executables are
my $dir = '/opt/zhcp/bin';
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
my $userId = xCAT::zvmCPUtils->getUserId($user, $node);
# Call IUO function to query CPU used time
my $outmsg;
my $rc;
my $time = `ssh $user\@$hcp "$sudo $dir/smcli Image_Performance_Query -T $userId -c 1"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo $dir/smcli Image_Performance_Query -T $userId -c 1\"", $hcp, "getUsedCpuTime", $time, $node );
if ($rc != 0) {
return $outmsg;
}
$time = `echo "$time" | egrep -a -i "Used CPU time:"`;
$time =~ s/^Used CPU time:(.*)/$1/;
$time =~ s/"//g;
$time =~ s/^\s+//;
$time =~ s/\s+$//;
if (!$time) {
$time = 0;
}
# Not found, return 0
return $time;
}
#-------------------------------------------------------
=head3 getUpTime
Description : Get running time of an instance
Arguments : User (root or non-root)
Node
Returns : Running time
Example : my $out = xCAT::zvmUtils->getUpTime($user, $node);
=cut
#-------------------------------------------------------
sub getUpTime {
my ( $class, $user, $node ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
#my $out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo uptime"`;
my $cmd = "$sudo uptime";
my $out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
if (xCAT::zvmUtils->checkOutput( $out ) == -1) {
return $out;
}
$out = xCAT::zvmUtils->trimStr($out);
$out =~ /.*up +(?:(\d+) days?,? +)?(\d+):(\d+),.*/;
my $uptime;
if (!$1 && !$2) {
# Special case for less than 1 hour, will display X min
$out =~ /.*up +(\d+) min,.*/;
$uptime = "0 days $3 min";
} elsif (!$1) {
# Special case for less than 1 day, will display X hr X min
$uptime = "0 days $2 hr $3 min";
} else {
$uptime = "$1 days $2 hr $3 min";
}
return ($uptime);
}
#-------------------------------------------------------
=head3 getSizeFromByte
Description : Return disk size (G or M) from given bytes
Arguments : Bytes
Returns : Size string
Example : my $out = xCAT::zvmUtils->getSizeFromByte($bytes);
=cut
#-------------------------------------------------------
sub getSizeFromByte {
my ( $class, $bytes ) = @_;
my $size = ($bytes)/(1024*1024);
if ($size > (1024*5)) {
$size = ($size / 1024);
# If the size > 5G, will use G to represent
$size = sprintf("%.1f",$size);
$size = $size . 'G';
} else {
# If the size < 5G, will use M to represent
$size = sprintf("%d",$size);
$size = $size . 'M';
}
return ($size);
}
#-------------------------------------------------------
=head3 getSizeFromCyl
Description : Return disk size (G or M) from given cylinders
Arguments : Node
Returns : Size string
Example : my $out = xCAT::zvmUtils->getSizeFromCyl($cyl);
=cut
#-------------------------------------------------------
sub getSizeFromCyl {
my ($class, $cyl) = @_;
my $bytes = ($cyl * 737280);
my $size = xCAT::zvmUtils->getSizeFromByte($bytes);
return ($size);
}
#-------------------------------------------------------
=head3 getSizeFromPage
Description : Return disk size (G or M) from given pages
Arguments : Page
Returns : Size string
Example : my $out = xCAT::zvmUtils->getSizeFromPage($page);
=cut
#-------------------------------------------------------
sub getSizeFromPage {
my ( $class, $page ) = @_;
my $bytes = ($page * 4096);
my $size = xCAT::zvmUtils->getSizeFromByte($bytes);
return ($size);
}
#-------------------------------------------------------
=head3 getLparCpuTotal
Description : Get total count of logical CPUs in the LPAR
Arguments : User (root or non-root)
zHCP
Returns : Total CPU count or string containing (Error)...
Example : my $out = xCAT::zvmCPUtils->getLparCpuTotal($user, $hcp);
=cut
#-------------------------------------------------------
sub getLparCpuTotal {
my ($class, $user, $hcp) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
my $outmsg;
my $rc;
my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo cat /proc/sysinfo"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh -o ConnectTimeout=5 $user\@$hcp \"$sudo cat /proc/sysinfo\"", $hcp, "getLparCpuTotal", $out );
if ($rc != 0) {
return $outmsg;
}
$out = `echo "$out" | egrep -a -i "LPAR CPUs Total"`;
my @results = split(' ', $out);
return ($results[3]);
}
#-------------------------------------------------------
=head3 getLparCpuUsed
Description : Get count of used logical CPUs in the LPAR
Arguments : User (root or non-root)
zHCP
Returns : Used CPU count or string containing (Error)...
Example : my $out = xCAT::zvmCPUtils->getLparCpuUsed($user, $hcp);
=cut
#-------------------------------------------------------
sub getLparCpuUsed {
my ($class, $user, $hcp) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
my $outmsg;
my $rc;
my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo cat /proc/sysinfo"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh -o ConnectTimeout=5 $user\@$hcp \"$sudo cat /proc/sysinfo\"", $hcp, "getLparCpuUsed", $out );
if ($rc != 0) {
return $outmsg;
}
$out = `echo "$out" | egrep -a -i "LPAR CPUs Configured"`;
my @results = split(' ', $out);
return ($results[3]);
}
#-------------------------------------------------------
=head3 getCecModel
Description : Get the model of this CEC (LPAR)
Arguments : User (root or non-root)
zHCP
Returns : Model of this CEC or string containing (Error)...
Example : my $out = xCAT::zvmCPUtils->getCecModel($user, $hcp);
=cut
#-------------------------------------------------------
sub getCecModel {
my ($class, $user, $hcp) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
my $outmsg;
my $rc;
my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo cat /proc/sysinfo"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh -o ConnectTimeout=5 $user\@$hcp \"$sudo cat /proc/sysinfo\"", $hcp, "getCecModel", $out );
if ($rc != 0) {
return $outmsg;
}
$out = `echo "$out" | egrep -a -i "^Type:"`;
my @results = split(' ', $out);
return ($results[1]);
}
#-------------------------------------------------------
=head3 getCecVendor
Description : Get the vendor of this CEC (LPAR)
Arguments : User (root or non-root)
zHCP
Returns : Vendor of this CEC or string containing (Error)...
Example : my $out = xCAT::zvmCPUtils->getCecVendor($user, $hcp);
=cut
#-------------------------------------------------------
sub getCecVendor {
my ( $class, $user, $hcp ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
my $outmsg;
my $rc;
my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo cat /proc/sysinfo"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh -o ConnectTimeout=5 $user\@$hcp \"$sudo cat /proc/sysinfo\"", $hcp, "getCecVendor", $out );
if ($rc != 0) {
return $outmsg;
}
$out = `echo "$out" | egrep -a -i "Manufacturer"`;
my @results = split(' ', $out);
return ($results[1]);
}
#-------------------------------------------------------
=head3 getHypervisorInfo
Description : Get the info(name & version) for this hypervisor
Arguments : User (root or non-root)
zHCP
Returns : Name & version of this hypervisor or string containing (Error)...
Example : my $out = xCAT::zvmCPUtils->getHypervisorInfo($user, $hcp);
=cut
#-------------------------------------------------------
sub getHypervisorInfo {
my ($class, $user, $hcp) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
my $outmsg;
my $rc;
my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo cat /proc/sysinfo"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh -o ConnectTimeout=5 $user\@$hcp \"$sudo cat /proc/sysinfo\"", $hcp, "getHypervisorInfo", $out );
if ($rc != 0) {
return $outmsg;
}
$out = `echo "$out" | egrep -a -i "VM00 Control Program"`;
my @results = split(' ', $out);
my $str = "$results[3] $results[4]";
return ($str);
}
#-------------------------------------------------------
=head3 getLparMemoryTotal
Description : Get the total physical memory of this LPAR
Arguments : User (root or non-root)
zHCP
Returns : Total physical memory or string containing (Error)...
Example : my $out = xCAT::zvmCPUtils->getLparMemoryTotal($user, $hcp);
=cut
#-------------------------------------------------------
sub getLparMemoryTotal {
my ($class, $user, $hcp) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
my $outmsg;
my $rc;
my $out = `ssh $user\@$hcp "$sudo /opt/zhcp/bin/smcli System_Info_Query"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo /opt/zhcp/bin/smcli System_Info_Query\"", $hcp, "getLparMemoryTotal", $out );
if ($rc != 0) {
return $outmsg;
}
$out = `echo "$out" | egrep -a -i "real storage"`;
my @results = split(' ', $out);
return ($results[5]);
}
#-------------------------------------------------------
=head3 getLparMemoryOffline
Description : Get the offline physical memory of this LPAR
Arguments : User (root or non-root)
zHCP
Returns : Offline physical memory or string containing (Error)...
Example : my $out = xCAT::zvmCPUtils->getLparMemoryOffline($user, $hcp);
=cut
#-------------------------------------------------------
sub getLparMemoryOffline {
my ($class, $user, $hcp) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
my $outmsg;
my $rc;
my $out = `ssh $user\@$hcp "$sudo /opt/zhcp/bin/smcli System_Info_Query"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo /opt/zhcp/bin/smcli System_Info_Query\"", $hcp, "getLparMemoryOffline", $out );
if ($rc != 0) {
return $outmsg;
}
$out = `echo "$out" | egrep -a -i "real storage"`;
my @results = split(' ', $out);
return ($results[14]);
}
#-------------------------------------------------------
=head3 getLparMemoryUsed
Description : Get the used physical memory of this LPAR
Arguments : User (root or non-root)
zHCP
Returns : Used physical memory or string containing (Error)...
Example : my $out = xCAT::zvmCPUtils->getLparMemoryUsed($user, $hcp);
=cut
#-------------------------------------------------------
sub getLparMemoryUsed {
my ($class, $user, $hcp) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
my $outmsg;
my $rc;
my $out = `ssh $user\@$hcp "$sudo /opt/zhcp/bin/smcli System_Performance_Info_Query "`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo /opt/zhcp/bin/smcli System_Performance_Info_Query \"", $hcp, "getLparMemoryUsed", $out );
if ($rc != 0) {
return $outmsg;
}
$out = `echo "$out" | egrep -a -i "Used memory pages:"`;
my @results = split(':', $out);
my $page = xCAT::zvmUtils->trimStr( $results[1] );
my $size = xCAT::zvmUtils->getSizeFromPage( $page );
return ($size);
}
#-------------------------------------------------------
=head3 getDiskPoolUsed
Description : Get the used size of specified disk pool
Arguments : User (root or non-root)
zHCP
Disk pool
Returns : Used size of specified disk pool
Example : my $out = xCAT::zvmCPUtils->getDiskPoolUsed($user, $hcp, $diskpool);
=cut
#-------------------------------------------------------
sub getDiskPoolUsed {
my ($class, $user, $hcp, $diskpool) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
my $hcpUserId = xCAT::zvmCPUtils->getUserId($user, $hcp);
my $out = `ssh $user\@$hcp "$sudo /opt/zhcp/bin/smcli Image_Volume_Space_Query_DM -q 3 -e 3 -n $diskpool -T $hcpUserId"`;
my @lines = split('\n', $out);
my @results;
my $used = 0;
foreach (@lines) {
@results = split(' ', $_);
if ($results[1] =~ '^9336') {
# Change the format from blocks (512 byte) to cylinder (737280)
my $cyls = ($results[3] * 512)/(737280);
$used += $cyls;
} elsif ($results[1] =~ '^3390') {
$used += $results[3];
}
}
return ($used);
}
#-------------------------------------------------------
=head3 getDiskPoolFree
Description : Get the free size of specified disk pool
Arguments : User (root or non-root)
zHCP
Disk pool
Returns : Free size of specified disk pool
Example : my $out = xCAT::zvmCPUtils->getDiskPoolFree($user, $hcp, $diskpool);
=cut
#-------------------------------------------------------
sub getDiskPoolFree {
my ($class, $user, $hcp, $diskpool) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
my $hcpUserId = xCAT::zvmCPUtils->getUserId($user, $hcp);
my $out = `ssh $user\@$hcp "$sudo /opt/zhcp/bin/smcli Image_Volume_Space_Query_DM -q 2 -e 3 -n $diskpool -T $hcpUserId"`;
my @lines = split('\n', $out);
my @results;
my $free = 0;
foreach (@lines) {
@results = split(' ', $_);
if ($results[1] =~ '^9336') {
# Change the format from blocks (512 byte) to cylinder (737280)
my $cyls = ( $results[3] * 512 ) / ( 737280 );
$free += $cyls;
} elsif ($results[1] =~ '^3390') {
$free += $results[3];
}
}
return ($free);
}
#-------------------------------------------------------
=head3 getMaxMemory
Description : Get the max memory of a given node
Arguments : User (root or non-root)
zHCP
Node
Returns : Max memory
Example : my $maxMemory = xCAT::zvmCPUtils->getMaxMemory($user, $hcp, $node);
=cut
#-------------------------------------------------------
sub getMaxMemory {
my ($class, $user, $hcp , $node) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
my $userId = xCAT::zvmCPUtils->getUserId( $user, $node );
# Query the maximum memory allowed in user directory entry
my $out = `ssh $user\@$hcp "$sudo /opt/zhcp/bin/smcli Image_Definition_Query_DM -T $userId -k STORAGE_MAXIMUM"`;
my @results = split('=', $out);
return ($results[1]);
}
#-------------------------------------------------------
=head3 handlePowerUp
Description : Handle power up of nodes whose IP information
may change on power up. The routine will weed out
non-s390x architectures and do processing for nodes whose
status in the zvm table is "POWER_UP=1".
Arguments : Callback
Nodes that are to be handled.
Returns : None
Example : xCAT::zvmUtils->handlePowerUp( $callback, $nodes, \%args );
=cut
#-------------------------------------------------------
sub handlePowerUp {
my ( $class, $callback, $nodes, $argsRef ) = @_;
my %propHash; # Property hash used to fill in various tables
my %sysInfo; # Hash to hold system information
my %args = %$argsRef; # Command arguments, verbose is one such operand
my $nodetypeTab = xCAT::Table->new('nodetype');
my $nodetypeHash = $nodetypeTab->getNodesAttribs( $nodes, ['arch'] );
my $zvmTab = xCAT::Table->new('zvm');
my $zvmHash = $zvmTab->getNodesAttribs( $nodes, ['hcp', 'status', 'userid'] );
foreach my $node ( keys %{$nodetypeHash} ) {
next if ( $nodetypeHash->{$node}->[0]->{'arch'} !~ 's390x' );
my $status = $zvmHash->{$node}->[0]->{'status'};
if ( $status =~ 'POWER_UP=1' ) {
my $userid = $zvmHash->{$node}->[0]->{'userid'};
my $rc = xCAT::zvmUtils->findAccessIP( $callback,
$userid,
$zvmHash->{$node}->[0]->{'hcp'},
\%sysInfo,
\%args );
if ( $rc == 0 ) {
# Got what we needed so we can update tables with the current information.
if ( $args{'verbose'} == 1 ) {
my $rsp;
push @{$rsp->{data}}, "Updating xCAT tables with IP information for $node:\n" .
" ip: $sysInfo{$userid}{'ipAddr'}, hostname: $sysInfo{$userid}{'hostname'}\n".
" macAddr: $sysInfo{$userid}{'macAddr'}, switch: $sysInfo{$userid}{'switch'}\n".
" Network Adapter VDEV: $sysInfo{$userid}{'adapterAddr'}";
xCAT::MsgUtils->message( "I", $rsp, $callback );
}
substr( $sysInfo{$userid}{'macAddr'}, 10, 0 ) = ':';
substr( $sysInfo{$userid}{'macAddr'}, 8, 0 ) = ':';
substr( $sysInfo{$userid}{'macAddr'}, 6, 0 ) = ':';
substr( $sysInfo{$userid}{'macAddr'}, 4, 0 ) = ':';
substr( $sysInfo{$userid}{'macAddr'}, 2, 0 ) = ':';
%propHash = (
'disable' => 0,
'interface' => $sysInfo{$userid}{'vdev'},
'mac' => $sysInfo{$userid}{'macAddr'},
);
xCAT::zvmUtils->setNodeProps( 'mac', $node, \%propHash );
%propHash = (
'disable' => 0,
'hostnames' => $sysInfo{$userid}{'hostname'},
'ip' => $sysInfo{$userid}{'ipAddr'},
);
xCAT::zvmUtils->setNodeProps( 'hosts', $node, \%propHash );
$status =~ s/POWER_UP=1/POWER_UP=0/g;
%propHash = (
'status' => $status,
);
xCAT::zvmUtils->setNodeProps( 'zvm', $node, \%propHash );
my $out = `/opt/xcat/sbin/makehosts $node 2>&1`;
if ( $out ne '' ) {
my $rsp;
push @{$rsp->{data}}, "'makehosts' failed for $node. " .
"'makehosts' response: $out";
xCAT::MsgUtils->message( "E", $rsp, $callback );
}
# Inform OpenStack of the hostname.
if ( -e $locOpenStackUpdateName ) {
# Call the python change instance name command
my $renamed = 0;
my $args = "--nodename $node --hostname $sysInfo{$userid}{'hostname'}";
xCAT::MsgUtils->message( "S", "Invoking $locOpenStackUpdateName $args" );
my $out = `python $locOpenStackUpdateName $args`;
xCAT::MsgUtils->message( "S", "Returned from OpenStack node name update for $node with $out" );
if ( $out ) {
if ( $out =~ m/^Success!/ ) {
$renamed = 1;
if ( $args{'verbose'} == 1 ) {
my $rsp;
push @{$rsp->{data}}, "Renamed the OpenStack instance.";
xCAT::MsgUtils->message("I", $rsp, $callback);
}
}
}
if ( !$renamed ) {
# Return an information message but do not fail the nodeset with an error
# message. This error is minor to the overall operation.
my $rsp;
push @{$rsp->{data}}, "Unable to update the OpenStack node name: $node";
xCAT::MsgUtils->message("I", $rsp, $callback);
}
}
} else {
my $rsp;
push @{$rsp->{data}}, "Did not find sufficient IP information for $node.";
xCAT::MsgUtils->message( "I", $rsp, $callback );
}
}
}
}
#-------------------------------------------------------
=head3 findAccessIP
Description : Obtain TCP/IP and hostname information about
the virtual machine related to the node.
Arguments : Callback in case we want to produce a message
Virtual machine userid
ZHCP node handling the z/VM host node
Hash to contain information on the system
Command invocation argument hash. 'ipfilter' and
'verbose' keys are used in this routine.
SUDO issuer ($sudoer) or 'root' user for the SSH into ZHCP.
This parameter avoids the call to getsudoer() to obtain
the sudo and sudoer value. 'root' user does not use 'sudo'.
Returns : 0 - No error
non-zero - Error detected or filtered out as a usable IP address
Example : $rc = findAccessIP( $callback, 'linux001', $hcp
\%sysInfo, \%args );
=cut
#-------------------------------------------------------
sub findAccessIP
{
my $class = shift; # Perl class
my $callback = shift; # Callback for messaging
my $activeSystem = shift; # Userid of the system being queried
my $hcp = shift; # HCP
my $sysInfoRef = shift; # Hash reference for system IP information
my $argsRef = shift; # Command arguments, verbose, ipFilter
my %args = %$argsRef; # Access hash for easier reference
my $sudoer = shift; # SUDO issuer
my %adapter; # Adapter hash info, used mainly for verbose processing
my @failureInfo; # Information on IP contact failures
my $hostname = ''; # Hostname from the target node
my @hostnameCmds = ( # List of host name resolution commands to be issued in a virtual OS.
'hostname --fqdn',
'hostname --long',
'hostname',
);
my %ips; # Hash of IP info obtained from the various calls
my $out; # Output buffer work area
my $rc; # Return code
my $rsp; # Message work buffer
my $sudo = ''; # Assume we are not going to use SUDO on ZHCP call.
# Use sudo or not
if ( $sudoer eq '' ) {
# Looks in the passwd table for a key = sudoer.
($sudoer, $sudo) = xCAT::zvmUtils->getSudoer();
} elsif ( $sudoer ne 'root' ) {
# Non-root user specified so we will invoke 'sudo' on the SSH call to ZHCP.
$sudo = 'sudo';
}
# Get the list of IP addresses currently in use by the virtual machine.
$out = `ssh -q $sudoer\@$hcp $sudo /opt/zhcp/bin/smcli "Virtual_Network_Adapter_Query_Extended -T '$activeSystem' -k 'image_device_number=*'"`;
$rc = $? >> 8;
if ($rc == 255) {
push @{$rsp->{data}}, "Unable to communicate with the zhcp system: $hcp";
xCAT::MsgUtils->message("E", $rsp, $callback);
goto FINISH_findAccessIP;
} elsif ( $rc == 1 ) {
my ( $smcliRC, $smcliRS, $smcliDesc );
my $errorOut = `echo "$out" | egrep -i '(^ Return Code: |^ Reason Code: |^ Description: )'`;
my @errorLines = split( "\n", $errorOut );
foreach my $errorLine ( @errorLines ) {
if ( $errorLine =~ /^ Return Code: / ) {
($smcliRC) = $errorLine =~ /^ Return Code: (.*)/;
}
if ( $errorLine =~ /^ Reason Code: / ) {
($smcliRS) = $errorLine =~ /^ Reason Code: (.*)/;
}
if ( $errorLine =~ /^ Description: / ) {
($smcliDesc) = $errorLine =~ /^ Description: (.*)/;
}
}
if (( $smcliRC == 212 ) && ( $smcliRS == 8 )) {
if ( $args{'verbose'} == 1 ) {
push @{$rsp->{data}}, "For userid $activeSystem, the virtual machine does not have any network adapters.";
xCAT::MsgUtils->message( "I", $rsp, $callback );
}
push @failureInfo, "The virtual machine does not have any network adapters";
goto FINISH_findAccessIP;
} else {
push @{$rsp->{data}}, "An unexpected return code $smcliRC and reason code $smcliRS was received from " .
"the zhcp server $hcp for an smcli Virtual_Network_Adapter_Query_Extended " .
"request. Error description: $smcliDesc";
xCAT::MsgUtils->message("E", $rsp, $callback);
goto FINISH_findAccessIP;
}
} elsif ( $rc != 0 ) {
push @{$rsp->{data}}, "An unexpected return code $rc was received from " .
"the zhcp server $hcp for an smcli Virtual_Network_Adapter_Query_Extended " .
"request. SMAPI servers may be unavailable. " .
"Received response: $out";
xCAT::MsgUtils->message("E", $rsp, $callback);
goto FINISH_findAccessIP;
}
my $filteredOut = `echo "$out" | egrep -i '(adapter_address=|adapter_status=|mac_address=|mac_ip_address=|mac_ip_version=|lan_name=|lan_owner=)'`;
my @ipOut = split( "\n", $filteredOut );
my ($adapterAddr, $adapterStatus, $ipAddr, $ipVersion, $lanName, $lanOwner, $macAddr );
foreach my $ipLine ( @ipOut ) {
if ( $ipLine =~ /adapter_address=/ ) {
($adapterAddr) = $ipLine =~ /adapter_address=(.*)/;
$adapter{$adapterAddr}{'ipCnt'} = 0;
$adapter{$adapterAddr}{'macCnt'} = 0;
($lanName, $lanOwner) = '';
} elsif ( $ipLine =~ /adapter_status=/ ) {
($adapterStatus) = $ipLine =~ /adapter_status=(.*)/;
$adapter{$adapterAddr}{'status'} = $adapterStatus;
} elsif ( $ipLine =~ /^lan_name=/ ) {
($lanName) = $ipLine =~ /lan_name=(.*)/;
#} elsif ( $ipLine =~ /^lan_owner=/ ) {
# ($lanOwner) = $ipLine =~ /lan_owner=(.*)/;
} elsif ( $ipLine =~ /^mac_address=/ ) {
($macAddr) = $ipLine =~ /mac_address=(.*)/;
($ipVersion, $ipAddr) = '';
$adapter{$adapterAddr}{'macCnt'} += 1;
} elsif ( $ipLine =~ /^mac_ip_address=/ ) {
($ipAddr) = $ipLine =~ /mac_ip_address=(.*)/;
} elsif ( $ipLine =~ /^mac_ip_version=/ ) {
($ipVersion) = $ipLine =~ /mac_ip_version=(.*)/;
}
if ( $ipVersion ne '' and $ipAddr ne '' ) {
$ips{$ipAddr}{'adapterAddr'} = $adapterAddr;
$ips{$ipAddr}{'ipVersion'} = $ipVersion;
$ips{$ipAddr}{'lanName'} = $lanName if $lanName;
#$ips{$ipAddr}{'lanOwner'} = $lanOwner if $lanOwner;
$ips{$ipAddr}{'macAddr'} = $macAddr;
$adapter{$adapterAddr}{'ipCnt'} += 1;
}
}
my $adapterCnt = keys %adapter;
push @{$rsp->{data}}, "For userid $activeSystem, $adapterCnt adapters were detected." if ( $args{'verbose'} == 1 );
foreach $adapterAddr ( keys %adapter ) {
if ( $adapter{$adapterAddr}{'macCnt'} > 0 ) {
if ( $adapter{$adapterAddr}{'ipCnt'} != 0 ) {
push @{$rsp->{data}}, " Adapter $adapterAddr: $adapter{$adapterAddr}{'macCnt'} MACs with $adapter{$adapterAddr}{'ipCnt'} associated IP address(es)" if ( $args{'verbose'} == 1 );
} else {
push @{$rsp->{data}}, " Adapter $adapterAddr: $adapter{$adapterAddr}{'macCnt'} MACs but no associated IP addresses" if ( $args{'verbose'} == 1 );
push @failureInfo, "Adapter $adapterAddr: $adapter{$adapterAddr}{'macCnt'} MACs but no associated IP addresses";
}
} elsif ( $adapter{$adapterAddr}{'status'} eq '00' ) {
push @{$rsp->{data}}, " Adapter $adapterAddr: Not coupled" if ( $args{'verbose'} == 1 );
push @failureInfo, "Adapter $adapterAddr: Not coupled";
} elsif ( $adapter{$adapterAddr}{'status'} eq '01' ) {
push @{$rsp->{data}}, " Adapter $adapterAddr: Not active" if ( $args{'verbose'} == 1 );
push @failureInfo, "Adapter $adapterAddr: Not active";
} else {
push @{$rsp->{data}}, " Adapter $adapterAddr: No MACs with associated IP addresses" if ( $args{'verbose'} == 1 );
push @failureInfo, "Adapter $adapterAddr: No MACs with associated IP addresses";
}
}
xCAT::MsgUtils->message( "I", $rsp, $callback ) if ( $args{'verbose'} == 1 );
if ( !%ips ) {
if ( keys %adapter eq 0 ) {
push @failureInfo, "No adapters were found";
} else {
push @failureInfo, "No IP addresses were detected";
}
goto FINISH_findAccessIP;
}
# Contact the IPs to see which one, if any, lets us in.
foreach $ipAddr ( keys %ips ) {
$rc = 0;
if ( $ips{$ipAddr}{'ipVersion'} eq '6' ) {
# IPv6 is not currently supported.
next;
}
if ( $args{'ipfilter'} ) {
if ( $ipAddr !~ m/$args{'ipfilter'}/i ) {
if ( $args{'verbose'} == 1 ) {
push @{$rsp->{data}}, "For userid $activeSystem, filtered out IP: $ipAddr";
xCAT::MsgUtils->message( "I", $rsp, $callback );
}
push @failureInfo, "$ipAddr - filtered out by the specified IP filter";
next;
}
}
# Ping the address to see if it is responsive.
if ( $ips{$ipAddr}{'ipVersion'} eq '4' ) {
$out = `ping -c1 $ipAddr`;
$rc = $?;
} elsif ( $ips{$ipAddr}{'ipVersion'} eq '6' ) {
# IPv6 is not currently supported.
$rc = 3;
#$out = `ping6 -c1 $ipAddr`;
#$rc = $?;
next;
} else {
push @{$rsp->{data}}, "Userid $activeSystem, IP address: $ipAddr has an unsupported IP version: $ips{$ipAddr}";
xCAT::MsgUtils->message( "E", $rsp, $callback );
next;
}
if ( $rc != 0 or $out !~ / 0% packet loss,/ ) {
if ( $args{'verbose'} == 1 ) {
push @{$rsp->{data}}, "For userid $activeSystem, ping failed for $ipAddr";
xCAT::MsgUtils->message("I", $rsp, $callback);
}
push @failureInfo, "$ipAddr - Unable to ping, rc: $rc";
next;
}
# SSH into the system to verify access.
my $line = `ssh -q $ipAddr pwd 2>/dev/null`;
$rc = $? >> 8;
if ( $rc == 255 ) {
if ( $args{'verbose'} == 1 ) {
push @{$rsp->{data}}, "For userid $activeSystem, Unable to ssh into: $ipAddr";
xCAT::MsgUtils->message("I", $rsp, $callback);
}
push @failureInfo, "$ipAddr - Unable to ssh into system";
next;
}
# Determine the fully qualified host name to use.
my $fqdn = '';
# Attempt to get it from the system's OS using one of a number of commands.
# If we can't get a fully qualified DNS names (with periods) then accept the short name.
my $shortName = '';
foreach my $cmd ( @hostnameCmds ) {
my $hostname = `ssh -q $ipAddr $cmd 2>/dev/null`;
my $rc = $? >> 8;
if ( $rc == 255 ) {
if ( $args{'verbose'} == 1 ) {
my $rsp;
push @{$rsp->{data}}, "For userid $activeSystem, Unable to ssh into: $ipAddr";
xCAT::MsgUtils->message("I", $rsp, $callback);
push @failureInfo, "$ipAddr - Unable to ssh into system";
last;
}
last;
} elsif ( $rc == 0 ) {
# verify the hostname is a fully qualified name.
chomp $hostname;
if ( $hostname =~ /\./ ) {
$fqdn = $hostname;
last;
} else {
$hostname =~ s/^\s+//;
if (( $hostname ne '' ) && ( $hostname !~ /\s/ )) {
# Single word returned without periods. Must be a short name.
$shortName = $hostname;
}
# Keep looking for a long name but we will remember the short name
# in case we can't find a long name.
}
} else {
if ( $args{'verbose'} == 1 ) {
my $rsp;
push @{$rsp->{data}}, "For userid $activeSystem, \'$cmd\' returned, rc: $rc.";
xCAT::MsgUtils->message("I", $rsp, $callback);
}
}
}
if (( $shortName eq '' ) && ( $rc != 255 )) {
push @failureInfo, "$ipAddr - hostname query commands failed to return required information";
}
if (( $fqdn eq '' ) && ( $shortName ne '' )) {
if ( $args{'verbose'} == 1 ) {
my $rsp;
push @{$rsp->{data}}, "For userid $activeSystem, Unable to determine the fully qualified domain name but found a short name. The short name will be used.";
xCAT::MsgUtils->message("I", $rsp, $callback);
}
$fqdn = $shortName;
}
# Found the last piece of info needed.
# Note: If hostname is empty because we could not find it, the ultimate response will
# be a failing return code.
$sysInfoRef->{$activeSystem}{'adapterAddr'} = $ips{$ipAddr}{'adapterAddr'};;
$sysInfoRef->{$activeSystem}{'ipAddr'} = $ipAddr;
$sysInfoRef->{$activeSystem}{'ipVersion'} = $ips{$ipAddr};
$sysInfoRef->{$activeSystem}{'macAddr'} = $ips{$ipAddr}{'macAddr'};
$sysInfoRef->{$activeSystem}{'switch'} = $ips{$ipAddr}{'lanName'};
$sysInfoRef->{$activeSystem}{'hostname'} = $fqdn;
last;
}
FINISH_findAccessIP:
if ( $sysInfoRef->{$activeSystem}{'hostname'} ) {
$rc = 0;
} else {
$rc = 1;
if ( @failureInfo ) {
my $rsp;
my $failureString = join( ',\n', @failureInfo );
push @{$rsp->{data}}, "Unable to access $activeSystem for the following reasons:\n$failureString";
xCAT::MsgUtils->message("I", $rsp, $callback);
$failureString = join( ', ', @failureInfo );
xCAT::zvmUtils->printSyslog( "findAccessIP() Unable to access $activeSystem for the following reasons: $failureString" );
}
}
return $rc;
}
#-------------------------------------------------------
=head3 smapi4xcat
Description : Verify if SMAPI EXEC (xCAT_Commands_IUO) exists
Arguments : User (root or non-root)
zHCP
Returns : 0 EXEC not found
1 EXEC found
Example : my $out = xCAT::zvmUtils->smapi4xcat($user, $hcp);
=cut
#-------------------------------------------------------
sub smapi4xcat {
my ( $class, $user, $hcp ) = @_;
# Directory where executables are
my $dir = '/opt/zhcp/bin';
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Get zHCP user ID
my $hcpUserId = xCAT::zvmCPUtils->getUserId($user, $hcp);
$hcpUserId =~ tr/a-z/A-Z/;
# Check SMAPI level
# Levels 621 and greater support SMAPI EXEC
my $out = `ssh $user\@$hcp "$sudo $dir/smcli Query_API_Functional_Level -T $hcpUserId"`;
$out = xCAT::zvmUtils->trimStr($out);
if ( !($out =~ m/V6.2/i || $out =~ m/V6.1/i || $out =~ m/V5.4/i) ) {
return 1;
}
# Check if SMAPI EXEC exists
# EXEC found if RC = 8 and RS = 3002
$out = `ssh $user\@$hcp "$sudo $dir/smcli xCAT_Commands_IUO -T $hcpUserId -c ''"`;
$out = xCAT::zvmUtils->trimStr($out);
if ( $out =~ m/Return Code: 8/i && $out =~ m/Reason Code: 3002/i ) {
return 1;
}
return 0;
}
#-------------------------------------------------------
=head3 generateUserEntryFile
Description : Generate a user entry file without Mdisk
Arguments : UserId
Password
Memory
Privilege
Profile
Cpu
ipl
logonby
Returns : If successful, return file path. Otherwise, return -1
Example : my $out = xCAT::zvmUtils->generateUserEntryFile($userId, $password, $memorySize, $privilege, $profileName, $cpuCount, $ipl, $logonby);
=cut
#-------------------------------------------------------
sub generateUserEntryFile {
my ( $class, $userId, $password, $memorySize, $privilege, $profileName, $cpuCount, $ipl, $logonby) = @_;
# If a file of this name already exists, just override it
my $file = "/tmp/$userId.txt";
my $content = "USER $userId $password $memorySize $memorySize $privilege\nINCLUDE $profileName\nCPU 00 BASE\n";
# Add additional CPUs
my $i;
for ( $i = 1; $i < $cpuCount; $i++ ) {
$content = $content.sprintf("CPU %02X\n", $i);
}
if ( $ipl ne "") {
# the caller need validate this $ipl param
$content = $content.sprintf("IPL %04s\n", $ipl);
}
if ( $logonby ne "") {
# the caller need validate the $logonby param
my $log = "LOGONBY ".$logonby."\n";
$content = $content.$log;
}
unless (open(FILE, ">$file")) {
return -1;
}
print FILE $content;
close(FILE);
return $file;
}
#-------------------------------------------------------
=head3 querySSI
Description : Obtain the SSI and system status
Arguments : User (root or non-root)
zHCP
Returns : SSI cluster name or string containing (Error)...
Example : my $out = xCAT::zvmUtils->querySSI($user, $hcp);
=cut
#-------------------------------------------------------
sub querySSI {
my ( $class, $user, $hcp ) = @_;
# Directory where executables are
my $dir = '/opt/zhcp/bin';
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
my $outmsg;
my $rc;
my $ssi = `ssh -o ConnectTimeout=10 $user\@$hcp "$sudo $dir/smcli SSI_Query"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh -o ConnectTimeout=10 $user\@$hcp \"$sudo $dir/smcli SSI_Query\"", $hcp, "querySSI", $ssi );
if ($rc != 0) {
return $outmsg;
}
$ssi = `echo "$ssi" | egrep -a -i "ssi_name"`;
$ssi =~ s/ssi_name = //;
$ssi =~ s/\s*$//;
$ssi =~ s/^\s*//;
return $ssi;
}
#-------------------------------------------------------
=head3 rExecute
Description : Execute a remote command
Arguments : User (root or non-root)
Node
Command to execute
Returns : Output returned from executing command
Example : my $out = xCAT::zvmUtils->rExecute($user, $node, $cmd);
=cut
#-------------------------------------------------------
sub rExecute {
my ( $class, $user, $node, $cmd ) = @_;
my $out;
my $sudo = "sudo";
if ($user eq "root") {
# Just execute the command if root
#$out = `ssh $user\@$node "$cmd"`;
$out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
return $out;
}
# Encapsulate command in single quotes
$cmd = "'" . $cmd . "'";
#$out = `ssh $user\@$node "$sudo sh -c $cmd"`;
$cmd = "$sudo sh -c $cmd";
$out = xCAT::zvmUtils->execcmdonVM($user, $node, $cmd); # caller sets $user to $::SUDOER
return $out;
}
#-------------------------------------------------------
=head3 getUsedFcpDevices
Description : Get a list of used FCP devices in the zFCP pools
Arguments : User (root or non-root)
zHCP
Returns : List of known FCP devices, or hash with key "Error" containing error message
Example : my %devices = xCAT::zvmUtils->getUsedFcpDevices($user, $zhcp);
=cut
#-------------------------------------------------------
sub getUsedFcpDevices {
my ( $class, $user, $hcp ) = @_;
# Directory where zFCP pools are
my $pool = "/var/opt/zhcp/zfcp";
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Grep the pools for used or allocated zFCP devices
my %usedDevices;
my @args;
my $outmsg;
my $rc;
my $out = `ssh $user\@$hcp "$sudo cat $pool/*.conf"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo cat $pool/*.conf\"", $hcp, "getUsedFcpDevices", $out );
if ($rc != 0) {
$usedDevices{"Error"} = $outmsg;
return %usedDevices;
}
$out = `echo "$out" | egrep -a -i "used|allocated"`;
my @devices = split("\n", $out);
foreach (@devices) {
@args = split(",", $_);
# Sample pool configuration file:
# #status,wwpn,lun,size,range,owner,channel,tag
# used,1000000000000000,2000000000000110,8g,3B00-3B3F,ihost1,1a23,$root_device$
# free,1000000000000000,2000000000000111,,3B00-3B3F,,,
# free,1230000000000000,2000000000000112,,3B00-3B3F,,,
$args[6] = xCAT::zvmUtils->trimStr($args[6]);
# Push used or allocated devices into hash
if ($args[6]) {
$usedDevices{uc($args[6])} = 1;
}
}
return %usedDevices;
}
#-------------------------------------------------------
=head3 establishMount
Description : Establish an NFS mount point on a zHCP system.
Arguments : Sudoer user name
Sudo keyword
zHCP hostname
Install root directory
Local directory to remotely mount
Mount access ('ro' for read only, 'rw' for read write)
Directory as known to zHCP (out)
Returns : 0 - Mounted, or zHCP and MN are on the same system
1 - Mount failed, errors returned in $callback
Example : establishMount( $callback, $::SUDOER, $::SUDO, $hcp, $installRoot, $provMethod, "ro", \$remoteDeployDir );
=cut
#-------------------------------------------------------
sub establishMount {
# Get inputs
my ($class, $callback, $sudoer, $sudo, $hcp, $installRoot, $localDir, $access, $mountedPt) = @_;
my $out;
# If the target system is not on this system then establish the NFS mount point.
my $hcpIP = xCAT::NetworkUtils->getipaddr( $hcp );
if (! defined $hcpIP) {
xCAT::zvmUtils->printLn( $callback, "(Error) Unable to obtain the IP address of the hcp node" );
return 1;
}
# Get internal master IP if xcat and zhcp are on a 10. network
my $masterIp = xCAT::TableUtils->get_site_attribute("internalmaster");
# Use "internalmaster", if it is set. Otherwise, look at "master" property.
if (!defined $masterIp) {
$masterIp = xCAT::TableUtils->get_site_attribute("master");
if (! defined $masterIp) {
xCAT::zvmUtils->printLn( $callback, "$hcp: (Error) Unable to obtain the management node IP address from the site table" );
return 1;
}
}
if ($masterIp eq $hcpIP) {
# xCAT MN and zHCP are on the same box and will use the same directory without the need for an NFS mount.
$$mountedPt = "$installRoot/$localDir";
} else {
# Determine the hostname for this management node
my $masterHostname = Sys::Hostname::hostname();
if (! defined $masterHostname) {
# For some reason, the xCAT MN's hostname is not known. We pass along the IP address instead.
$masterHostname = $masterIp;
}
$$mountedPt = "/mnt/$masterHostname$installRoot/$localDir";
# If the mount point already exists then return because we are done.
my $outmsg;
my $rc;
$out = `ssh $sudoer\@$hcp "$sudo mount"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $sudoer\@$hcp \"$sudo mount\"", $hcp, "establishMount", $out );
if ($rc != 0) {
xCAT::zvmUtils->printLn( $callback, "$outmsg" );
return 1;
}
$rc = `echo "$out" | egrep -a -i $$mountedPt > /dev/null; echo \\\$?"`;
if ($rc == 0) {
return 0;
}
xCAT::zvmUtils->printSyslog( "establishMount() Preparing the NFS mount point on zHCP ($hcpIP) to xCAT MN $masterHostname($masterIp) for $localDir" );
# Prepare the staging mount point on zHCP, if they need to be established
$rc = `ssh $sudoer\@$hcp "$sudo mkdir -p $$mountedPt && mount -t nfs -o $access $masterIp:/$localDir $$mountedPt; echo \\\$?"`;
# Return code = 0 (mount succeeded)
if ($rc != '0') {
xCAT::zvmUtils->printLn( $callback, "$hcp: (Error) Unable to establish zHCP mount point: $$mountedPt" );
xCAT::zvmUtils->printSyslog( "establishMount() Unable to establish zHCP mount point: $$mountedPt, rc: $rc" );
return 1;
}
}
return 0;
}
#-------------------------------------------------------
=head3 getFreeRepoSpace
Description : Get the free space of image repository under /install.
Arguments : Node
Returns : The available space for /install (e.g. "2.1G ").
The value is returned as a perl string (e.g. "0 ") to
avoid perl returning null instead of "0" in the case
of no space available.
Example : my $free = getFreeRepoSpace($callback, $node);
=cut
#-------------------------------------------------------
sub getFreeRepoSpace {
# Get inputs
my ($class, $user, $node) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# 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
my $out = `$sudo /bin/df -h /install | sed 1d`;
# Comment out the horizontal whitespace escape, it was causing "Restarting xCATd Unrecognized escape"
# $out =~ s/\h+/ /g;
my @results = split(' ', $out);
if ( $results[3] eq "0" ) {
$results[3] = "0M";
}
return $results[3];
}
return;
}
#-------------------------------------------------------
=head3 findAndUpdatezFcpPool
Description : Find and update a SCSI/FCP device in a given storage pool.
xCAT will find and update the SCSI/FCP device in all known pools based on the unique WWPN/LUN combo.
Arguments : Message header
User (root or non-root)
zHCP
Storage pool
Criteria hash including:
- Status (free, reserved, or used)
- zFCP channel
- WWPN
- LUN
- Size requested
- Owner
- Tag
Returns : Results hash including:
- Return code (0 = Success, -1 = Failure, errors returned in $callback)
- zFCP device (if one is requested)
- WWPN
- LUN
Example : my $resultsRef = xCAT::zvmUtils->findAndUpdatezFcpPool($callback, $header, $user, $hcp, $pool, $criteriaRef);
=cut
#-------------------------------------------------------
sub findAndUpdatezFcpPool {
# Get inputs
my ($class, $callback, $header, $user, $hcp, $pool, $criteriaRef) = @_;
my $outmsg;
my $rc;
my $out;
# Determine if sudo is used
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Directory where executables are on zHCP
my $dir = "/opt/zhcp/bin";
# Directory where FCP disk pools are on zHCP
my $zfcpDir = "/var/opt/zhcp/zfcp";
my %results = ('rc' => -1); # Default to error
# Extract criteria
my %criteria = %$criteriaRef;
my $status = defined($criteria{status}) ? $criteria{status} : "";
my $fcpDevice = defined($criteria{fcp}) ? $criteria{fcp} : "";
my $wwpn = defined($criteria{wwpn}) ? $criteria{wwpn} : "";
my $lun = defined($criteria{lun}) ? $criteria{lun} : "";
my $size = defined($criteria{size}) ? $criteria{size} : "";
my $owner = defined($criteria{owner}) ? $criteria{owner} : "";
my $tag = defined($criteria{tag}) ? $criteria{tag} : "";
# Check required arguments: pool, status
# If you do not know what to update, why update!
if (!$pool && !$status) {
return \%results;
}
# Check status
if ($status !~ m/^(free|used|reserved)$/i) {
xCAT::zvmUtils->printLn($callback, "$header: (Error) Status not recognized. Status can be free, used, or reserved.");
return \%results;
}
# Check FCP device syntax
if ($fcpDevice && ($fcpDevice !~ /^auto/i) && ($fcpDevice =~ /[^0-9a-f;]/i)) {
xCAT::zvmUtils->printLn($callback, "$header: (Error) Invalid FCP channel address $fcpDevice.");
return \%results;
}
# Owner must be specified if status is used
if ($status =~ m/used/i && !$owner) {
xCAT::zvmUtils->printLn( $callback, "$header: (Error) Owner must be specified if status is used." );
return \%results;
} elsif ($status =~ m/free/i && $owner) {
xCAT::zvmUtils->printLn( $callback, "$header: (Error) Owner must not be specified if status is free." );
return \%results;
}
# Size can be M(egabytes) or G(igabytes). Convert size into MB.
my $originSize = $size;
if ($size) {
if ($size =~ m/G/i) {
# Convert to MegaBytes
$size =~ s/\D//g;
$size = int($size) * 1024
} elsif ($size =~ m/M/i || !$size) {
# Do nothing
} else {
xCAT::zvmUtils->printLn( $callback, "$header: (Error) Size not recognized. Size can be M(egabytes) or G(igabytes)." );
return \%results;
}
}
# Check if WWPN and LUN are given
# WWPN can be given as a semi-colon separated list (multipathing)
my $useWwpnLun = 0;
if ($wwpn && $lun) {
xCAT::zvmUtils->printLn($callback, "$header: Using given WWPN and LUN");
$useWwpnLun = 1;
# Make sure WWPN and LUN do not have 0x prefix
$wwpn = xCAT::zvmUtils->replaceStr($wwpn, "0x", "");
$lun = xCAT::zvmUtils->replaceStr($lun, "0x", "");
# Check WWPN and LUN syntax
if ( $wwpn && ($wwpn =~ /[^0-9a-f;]/i) ) {
xCAT::zvmUtils->printLn( $callback, "$header: (Error) Invalid world wide portname $wwpn." );
return \%results;
} if ( $lun && ($lun =~ /[^0-9a-f]/i) ) {
xCAT::zvmUtils->printLn( $callback, "$header: (Error) Invalid logical unit number $lun." );
return \%results;
}
}
# Find disk pool (create one if non-existent)
if (!(`ssh $user\@$hcp "$sudo test -d $zfcpDir && echo Exists"`)) {
# Create pool directory
$out = `ssh $user\@$hcp "$sudo mkdir -p $zfcpDir"`;
}
# Find if disk pool exists
if (!(`ssh $user\@$hcp "$sudo test -e $zfcpDir/$pool.conf && echo Exists"`)) {
# Return if xCAT is expected to find a FCP device, but no disk pool exists.
xCAT::zvmUtils->printLn($callback, "$header: (Error) FCP storage pool does not exist");
return \%results;
}
# Find a free disk in the pool
# FCP devices are contained in /var/opt/zhcp/zfcp/<pool-name>.conf
my $range = "";
my $sizeFound = "*";
my @info;
if (!$useWwpnLun) {
# Find a suitable pair of WWPN and LUN in device pool based on requested size
# Sample pool configuration file:
# #status,wwpn,lun,size,range,owner,channel,tag
# used,1000000000000000,2000000000000110,8g,3B00-3B3F,ihost1,1a23,$root_device$
# free,1000000000000000,2000000000000111,,3B00-3B3F,,,
# free,1230000000000000;4560000000000000,2000000000000112,,3B00-3B3F,,,
$out = `ssh $user\@$hcp "$sudo cat $zfcpDir/$pool.conf"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo cat $zfcpDir/$pool.conf\"", $hcp, "findAndUpdatezFcpPool", $out );
if ($rc != 0) {
xCAT::zvmUtils->printLn($callback, "$outmsg");
return \%results;
}
$out = `echo "$out" | egrep -a -i ^free`;
my @devices = split("\n", $out);
$sizeFound = 0;
foreach (@devices) {
@info = split(',', $_);
# Check if the size is sufficient. Convert size into MB.
if ($info[3] =~ m/G/i) {
# Convert to MegaBytes
$info[3] =~ s/\D//g;
$info[3] = int($info[3]) * 1024
} elsif ($info[3] =~ m/M/i) {
# Do nothing
$info[3] =~ s/\D//g;
} else {
next;
}
# Find optimal disk based on requested size
if ($sizeFound && $info[3] >= $size && $info[3] < $sizeFound) {
$sizeFound = $info[3];
$wwpn = $info[1];
$lun = $info[2];
$range = $info[4];
} elsif (!$sizeFound && $info[3] >= $size) {
$sizeFound = $info[3];
$wwpn = $info[1];
$lun = $info[2];
$range = $info[4];
}
}
# Do not continue if no devices can be found
if (!$wwpn || !$lun) {
xCAT::zvmUtils->printLn($callback, "$header: (Error) A suitable device of $size" . "M or larger could not be found");
return \%results;
}
} else {
# Find given WWPN and LUN. Do not continue if device is used
my $select = `ssh $user\@$hcp "$sudo cat $zfcpDir/$pool.conf"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo cat $zfcpDir/$pool.conf\"", $hcp, "findAndUpdatezFcpPool", $select );
if ($rc != 0) {
xCAT::zvmUtils->printLn($callback, "$outmsg");
return \%results;
}
$select = `echo "$select" | egrep -a -i "$wwpn,$lun"`;
chomp($select);
if (!$select) {
xCAT::zvmUtils->printLn($callback, "$header: (Error) zFCP device 0x$wwpn/0x$lun could not be found in zFCP pool $pool");
return \%results;
}
@info = split(',', $select);
if ($size) {
if ($info[3] =~ m/G/i) {
# Convert to MegaBytes
$info[3] =~ s/\D//g;
$info[3] = int($info[3]) * 1024
} else {
# Do nothing
$info[3] =~ s/\D//g;
}
# Do not continue if specified device does not have enough capacity
if ($info[3] < $size) {
xCAT::zvmUtils->printLn($callback, "$header: (Error) FCP device $wwpn/$lun is not large enough");
return \%results;
}
}
# Find range of the specified disk
$range = $info[4];
}
xCAT::zvmUtils->printLn($callback, "$header: Found FCP device 0x$wwpn/0x$lun");
if ( ($status =~ m/used/i) && ($fcpDevice =~ /^auto/i) ) {
# select an eligible FCP device
$fcpDevice = xCAT::zvmUtils->selectFcpDevice($callback, $header, $user, $hcp, $fcpDevice, $range, $owner);
if (!$fcpDevice) {
return \%results;
}
} elsif ($status =~ m/free/i) {
# Owner and FCP channel make no sense when status is free
$fcpDevice = "";
$owner = "";
}
# Mark WWPN and LUN as used, free, or reserved and set the owner/channel appropriately
# This config file keeps track of the owner of each device, which is useful in nodeset
$size = $size . "M";
my $select = `ssh $user\@$hcp "$sudo cat $zfcpDir/$pool.conf"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo cat $zfcpDir/$pool.conf\"", $hcp, "findAndUpdatezFcpPool", $select );
if ($rc != 0) {
xCAT::zvmUtils->printLn($callback, "$outmsg");
return \%results;
}
$select = `echo "$select" | egrep -a -i "$lun"`;
chomp($select);
if ($select) {
@info = split(',', $select);
if (!$info[3]) {
$info[3] = $size;
}
# Do not update if WWPN/LUN pair is specified but the pair does not exist
if (!($info[1] =~ m/$wwpn/i)) {
xCAT::zvmUtils->printLn($callback, "$header: (Error) FCP device $wwpn/$lun does not exists");
return \%results;
}
# Entry order: status,wwpn,lun,size,range,owner,channel,tag
# The following are never updated: wwpn, lun, size, and range
my $update = "$status,$info[1],$info[2],$info[3],$info[4],$owner,$fcpDevice,$tag";
my $expression = "'s#" . $select . "#" .$update . "#i'";
$out = `ssh $user\@$hcp "$sudo sed --in-place -e $expression $zfcpDir/$pool.conf"`;
} else {
# Insert device entry into file
$out = `ssh $user\@$hcp "$sudo echo \"$status,$wwpn,$lun,$size,,$owner,$fcpDevice,$tag\" >> $zfcpDir/$pool.conf"`;
}
# Generate results hash
%results = (
'rc' => 0,
'fcp' => $fcpDevice,
'wwpn' => $wwpn,
'lun' => $lun
);
return \%results;
}
#-------------------------------------------------------
=head3 selectFcpDevice
Description : Select an eligible FCP device for attaching a zFCP device to a node
Arguments : Message header
User (root or non-root)
zHCP
candidate FCP devices or auto
FCP device range
zFCP device owner
Returns : selected FCP device or empty if no one is selected, errors returned in $callback
Example : my $fcpDevice = xCAT::zvmUtils->selectFcpDevice($callback, $header, $user, $hcp, $fcpDevice, $range, $owner);
=cut
#-------------------------------------------------------
sub selectFcpDevice {
# Get inputs
my ($class, $callback, $header, $user, $hcp, $fcpDevice, $range, $owner) = @_;
# Determine if sudo is used
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Directory where executables are on zHCP
my $dir = "/opt/zhcp/bin";
# Directory where FCP disk pools are on zHCP
my $zfcpDir = "/var/opt/zhcp/zfcp";
my %results = ('rc' => -1); # Default to error
# Check FCP device syntax
if ($fcpDevice && ($fcpDevice !~ /^auto/i) && ($fcpDevice =~ /[^0-9a-f]/i)) {
xCAT::zvmUtils->printLn($callback, "$header: (Error) Invalid FCP channel address $fcpDevice.");
return;
}
# Find a free FCP device based on the given range
if ($fcpDevice =~ m/^auto/i) {
my @ranges;
my $min;
my $max;
my $found = 0;
if ($range =~ m/;/i) {
@ranges = split(';', $range);
} else {
push(@ranges, $range);
}
if (!$found) {
# If the node has an eligible FCP device, use it
my @deviceList = xCAT::zvmUtils->getDedicates($callback, $user, $owner);
foreach (@deviceList) {
# Check if this devide is eligible (among the range specified for disk $lun)
my @info = split(' ', $_);
my $candidate = $info[2];
foreach (@ranges) {
($min, $max) = split('-', $_);
if (hex($candidate) >= hex($min) && hex($candidate) <= hex($max)) {
$found = 1;
$fcpDevice = uc($candidate);
last;
}
}
if ($found) {
xCAT::zvmUtils->printLn($callback, "$header: Found eligible FCP channel $fcpDevice");
last;
}
}
}
if (!$found) {
# If the node has no eligible FCP device, find a free one for it.
my %usedDevices = xCAT::zvmUtils->getUsedFcpDevices($user, $hcp);
if (exists $usedDevices{"Error"}) {
xCAT::zvmUtils->printLn($callback, "$header: $usedDevices{Error}");
return;
}
my $hcpUserId = xCAT::zvmCPUtils->getUserId($user, $hcp);
$hcpUserId =~ tr/a-z/A-Z/;
# Find a free FCP channel
my $outmsg;
my $rc;
my $out = `ssh $user\@$hcp "$sudo $dir/smcli System_WWPN_Query -T $hcpUserId"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo $dir/smcli System_WWPN_Query -T $hcpUserId\"", $hcp, "selectFcpDevice", $out );
if ($rc != 0) {
xCAT::zvmUtils->printLn($callback, "$outmsg");
return;
}
$out = `echo "$out" | egrep -a -i "FCP device number|Status"`;
my @devices = split( "\n", $out );
for (my $i = 0; $i < @devices; $i++) {
# Extract the device number and status
$fcpDevice = $devices[$i];
$fcpDevice =~ s/^FCP device number:(.*)/$1/;
$fcpDevice =~ s/^\s+//;
$fcpDevice =~ s/\s+$//;
$i++;
my $fcpStatus = $devices[$i];
$fcpStatus =~ s/^Status:(.*)/$1/;
$fcpStatus =~ s/^\s+//;
$fcpStatus =~ s/\s+$//;
# Only look at free FCP devices
if ($fcpStatus =~ m/free/i) {
# If the device number is within the specified range, exit out of loop
# Range: 3B00-3C00;4B00-4C00;5E12-5E12
foreach (@ranges) {
($min, $max) = split('-', $_);
if (hex($fcpDevice) >= hex($min) && hex($fcpDevice) <= hex($max)) {
$fcpDevice = uc($fcpDevice);
# Use found FCP channel if not in use or allocated
if (!$usedDevices{$fcpDevice}) {
$found = 1;
last;
}
}
}
}
# Break out of loop if FCP channel is found
if ($found) {
xCAT::zvmUtils->printLn($callback, "$header: Found FCP channel within acceptable range $fcpDevice");
last;
}
}
}
# Do not continue if no FCP channel is found
if (!$found) {
xCAT::zvmUtils->printLn($callback, "$header: (Error) A suitable FCP channel could not be found");
return;
}
}
# If there are multiple devices (multipathing), take the 1st one
if ($fcpDevice) {
if ($fcpDevice =~ m/;/i) {
my @info = split(';', $fcpDevice);
$fcpDevice = xCAT::zvmUtils->trimStr($info[0]);
}
# Make sure channel has a length of 4
while (length($fcpDevice) < 4) {
$fcpDevice = "0" . $fcpDevice;
}
}
return $fcpDevice;
}
#-------------------------------------------------------
=head3 findzFcpDevicePool
Description : Find the zFCP storage pool that contains the given zFCP device
Arguments : User (root or non-root)
zHCP
WWPN
LUN
Returns : Storage pool where zFCP device resides, or string containing (Error)...
Example : my $pool = xCAT::zvmUtils->findzFcpDevicePool($user, $hcp, $wwpn, $lun);
=cut
#-------------------------------------------------------
sub findzFcpDevicePool {
# Get inputs
my ( $class, $user, $hcp, $wwpn, $lun ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Directory where FCP disk pools are on zHCP
my $zfcpDir = "/var/opt/zhcp/zfcp";
# Find the pool that contains the SCSI/FCP device
my $out;
my $outmsg;
my $rc;
$out = `ssh $user\@$hcp "$sudo grep -i -l \\\"$wwpn,$lun\\\" $zfcpDir/*.conf"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo grep -i -l \\\"$wwpn,$lun\\\" $zfcpDir/*.conf\"", $hcp, "findzFcpDevicePool", $out );
if ($rc != 0) {
return $outmsg;
}
my @pools = split("\n", $out);
my $pool = "";
if (scalar(@pools)) {
$pool = basename($pools[0]);
$pool =~ s/\.[^.]+$//; # Do not use extension
}
return $pool;
}
#-------------------------------------------------------
=head3 findzFcpDeviceAttr
Description : Find the zFCP device attributes
Arguments : User (root or non-root)
zHCP
Storage pool
WWPN
LUN
Returns : Architecture of node or string containing (Error)...
Example : my $deviceRef = xCAT::zvmUtils->findzFcpDeviceAttr($user, $hcp, $pool, $wwpn, $lun);
=cut
#-------------------------------------------------------
sub findzFcpDeviceAttr {
# Get inputs
my ( $class, $user, $hcp, $pool, $wwpn, $lun ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Directory where FCP disk pools are on zHCP
my $zfcpDir = "/var/opt/zhcp/zfcp";
# Find the SCSI/FCP device
# Entry order: status,wwpn,lun,size,range,owner,channel,tag
my $out;
my $outmsg;
my $rc;
$out = `ssh $user\@$hcp "$sudo grep -i \"$wwpn,$lun\" $zfcpDir/$pool.conf"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "ssh $user\@$hcp \"$sudo grep -i \"$wwpn,$lun\" $zfcpDir/$pool.conf\"", $hcp, "findzFcpDeviceAttr", $out );
if ($rc != 0) {
return $outmsg;
}
my @info = split("\n", $out);
my $entry = $info[0];
chomp($entry);
# Do not continue if no device is found
my %attrs = ();
if (!$entry) {
return \%attrs;
}
@info = split(',', $entry);
%attrs = (
'status' => $info[0],
'wwpn' => $info[1],
'lun' => $info[2],
'size' => $info[3],
'range' => $info[4],
'owner' => $info[5],
'fcp' => $info[6],
'tag' => $info[7]
);
return \%attrs;
}
#-------------------------------------------------------
=head3 findUsablezHcpNetwork
Description : Find a useable NIC shared with the zHCP for a given user Id
Arguments : User (root or non-root)
zHCP
User Id to find a useable NIC on
DHCP is used or not (0 or 1)
Returns : NIC, device channel, and layer (2 or 3)
Example : my ($nic, $channel, $layer) = xCAT::zvmUtils->findUsablezHcpNetwork($user, $hcp, $userId, $dhcp);
=cut
#-------------------------------------------------------
sub findUsablezHcpNetwork {
# Get inputs
my ( $class, $user, $hcp, $userId, $dhcp ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
my $nic = ''; # Usuable NIC on zHCP
my $channel = ''; # Device channel where NIC is attached
my $layer;
my $i;
my @words;
# Get the networks used by the zHCP
my @hcpNetworks = xCAT::zvmCPUtils->getNetworkNamesArray($user, $hcp);
# Search directory entry for network name
my $userEntry = `ssh $user\@$hcp "$sudo $::DIR/smcli Image_Query_DM -T $userId" | sed '\$d'`;
xCAT::zvmUtils->printSyslog("findUsablezHcpNetwork() smcli Image_Query_DM -T $userId");
xCAT::zvmUtils->printSyslog("findUsablezHcpNetwork() $userEntry");
my $out = `echo "$userEntry" | grep "NICDEF"`;
my @lines = split('\n', $out);
# Go through each line
for ($i = 0; $i < @lines; $i++) {
# Go through each network device attached to zHCP
foreach (@hcpNetworks) {
# If network device is found
if ($lines[$i] =~ m/ $_/i) {
# Get network layer
$layer = xCAT::zvmCPUtils->getNetworkLayer($user, $hcp, $_);
xCAT::zvmUtils->printSyslog("findUsablezHcpNetwork() NIC:$_ layer:$layer");
# If template using DHCP, layer must be 2
if ((!$dhcp && $layer != 2) || (!$dhcp && $layer == 2) || ($dhcp && $layer == 2)) {
# Save network name
$nic = $_;
# Get network virtual address
@words = split(' ', $lines[$i]);
# Get virtual address (channel)
# Convert subchannel to decimal
$channel = sprintf('%d', hex($words[1]));
xCAT::zvmUtils->printSyslog("findUsablezHcpNetwork() Candidate found NIC:$nic channel:$channel layer:$layer");
return ($nic, $channel, $layer);
} else {
# Go to next network available
$nic = '';
}
}
}
}
# If network device is not found
if (!$nic) {
# Check for user profile
my $profileName = `echo "$userEntry" | grep "INCLUDE"`;
if ($profileName) {
@words = split(' ', xCAT::zvmUtils->trimStr($profileName));
# Get user profile
my $userProfile = xCAT::zvmUtils->getUserProfile($user, $hcp, $words[1]);
xCAT::zvmUtils->printSyslog("findUsablezHcpNetwork() $userProfile");
# Get the NICDEF statement
$out = `echo "$userProfile" | grep "NICDEF"`;
@lines = split('\n', $out);
# Go through each line
for ($i = 0; $i < @lines; $i++) {
# Go through each network device attached to zHCP
foreach (@hcpNetworks) {
# If network device is found
if ($lines[$i] =~ m/ $_/i) {
# Get network layer
$layer = xCAT::zvmCPUtils->getNetworkLayer($user, $hcp, $_);
xCAT::zvmUtils->printSyslog("findUsablezHcpNetwork() NIC:$_ layer:$layer");
# If template using DHCP, layer must be 2
if ((!$dhcp && $layer != 2) || (!$dhcp && $layer == 2) || ($dhcp && $layer == 2)) {
# Save network name
$nic = $_;
# Get network virtual address
@words = split(' ', $lines[$i]);
# Get virtual address (channel)
# Convert subchannel to decimal
$channel = sprintf('%d', hex($words[1]));
xCAT::zvmUtils->printSyslog("findUsablezHcpNetwork() Candidate found NIC:$nic channel:$channel layer:$layer");
return ($nic, $channel, $layer);
} else {
# Go to next network available
$nic = '';
}
}
} # End of foreach
} # End of for
} # End of if
}
return;
}
#-------------------------------------------------------
=head3 printInfo
Description : Print a long string to stdout as information without checking anything
Arguments : String
Returns : Nothing
Example : xCAT::zvmUtils->printInfo($callback, $str);
=cut
#-------------------------------------------------------
sub printInfo {
# Get inputs
my ( $class, $callback, $str ) = @_;
# Print string
my $rsp;
$rsp->{data}->[0] = "$str";
xCAT::MsgUtils->message( "I", $rsp, $callback );
return;
}
#-------------------------------------------------------
=head3 getSpecialCloneInfo
Description : Look in the /var/opt/xcat/doclone.txt file (if exists) and return a
hash of the keys and values found that match the image name parameter
Arguments : User friendly image name
Returns : hash of keys and values found or empty hash
Example : my %cloneinfo = xCAT::zvmUtils->getSpecialCloneInfo($callback, $user, $node);
if (%cloneinfo) {
%cloneinfo has at least one key
} else {
%cloneinfo empty, no keys
}
=cut
#-------------------------------------------------------
sub getSpecialCloneInfo {
# Get inputs
my ( $class, $imagename ) = @_;
my %cloneInfoHash = (); # create empty hash
# Directory where doclone.txt is
my $dir = '/var/opt/xcat/';
my $clonefile = 'doclone.txt';
my $out;
# Does the file exist? If so read and look for this image name
if (-e "$dir$clonefile") {
# look for this image name and ignore case
$out = `cat $dir$clonefile | grep -v '^\\s*/[*]'| grep -v '^\\s*[*]'| grep -E -i -w "IMAGE_NAME[[:blank:]]*=[[:blank:]]*$imagename"`;
my @lines = split( '\n', $out );
my $count = @lines;
# loop for any lines found
for (my $i=0; $i < $count; $i++) {
# Break out each key=value; item
my @parms = split( ';', $lines[$i]);
my $parmcount = @parms;
# get the key and value for this item, store in hash
for (my $j=0; $j < $parmcount; $j++) {
my @keyvalue = split('=', $parms[$j]);
my $key = $keyvalue[0];
$key =~ s/^\s+|\s+$//g; # get rid of leading and trailing blanks
next if ( length( $key ) == 0 ); # Skip incorrect key=value data
my $value = $keyvalue[1];
$value =~ s/^\s+|\s+$//g;
next if ( length( $value ) == 0 ); # Skip incorrect key=value data
#uppercase both key and value;
$key = uc $key;
$value = uc $value;
$cloneInfoHash{ $key } = $value;
}
}
}
return (%cloneInfoHash);
}
#-------------------------------------------------------
=head3 pingNode
Description : Execute a Perl ping for this node
Arguments : Node name
Returns : "ping" if found; or "noping" (if not found)
Example : my $out = xCAT::zvmUtils->pingNode($node);
=cut
#-------------------------------------------------------
sub pingNode {
# Get input node
my ( $class, $node ) = @_;
my $timeout = 2; # how many seconds to wait for response. Default was 5
# call system ping and max count of pings 2
my $out = `ping -W $timeout -c 2 -q $node`;
if ($? != 0) {
# Ping failed, try to get result with execcmdonVM.
my $result = xCAT::zvmUtils->execcmdonVM($::SUDOER, $node, 'date');
if (xCAT::zvmUtils->checkOutput( $result ) == -1) {
return $result;
}
if ($result) {
return ("ping");
}
return ("noping");
}
return ("ping");
}
#-------------------------------------------------------
=head3 onlineZhcpPunch
Description : Online punch device and load VMCP module on zHCP
Arguments : User (root or non-root)
zHCP
Returns : Operation results (Done/Failed)
Example : my $out = xCAT::zvmUtils->onlineZhcpPunch($user, $hcp);
=cut
#-------------------------------------------------------
sub onlineZhcpPunch {
# Get input node
my ( $class, $user, $hcp ) = @_;
my $out = "";
my $subResp = "";
my $rc = "";
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
# Online zHCP's punch
$out = `ssh $user\@$hcp "$sudo cat /sys/bus/ccw/drivers/vmur/0.0.000d/online" 2>&1`;
$rc = $? >> 8;
if ( $rc == 255 ) {
# SSH failure to communicate with zHCP.
$subResp = "Failed to communicate with the zHCP system to get the punch device status";
} elsif ( $rc != 0 ) {
# Generic failure of the command.
chomp( $out );
xCAT::zvmUtils->printSyslog( "onlineZhcpPunch() Failed to get the punch device status on zHCP rc: $rc, out: $out" );
$subResp = "Failed to online the punch device on zHCP rc: $rc, out: $out";
}
if ( $subResp eq "" ) {
if ($out != 1) {
chomp( $out = `ssh $user\@$hcp "$sudo /sbin/cio_ignore -r 000d; /sbin/chccwdev -e 000d"`);
$rc = $? >> 8;
if ( $rc == 0 ) {
$subResp = "Done";
} elsif ( $rc == 255 ) {
# SSH failure to communicate with zHCP.
$subResp = "Failed to communicate with the zHCP system to online the punch device";
} else {
if ( !( $out =~ m/Done$/i ) ) {
xCAT::zvmUtils->printSyslog("onlineZhcpPunch() failed to online the zHCP's punch, cmd output: $out.");
$subResp = "Failed to online the zHCP's punch rc: $rc, out: $out";
}
}
`ssh $user\@$hcp "$sudo which udevadm &> /dev/null && udevadm settle || udevsettle"`;
} else {
$subResp = "Done";
}
}
return $subResp
}
#-------------------------------------------------------
=head3 genCfgdrive
Description : Generate a final config drive to punch
Arguments : Configure file directory
Returns : Generated config drive file path
Example : my $out = xCAT::zvmUtils->genCfgdrive($path);
=cut
#-------------------------------------------------------
sub genCfgdrive {
# Get input node
my ( $class, $cfgpath ) = @_;
my $node = basename($cfgpath);
my $out = xCAT::zvmUtils->injectMNKey($cfgpath);
if ( $out =~ m/Failed/i ) {
xCAT::zvmUtils->printSyslog("genCfgdrive() Failed to generate the final cfgdrive.tgz for target node: $node, out: $out");
return "";
} else {
xCAT::zvmUtils->printSyslog("genCfgdrive() Successfully generated the final cfgdrive.tgz for target node: $node");
return "$cfgpath/cfgdrive.tgz";
}
}
#-------------------------------------------------------
=head3 injectMNKey
Description : Inject xCAT MN's public key to the meta_data.json for target vm
Arguments : Configure file directory
Returns : A message indicate whether the MN's key in injected success or not
Example : my $out = xCAT::zvmUtils->injectMNKey($path);
=cut
#-------------------------------------------------------
sub injectMNKey {
# Get input node
my ( $class, $cfgpath ) = @_;
my $subResp = "";
if ( -e "$cfgpath/cfgdrive.tgz" ) {
system("tar -zxf $cfgpath/cfgdrive.tgz -C $cfgpath ");
} else {
$subResp = "injectMNKey() Failed to find the cfgdrive.tgz under $cfgpath for target node";
return $subResp;
}
# Get xcat key, store it to a hash var for later use
open(my $keyFile, '<', "/root/.ssh/id_rsa.pub");
my $mnKey = <$keyFile>;
close($keyFile);
my @set = ('0' ..'9', 'A' .. 'F');
my $mnKeyName = join '' => map $set[rand @set], 1 .. 8;
my %mnKeyHash = ("name" => $mnKeyName, "type" => "ssh", "data" => $mnKey,);
# Read the file content to a variable named md_json,and close the source file
my $jsonText;
my $MDfile;
if(open($MDfile, '<', "$cfgpath/openstack/latest/meta_data.json")) {
while(<$MDfile>) {
$jsonText .= "$_";
}
} else {
$subResp = "injectMNKey() Failed to open the meta data file for processing";
close($MDfile);
return $subResp;
}
close($MDfile);
# Get the public_keys from meta_data.json, if it not exist, add xCAT's key to meta_data.json directly,
# if already exist, compare if the xCAT's key is same or not with existing one, append xCAT key if not same
my $md_json = decode_json($jsonText);
if (exists $md_json->{"public_keys"}) {
my $publicKeys = $md_json->{"public_keys"};
# Check if xCAT key already exist , append it if not exist.
foreach my $pubkey ( keys %$publicKeys ) {
if ( $publicKeys->{$pubkey} eq $mnKey ) {
last;
}
$publicKeys->{$mnKeyName} = $mnKey;
my @tkeys = $md_json->{"keys"};
push @tkeys, {%mnKeyHash};
#push $md_json->{"keys"}, {%mnKeyHash};
}
} else {
# Set the public_keys and keys with xCAT's key info in meta_data.json
$md_json->{"public_keys"}->{$mnKeyName} = $mnKey;
$md_json->{"keys"}[0] = {%mnKeyHash};
}
# Save the changed meta_data.json to new file
open my $fh, ">", "$cfgpath/meta_data.json";
print $fh encode_json($md_json);
close $fh;
# Replace the meta_data.json file in original config drive with the modified one
system( "find $cfgpath/openstack -name meta_data.json -print | xargs -i cp $cfgpath/meta_data.json {}");
`rm -f $cfgpath/meta_data.json`;
# Tar the file generate the final one
my $oldpath=cwd();
chdir($cfgpath);
system ( "tar -zcf cfgdrive.tgz openstack ec2");
chdir($oldpath);
$subResp = "Done";
return $subResp;
}
#-------------------------------------------------------
=head3 execcmdthroughIUCV
Description : Execute a command to node with IUCV client.
Arguments : User (root or non-root).
zHCP (opencloud user)
VM's userid
command [parms..] the comands and parms with the command which need to execute.
callback
Returns : command result, if success.
if an error:
and $callback then $callback gets error message
returns with string containing (Error) and message
Example : my $out = xCAT::zvmUtils->execcmdthroughIUCV($user, $hcp, $userid, $command);
=cut
#-------------------------------------------------------
sub execcmdthroughIUCV {
my ($class, $user, $hcp, $userid, $commandwithparm, $callback) = @_;
my $result = '';
my $rsp;
my $msg;
my $iucvpath = '/opt/zhcp/bin/IUCV';
my $isCallback = 0;
if (defined $callback) {
$isCallback = 1;
}
$result= `ssh $user\@$hcp $::SUDO $iucvpath/iucvclnt $userid "\'$commandwithparm\'" 2>&1`;
my $rc = $? >> 8;
$result = xCAT::zvmUtils->trimStr( $result );
if ( $isCallback || $rc == 0 ){
xCAT::zvmUtils->printSyslog("$userid: IUCV command: ssh $user\@$hcp $::SUDO $iucvpath/iucvclnt $userid $commandwithparm. return $rc\n $result");
} else {
xCAT::zvmUtils->printSyslog("$userid: IUCV command: ssh $user\@$hcp $::SUDO $iucvpath/iucvclnt $userid $commandwithparm.");
}
if ( $rc == 0 ) {
if ($result eq ''){
return "Done";
}
return $result;
} elsif ( $rc == 1 ) {
$msg = "Issued command was not authorized or a generic Linux error occurred. error details $result";
push @{$rsp->{data}}, $msg;
} elsif ( $rc == 2 ) {
$msg = "parameter to iucvclient error, $result";
push @{$rsp->{data}}, $msg
} elsif ( $rc == 4 ) {
$msg = "IUCV socket error, error details $result";
push @{$rsp->{data}}, $msg;
} elsif ( $rc == 8 ) {
$msg = "Command executed failed, error details $result";
push @{$rsp->{data}}, $msg;
} elsif ( $rc == 16 ) {
$msg = "File Transport failed, error details $result";
push @{$rsp->{data}}, $msg;
} elsif ( $rc == 32 ) {
$msg = "File Transport failed, error details $result";
push @{$rsp->{data}}, $msg;
}
# Error occurred
if ($isCallback){
xCAT::MsgUtils->message( "E", $rsp, $callback );
}
return "(Error) $msg";
}
#-------------------------------------------------------
=head3 cleanIUCV
Description : rollback IUCV to clean all the files that copy to it.
Arguments : User (root or non-root).
VM's node
VM's system
Returns : Nothing
Example : xCAT::zvmUtils->cleanIUCV( $user, $hcp, $userid);
=cut
#-------------------------------------------------------
sub cleanIUCV {
my ($class, $user, $node, $os) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
my $result = '';
my $outmsg = '';
my $cmd = '';
my $rc;
my $trgtiucvpath = "/usr/bin/iucvserv";
my $trgtiucvservicepath_rh6_sl11 = "/etc/init.d/iucvserd";
my $trgtiucvservicepath_rh7 = "/lib/systemd/system/iucvserd.service";
my $trgtiucvservicepath_ubuntu16 = "/lib/systemd/system/iucvserd.service";
my $trgtiucvservicepath_sl12 = "/usr/lib/systemd/system/iucvserd.service";
#clean iucv server file
$cmd = "ssh -o ConnectTimeout=5 $user\@$node rm -rf $trgtiucvpath 2>&1";
$result = `ssh -o ConnectTimeout=5 $user\@$node rm -rf $trgtiucvpath 2>&1`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "$cmd", $node, "cleanIUCV", $result, $result, $node );
# Continue processing even if an error.
#clean iucv server service file
if ( $os =~ m/sles11/i or $os =~ m/rhel6/i ) {
$cmd = "ssh -o ConnectTimeout=5 $user\@$node rm -rf $trgtiucvservicepath_rh6_sl11 2>&1";
$result = `ssh -o ConnectTimeout=5 $user\@$node rm -rf $trgtiucvservicepath_rh6_sl11 2>&1`;
}
elsif ( $os =~ m/sles12/i ) {
$cmd = "ssh -o ConnectTimeout=5 $user\@$node rm -rf $trgtiucvservicepath_sl12 2>&1";
$result = `ssh -o ConnectTimeout=5 $user\@$node rm -rf $trgtiucvservicepath_sl12 2>&1`;
}
elsif ( $os =~ m/rhel7/i){
$cmd = "ssh -o ConnectTimeout=5 $user\@$node rm -rf $trgtiucvservicepath_rh7 2>&1";
$result = `ssh -o ConnectTimeout=5 $user\@$node rm -rf $trgtiucvservicepath_rh7 2>&1`;
} elsif ( $os =~ m/ubuntu16/i){
$cmd = "ssh -o ConnectTimeout=5 $user\@$node rm -rf $trgtiucvservicepath_ubuntu16 2>&1";
$result = `ssh -o ConnectTimeout=5 $user\@$node rm -rf $trgtiucvservicepath_ubuntu16 2>&1`;
}
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "$cmd", $node, "cleanIUCV", $result, $node );
# Continue processing even if an error.
#clean iucv server authorized file
$cmd = "ssh -o ConnectTimeout=5 $user\@$node rm -rf $trgtiucvpath 2>&1";
$result = `ssh -o ConnectTimeout=5 $user\@$node rm -rf $trgtiucvpath 2>&1`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "$cmd", $node, "cleanIUCV", $result, $node );
# Continue processing even if an error.
#clean iucv server service start
if ( $os =~ m/sles11/i or $os =~ m/rhel6/i ){
$cmd = "ssh -o ConnectTimeout=5 $user\@$node \"chkconfig --del iucvserd && service iucvserd stop 2>&1";
$result = `ssh -o ConnectTimeout=5 $user\@$node "chkconfig --del iucvserd && service iucvserd stop 2>&1"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "$cmd", $node, "cleanIUCV", $result, $node );
# Continue processing even if an error.
}else{
$cmd = "ssh -o ConnectTimeout=5 $user\@$node \"systemctl disable iucvserd.service && systemctl stop iucvserd.service 2>&1";
$result = `ssh -o ConnectTimeout=5 $user\@$node "systemctl disable iucvserd.service && systemctl stop iucvserd.service 2>&1"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "$cmd", $node, "cleanIUCV", $result, $node );
# Continue processing even if an error.
}
}
#-------------------------------------------------------
=head3 setsshforvm
Description : If IUCV communication failed, try to use ssh to make communication.
Arguments : User (root or non-root).
VM's node
VM's linux system type
command [parms..] the comands and parms with the command which need to execute.
error message which is got in setup IUCV
current VM's status in zvm table
callback
Returns : command result, if success.
if an error:
and $callback then $callback gets error message and routine returns with 1
if no $callback then routine returns with string containing Error: and message
Example : my $out = xCAT::zvmUtils->setsshforvm($user, $node, $os, $commandwithparm, $msg, $status, $callback);
=cut
#-------------------------------------------------------
sub setsshforvm {
my ($class, $user, $node, $os, $commandwithparm, $msg, $status, $callback) = @_;
my $result ='';
my $rsp;
my $isCallback = 0;
my $outmsg = '';
my $rc;
if (defined $callback) {
$isCallback = 1;
}
#clean IUCV server first.
$result = xCAT::zvmUtils->cleanIUCV($user, $node, $os);
if (xCAT::zvmUtils->checkOutput( $result ) == -1) {
return $result;
}
# check whether the vm can be ping, if so then set ssh to zvm table,
# to indicate that it use ssh.
my $ping = `ping -W 2 -c 2 -q $node`;
if ($? == 0) {
my $cmd = "ssh -o ConnectTimeout=5 $user\@$node \"$commandwithparm\"";
$result = `ssh -o ConnectTimeout=5 $user\@$node "$commandwithparm"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "$cmd", $node, "setsshforvm", $result, $node );
if ($rc == 255) {
if ($isCallback){
xCAT::zvmUtils->printLn( $callback, "$outmsg");
}
# Continue processing even if an error.
}
if ($status){
$status = "$status;SSH=1";
}else{
$status = "SSH=1";
}
xCAT::zvmUtils->setNodeProp( 'zvm', $node, 'status', $status );
xCAT::zvmUtils->printSyslog("$node: Set SSH=1 for node $node");
if ($isCallback){
xCAT::zvmUtils->printLn( $callback, "$node: Set SSH=1 for node $node.");
}
return $result;
}
# Error occurred on ping
if ($callback){
push @{$rsp->{data}}, $msg;
xCAT::MsgUtils->message( "E", $rsp, $callback );
}
xCAT::zvmUtils->printSyslog("$node: $msg");
return "$msg";
}
#-------------------------------------------------------
=head3 execcmdonVM
Description : Execute a command to node.
Arguments : User (root or non-root).
VM's node
command [parms..] the comands and parms with the command which need to execute.
callback
Returns : command result, if success.
if an error:
and $callback then $callback gets error message
routine returns with string containing Error: and message
Example : my $out = xCAT::zvmUtils->execcmdonVM($user, $node, $commandwithparm, $callback);
=cut
#-------------------------------------------------------
sub execcmdonVM {
my ($class, $user, $node, $commandwithparm, $callback) = @_;
# get HCP and z/VM userid
my @propNames = ( 'hcp', 'userid', 'status' );
my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
my $status = $propVals->{'status'};
if(!(defined($status))){
$status = '';
}
my $hcp = $propVals->{'hcp'};
my $userid = $propVals->{'userid'};
my $isCallback = 0;
if (defined $callback) {
$isCallback = 1;
}
my $result = '';
my $outmsg = '';
my $rsp;
my $rc;
my $msg = '';
my $cmd = '';
my $opnclouduserid='OPNCLOUD';
my $simplecmd = 'date';
# Create path string
my $dest = "$user\@$node";
my $srciucvpath = '/opt/zhcp/bin/IUCV';
my $trgtiucvpath = "/usr/bin/iucvserv";
my $trgtiucvservicepath_rh6_sl11 = "/etc/init.d/iucvserd";
my $trgtiucvservicepath_rh7 = "/lib/systemd/system/iucvserd.service";
my $trgtiucvservicepath_sl12 = "/usr/lib/systemd/system/iucvserd.service";
my $trgtiucvservicepath_ubuntu16 = "/lib/systemd/system/iucvserd.service";
my $authorizedfilepath = "/etc/iucv_authorized_userid";
my $xcatuserid = `vmcp q userid | awk '{print \$1}'`;
chomp($xcatuserid);
# Add escape for IUCV and SSH commands.
if ($commandwithparm =~ '\\\"'){
$commandwithparm =~ s/"/\\"/g;
}
$commandwithparm =~ s/"/\\"/g;
# For not xcat deployed node, use SSH to make communication.
if (!(defined($userid)) || !(defined($hcp))){
$cmd = "ssh -o ConnectTimeout=5 $user\@$node \"$commandwithparm\"";
$result = `ssh -o ConnectTimeout=5 $user\@$node "$commandwithparm"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "$cmd", $node, "execcmdonVM", $result, $node );
if ($rc == 255) {
if ($isCallback){
xCAT::zvmUtils->printLn( $callback, "$outmsg");
}
}
# Remove IUCV=1 if it has been set
if ($status =~ /IUCV=1/){
$status =~ s/IUCV=1/SSH=1/g;
xCAT::zvmUtils->setNodeProp( 'zvm', $node, 'status', $status );
}
return $result;
}
$userid =~ tr/a-z/A-Z/;
# For normal managed nodes, ask zhcp to query the power state
if (($userid ne $xcatuserid) && !($hcp =~ /$node/) && ($hcp ne '')){
# Get VM's power stat first, if power stat is off, return error.
my $max = 0;
while ( !$result && $max < 10 ) {
$cmd = "ssh $::SUDOER\@$hcp \"$::SUDO /sbin/vmcp q user $userid 2>/dev/null\" | sed 's/HCPCQU045E.*/off/' | sed 's/$userid.*/on/'";
$result = `ssh $::SUDOER\@$hcp "$::SUDO /sbin/vmcp q user $userid 2>/dev/null" | sed 's/HCPCQU045E.*/off/' | sed 's/$userid.*/on/'`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "$cmd", $hcp, "execcmdonVM", $result, $node );
if ($rc == 255) {
if ($isCallback){
xCAT::zvmUtils->printLn( $callback, "$outmsg");
}
return $outmsg;
}
$max++;
}
#xCAT::zvmUtils->printSyslog("$node: ssh $::SUDOER\@$hcp \"$::SUDO /sbin/vmcp q user $userid 2>/dev/null\" | sed 's/HCPCQU045E.*/off/' | sed 's/$userid.*/on/' ##$result##");
if ("off" =~ $result) {
my $msgText = "$node: (Error) VM $userid is powered off";
xCAT::zvmUtils->printSyslog("$msgText");
if ($isCallback) {
xCAT::zvmUtils->printLn( $callback, "$msgText");
}
return "$msgText";
}
if (!($status =~ /SSH=1/) && !($status =~ /IUCV=1/)){
# if zhcp direct entry does set "IUCV ANY", will set to SSH directly.
my $hcpUserId = xCAT::zvmCPUtils->getUserId($user, $hcp);
@propNames = ( 'status' );
$propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $hcp, @propNames );
my $iucvanystatus = $propVals->{'status'};
if (!($iucvanystatus =~ m/IUCVANY/i)){
xCAT::zvmUtils->printSyslog("$node: zhcp's IUCVANY status is not set");
my $out = `ssh $user\@$hcp "$::SUDO /opt/zhcp/bin/smcli Image_Query_DM -T $hcpUserId"| egrep -i "IUCV ANY"`;
if ( $out =~ m/IUCV ANY/i){
if ($iucvanystatus){
$iucvanystatus = "$status;IUCVANY=1";
}else{
$iucvanystatus = "IUCVANY=1";
}
}else{
if ($iucvanystatus){
$iucvanystatus = "$status;IUCVANY=0";
}else{
$iucvanystatus = "IUCVANY=0";
}
}
xCAT::zvmUtils->setNodeProp( 'zvm', $hcp, 'status', $iucvanystatus );
xCAT::zvmUtils->printSyslog("$node: zhcp's status is $iucvanystatus");
}
if ($iucvanystatus =~ m/IUCVANY=0/i){
xCAT::zvmUtils->printSyslog("$node: zhcp doesn't support to make communication with IUCV, set SSH=1 for $node");
if ($status){
$status = "$status;SSH=1";
}else{
$status = "SSH=1";
}
xCAT::zvmUtils->setNodeProp( 'zvm', $node, 'status', $status );
}
}
}
# If node userid is xcat or zhcp, only use SSH.
if (($status =~ /SSH=1/) || ($userid eq $xcatuserid) || ($hcp =~ /$node/) || ($hcp eq '')){
# SSH=1, Use ssh to make communication.
$cmd = "ssh -o ConnectTimeout=5 $user\@$node \"$commandwithparm\"";
$result = `ssh -o ConnectTimeout=5 $user\@$node "$commandwithparm"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "$cmd", $node, "execcmdonVM", $result, $node );
if ($rc == 255) {
if ($isCallback){
xCAT::zvmUtils->printLn( $callback, "$outmsg");
}
}
return $result;
}elsif ($status =~ /IUCV=1/){
#xCAT::zvmUtils->printSyslog("$node: IUCV command: $commandwithparm");
# IUCV=1, Use IUCV to make communication.
$result = xCAT::zvmUtils->execcmdthroughIUCV($user, $hcp, $userid, $commandwithparm, $callback);
return $result;
}
xCAT::zvmUtils->printSyslog("$node: VM $userid doesn't set communicate type, will set it first." );
my $releaseInfo = `ssh -qo ConnectTimeout=2 $user\@$node "$::SUDO ls /dev/null $locAllEtcVerFiles 2>/dev/null | xargs grep ''"`;
if (xCAT::zvmUtils->checkOutput( $releaseInfo ) == -1) {
return $releaseInfo;
}
my $os = buildOsVersion( $callback, $releaseInfo, 'all' );
# For the existed VMs which are deployed with SSH, will try to copy IUCV files to them.
# These VMs are not set communication type, try IUCV first and set the type after communication.
# if IUCV server doesn't exist on xcat /var/lib/sspmod, first to copy from OPNCLOUD.
if ( not (-e "$srciucvpath/iucvserv" and -e "$srciucvpath/iucvserd"
and -e "$srciucvpath/iucvserd.service" )) {
$result= `mkdir -p $srciucvpath && scp -p $user\@$hcp:$srciucvpath/iucvser* $srciucvpath 2>&1`;
$rc = $? >>8 ;
xCAT::zvmUtils->printSyslog("$node: IUCV server files doesn't exist on xcat $srciucvpath, copy from OPNCLOUD.return $rc, $result");
if ($rc != 0) {
$msg = "Failed to copy $user\@$hcp:$srciucvpath/iucvser* to $srciucvpath. $result";
return xCAT::zvmUtils->setsshforvm($user, $node, $os, $commandwithparm, $msg, $status, $callback);
}
}
# Check whether IUCV server is installed.
$result = xCAT::zvmUtils->execcmdthroughIUCV($user, $hcp, $userid, $commandwithparm, $callback);
$rc = $? >> 8;
xCAT::zvmUtils->printSyslog("$node: try to execute command through IUCV. $result return $?" );
if ( $rc != 0 ){
#IUCV server doesn't exist on node, copy file to it and restart service
if ($result =~ "ERROR connecting socket") {
xCAT::zvmUtils->printSyslog("$node: start to set iucv, first to copy iucv server files and start iucv server service" );
#copy IUCV server files.
$result = `/usr/bin/scp -p $srciucvpath/iucvserv $dest:$trgtiucvpath 2>&1`;
$rc = $? >> 8;
xCAT::zvmUtils->printSyslog("$node: /usr/bin/scp -p $srciucvpath/iucvserv $dest:$trgtiucvpath 2>&1 return $rc\n $result");
if ($rc != 0) {
$msg = "Failed to copy $srciucvpath/iucvserv to $dest:$trgtiucvpath. $result";
return xCAT::zvmUtils->setsshforvm($user, $node, $os, $commandwithparm, $msg, $status, $callback);
}
if ( $os =~ m/sles11/i or $os =~ m/rhel6/i ) {
$result = `/usr/bin/scp -p $srciucvpath/iucvserd $dest:$trgtiucvservicepath_rh6_sl11 2>&1`;
}
elsif ( $os =~ m/sles12/i ) {
$result = `/usr/bin/scp -p $srciucvpath/iucvserd.service $dest:$trgtiucvservicepath_sl12 2>&1`;
}
elsif ( $os =~ m/rhel7/i){
$result = `/usr/bin/scp -p $srciucvpath/iucvserd.service $dest:$trgtiucvservicepath_rh7 2>&1`;
} elsif ( $os =~ m/ubuntu16/i){
# Note: we should not encounter this line as we don't have ubuntu support before IUCV enablement
$result = `/usr/bin/scp -p $srciucvpath/iucvserd.service $dest:$trgtiucvservicepath_ubuntu16 2>&1`;
}
$rc = $? >> 8;
xCAT::zvmUtils->printSyslog("$node: /usr/bin/scp -p iucv service file return $rc $result");
if ($rc != 0) {
$msg = "Failed to copy iucvservice file. $result";
return xCAT::zvmUtils->setsshforvm($user, $node, $os, $commandwithparm, $msg, $status, $callback);
}
$opnclouduserid = xCAT::zvmCPUtils->getUserId($user, $hcp);
$opnclouduserid =~ tr/a-z/A-Z/;
if ($rc !=0) {
$msg = "failed to get OPNCLOUD userid. return $? \n$result";
return xCAT::zvmUtils->setsshforvm($user, $node, $os, $commandwithparm, $msg, $status, $callback);
}
$cmd = "ssh -o ConnectTimeout=5 $user\@$node \"echo -n $opnclouduserid >$authorizedfilepath\" 2>&1";
$result = `ssh -o ConnectTimeout=5 $user\@$node "echo -n $opnclouduserid >$authorizedfilepath" 2>&1`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "$cmd", $node, "execcmdonVM", $result, $node );
if ($rc != 0) {
if ($isCallback){
xCAT::zvmUtils->printLn( $callback, "$outmsg");
}
$msg = "echo -n $hcp >$authorizedfilepath, failed to create authorized userid for $node. return $rc $result";
return xCAT::zvmUtils->setsshforvm($user, $node, $os, $commandwithparm, $msg, $status, $callback);
}
# Start service of IUCV server
if ( $os =~ m/sles11/i or $os =~ m/rhel6/i ){
$cmd = "ssh -o ConnectTimeout=5 $user\@$node \"chkconfig --add iucvserd && service iucvserd start 2>&1\"";
$result = `ssh -o ConnectTimeout=5 $user\@$node "chkconfig --add iucvserd && service iucvserd start 2>&1"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "$cmd", $node, "execcmdonVM", $result, $node );
if ($rc != 0) {
if ($isCallback){
xCAT::zvmUtils->printLn( $callback, "$outmsg");
}
$msg = "echo -n $hcp >$authorizedfilepath, failed to create authorized userid for $node. return $rc $result";
return xCAT::zvmUtils->setsshforvm($user, $node, $os, $commandwithparm, $msg, $status, $callback);
}
}else{
$cmd = "ssh -o ConnectTimeout=5 $user\@$node \"systemctl enable iucvserd.service && systemctl start iucvserd.service 2>&1\"";
$result = `ssh -o ConnectTimeout=5 $user\@$node "systemctl enable iucvserd.service && systemctl start iucvserd.service 2>&1"`;
($rc, $outmsg) = xCAT::zvmUtils->checkSSH_Rc( $?, "$cmd", $node, "execcmdonVM", $result, $node );
if ($rc != 0) {
if ($isCallback){
xCAT::zvmUtils->printLn( $callback, "$outmsg");
}
$msg = "echo -n $hcp >$authorizedfilepath, failed to create authorized userid for $node. return $rc $result";
return xCAT::zvmUtils->setsshforvm($user, $node, $os, $commandwithparm, $msg, $status, $callback);
}
}
$rc = $? >> 8;
xCAT::zvmUtils->printSyslog("$node: start iucvserver service return $rc. $result");
# Now that the IUCV server has started successfully, send a simple command
if ($rc == 0) {
$result = xCAT::zvmUtils->execcmdthroughIUCV($user, $hcp, $userid, $simplecmd, $callback);
# The simple command worked! Update the zvm table so we always communicate via IUCV
if ($? == 0){
xCAT::zvmUtils->printSyslog("$node: successfully initialized IUCV, Set IUCV=1 for $user");
if ($callback){
xCAT::zvmUtils->printLn( $callback, "$node: successfully initialized IUCV, Set IUCV=1 for $user");
}
if ($status){
$status = "$status;IUCV=1";
}else{
$status = "IUCV=1";
}
xCAT::zvmUtils->setNodeProp( 'zvm', $node, 'status', $status );
return xCAT::zvmUtils->execcmdthroughIUCV($user, $hcp, $userid, $commandwithparm, $callback);
}else{
$msg = "$node: Failed to start iucvserver, result is $result";
return xCAT::zvmUtils->setsshforvm($user, $node, $os, $commandwithparm, $msg, $status, $callback);
}
} else {
$msg = "$node: Failed to start iucvserver, result is $result";
return xCAT::zvmUtils->setsshforvm($user, $node, $os, $commandwithparm, $msg, $status, $callback);
}
# If our command failed, just return the error
} elsif ($result =~ /Command executed failed/) {
return $result;
} else {
$msg = "$node: IUCV server on VM got another error that is not a socket error, result is $result";
return xCAT::zvmUtils->setsshforvm($user, $node, $os, $commandwithparm, $msg, $status, $callback);
}
} else {
$msg = "IUCV has worked well, set IUCV=1 for $user .";
if ($status) {
$status = "$status;IUCV=1";
} else {
$status = "IUCV=1";
}
xCAT::zvmUtils->setNodeProp( 'zvm', $node, 'status', $status );
return $result;
}
}