xcat-core/perl-xCAT/xCAT/zvmUtils.pm
2013-10-23 15:40:25 -04:00

3062 lines
88 KiB
Perl

# IBM(c) 2013 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 strict;
use warnings;
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\)|\sfailed)/i) { # Set to print error if the string contains error
$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 like '%" . $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*"`;
@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*"`;
@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*"`;
@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*"`;
@parms = split( '\n', $out );
# Go through each line
foreach (@parms) {
# If the network file contains the NIC address
$out = `ssh -o ConnectTimeout=5 $user\@$node "$sudo cat $_" | egrep -i "$nic"`;
if ($out) {
# Return network file path
return ($_);
}
}
}
# 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"`;
@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 @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"`;
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 : Nothing
Example : xCAT::zvmUtils->sendFile($user, $node, $srcFile, $trgtFile);
=cut
#-------------------------------------------------------
sub sendFile {
# Get inputs
my ( $class, $user, $node, $srcFile, $trgtFile ) = @_;
# Create destination string
my $dest = "$user\@$node";
# SCP directory entry file over to HCP
my $out = `/usr/bin/scp $srcFile $dest:$trgtFile`;
return;
}
#-------------------------------------------------------
=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 ) = @_;
# Get the root device node
# LVM is not supported
my $out = `ssh $user\@$node "mount" | grep "/ 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.//'`;
@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 : Nothing
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" ) {
$out = `ssh $user\@$node "$sudo /sbin/chccwdev $option $devAddr"`;
}
return ($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
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 $out = `ssh $user\@$hcp "$sudo $dir/getuserentry $userId" | grep "MDISK"`;
# Get MDISK statements
my @lines = split( '\n', $out );
my @disks;
foreach (@lines) {
$_ = 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
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 $out = `ssh $user\@$hcp "$sudo $dir/smcli Image_Query_DM -T $userId" | egrep -i "DEDICATE"`;
# Get DEDICATE statements
my @lines = split( '\n', $out );
my @dedicates;
foreach (@lines) {
$_ = xCAT::zvmUtils->trimStr($_);
# Save statements
push( @dedicates, $_ );
}
return (@dedicates);
}
#-------------------------------------------------------
=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
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 $out = `ssh $user\@$hcp "$sudo $dir/smcli Image_Query_DM -T $userId" | sed '\$d' | grep -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($callback, $out);
=cut
#-------------------------------------------------------
sub checkOutput {
my ( $class, $callback, $out ) = @_;
# Check output string
my @outLn = split( "\n", $out );
foreach (@outLn) {
# If output contains 'Failed', 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($callback, $out, \$reason);
=cut
#-------------------------------------------------------
sub checkOutputExtractReason {
my ( $class, $callback, $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 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 @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"`;
$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"`;
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
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 $prefix = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo /sbin/vmcp q vmlan" | egrep -i "USER Prefix:"`;
$prefix =~ s/(.*?)USER Prefix:(.*)/$2/;
$prefix =~ s/^\s+//;
$prefix =~ s/\s+$//;
# Get MACADDR Prefix instead if USER Prefix is not defined
if (!$prefix) {
$prefix = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo /sbin/vmcp q vmlan" | egrep -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 @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"`;
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 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
Returns : Operating system name
Example : my $os = xCAT::zvmUtils->getOsVersion($user, $node);
=cut
#-------------------------------------------------------
sub getOsVersion {
# Get inputs
my ( $class, $user, $node ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
my $os = '';
my $version = '';
# Get operating system
my $release = `ssh -o ConnectTimeout=2 $user\@$node "$sudo cat /etc/*release"`;
my @lines = split('\n', $release);
if (grep(/SUSE Linux Enterprise Server/, @lines)) {
$os = 'sles';
$version = `echo "$release" | grep "VERSION ="`;
$version =~ s/\s*$//;
$version =~ s/^\s*//;
$version =~ tr/\.//;
$version =~ s/[^0-9]*([0-9]+).*/$1/;
$os = $os . $version;
# Append service level
$version = `echo "$release" | grep "LEVEL ="`;
$version =~ s/\s*$//;
$version =~ s/^\s*//;
$version =~ tr/\.//;
$version =~ s/[^0-9]*([0-9]+).*/$1/;
$os = $os . 'sp' . $version;
} elsif (grep(/Red Hat Enterprise Linux Server/, @lines)) {
$os = 'rhel';
$version = $lines[0];
$version =~ tr/\.//;
$version =~ s/([A-Za-z\s\(\)]+)//g;
$os = $os . $version;
}
return xCAT::zvmUtils->trimStr($os);
}
#-------------------------------------------------------
=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 @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"`;
$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 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 like '%" . $node . "%'", 'type' );
foreach (@results) {
# Return 'TRUE' if given node is in the table
if ($_->{"type"} eq "zvm") {
return 1;
}
}
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';
# 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"`;
} 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
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 $time = `ssh $user\@$hcp "$sudo $dir/smcli Image_Performance_Query -T $userId -c 1" | egrep -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"`;
$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
Example : my $out = xCAT::zvmCPUtils->getLparCpuTotal($user, $hcp);
=cut
#-------------------------------------------------------
sub getLparCpuTotal {
my ($class, $user, $hcp) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo cat /proc/sysinfo" | grep "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
Example : my $out = xCAT::zvmCPUtils->getLparCpuUsed($user, $hcp);
=cut
#-------------------------------------------------------
sub getLparCpuUsed {
my ($class, $user, $hcp) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo cat /proc/sysinfo" | grep "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
Example : my $out = xCAT::zvmCPUtils->getCecModel($user, $hcp);
=cut
#-------------------------------------------------------
sub getCecModel {
my ($class, $user, $hcp) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo cat /proc/sysinfo" | grep "^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
Example : my $out = xCAT::zvmCPUtils->getCecVendor($user, $hcp);
=cut
#-------------------------------------------------------
sub getCecVendor {
my ( $class, $user, $hcp ) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo cat /proc/sysinfo" | grep "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
Example : my $out = xCAT::zvmCPUtils->getHypervisorInfo($user, $hcp);
=cut
#-------------------------------------------------------
sub getHypervisorInfo {
my ($class, $user, $hcp) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
my $out = `ssh -o ConnectTimeout=5 $user\@$hcp "$sudo cat /proc/sysinfo" | grep "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
Example : my $out = xCAT::zvmCPUtils->getLparMemoryTotal($user, $hcp);
=cut
#-------------------------------------------------------
sub getLparMemoryTotal {
my ($class, $user, $hcp) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
my $out = `ssh $user\@$hcp "$sudo /opt/zhcp/bin/smcli System_Info_Query" | grep "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
Example : my $out = xCAT::zvmCPUtils->getLparMemoryOffline($user, $hcp);
=cut
#-------------------------------------------------------
sub getLparMemoryOffline {
my ($class, $user, $hcp) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
my $out = `ssh $user\@$hcp "$sudo /opt/zhcp/bin/smcli System_Info_Query" | grep "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
Example : my $out = xCAT::zvmCPUtils->getLparMemoryUsed($user, $hcp);
=cut
#-------------------------------------------------------
sub getLparMemoryUsed {
my ($class, $user, $hcp) = @_;
my $sudo = "sudo";
if ($user eq "root") {
$sudo = "";
}
my $out = `ssh $user\@$hcp "$sudo /opt/zhcp/bin/smcli System_Performance_Info_Query " | grep "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 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
Returns : If successful, return file path. Otherwise, return -1
Example : my $out = xCAT::zvmUtils->generateUserEntryFile($userId, $password, $memorySize, $privilege, $profileName, $cpuCount);
=cut
#-------------------------------------------------------
sub generateUserEntryFile {
my ( $class, $userId, $password, $memorySize, $privilege, $profileName, $cpuCount ) = @_;
# 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)
}
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
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 $ssi = `ssh -o ConnectTimeout=10 $user\@$hcp "$sudo $dir/smcli SSI_Query" | egrep -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"`;
return $out;
}
# Encapsulate command in single quotes
$cmd = "'" . $cmd . "'";
$out = `ssh $user\@$node "$sudo sh -c $cmd"`;
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
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 @devices = split("\n", `ssh $user\@$hcp "$sudo cat $pool/*.conf" | egrep -i "used|allocated"`);
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
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;
}
my $masterIp = xCAT::TableUtils->get_site_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 $rc = `ssh $sudoer\@$hcp "$sudo mount | grep $$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`;
$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)
- 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) = @_;
# 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)
my $out;
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,,,
my @devices = split("\n", `ssh $user\@$hcp "$sudo cat $zfcpDir/$pool.conf" | egrep -i ^free`);
$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" | grep -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];
}
# If there are multiple paths, take the 1st one
# Handle multi-pathing in postscript because autoyast/kickstart does not support it.
my $origWwpn = $wwpn;
if ($wwpn =~ m/;/i) {
@info = split(';', $wwpn);
$wwpn = xCAT::zvmUtils->trimStr($info[0]);
}
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" | grep -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,$origWwpn,$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
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);
my $hcpUserId = xCAT::zvmCPUtils->getUserId($user, $hcp);
$hcpUserId =~ tr/a-z/A-Z/;
# Find a free FCP channel
my $out = `ssh $user\@$hcp "$sudo $dir/smcli System_WWPN_Query -T $hcpUserId" | egrep -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
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 @pools = split("\n", `ssh $user\@$hcp "$sudo grep -i -l \"$wwpn,$lun\" $zfcpDir/*.conf"`);
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
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 @info = split("\n", `ssh $user\@$hcp "$sudo grep -i \"$wwpn,$lun\" $zfcpDir/$pool.conf"`);
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 containing the HCP network
$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;
}