# 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/.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; }