mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-11-04 05:12:30 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			3026 lines
		
	
	
		
			110 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			3026 lines
		
	
	
		
			110 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
#!/usr/bin/perl
 | 
						|
###############################################################################
 | 
						|
# IBM (C) Copyright 2016 Eclipse Public License
 | 
						|
# http://www.eclipse.org/org/documents/epl-v10.html
 | 
						|
###############################################################################
 | 
						|
# COMPONENT: verifynode
 | 
						|
#
 | 
						|
# Verify the capabilities of a node.
 | 
						|
###############################################################################
 | 
						|
 | 
						|
package xCAT_plugin::verifynode;
 | 
						|
BEGIN
 | 
						|
{
 | 
						|
    $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
 | 
						|
}
 | 
						|
 | 
						|
$XML::Simple::PREFERRED_PARSER='XML::Parser';
 | 
						|
 | 
						|
use strict;
 | 
						|
use warnings;
 | 
						|
 | 
						|
use Data::Dumper qw(Dumper);
 | 
						|
use File::Basename;
 | 
						|
use File::Path;
 | 
						|
use File::Spec;
 | 
						|
use File::Temp;
 | 
						|
use Getopt::Long;
 | 
						|
use Getopt::Long qw(GetOptionsFromString);
 | 
						|
use lib "$::XCATROOT/lib/perl";
 | 
						|
use MIME::Base64;
 | 
						|
use POSIX qw/strftime/;
 | 
						|
use Scalar::Util qw( looks_like_number );
 | 
						|
use Sys::Hostname;
 | 
						|
use Sys::Syslog qw( :DEFAULT setlogsock );
 | 
						|
use Socket;
 | 
						|
use Text::Wrap;
 | 
						|
use Time::HiRes qw( gettimeofday sleep );
 | 
						|
use Unicode::UCD qw(charinfo);
 | 
						|
 | 
						|
use xCAT::zvmCPUtils;
 | 
						|
use xCAT::zvmMsgs;
 | 
						|
use xCAT::zvmUtils;
 | 
						|
 | 
						|
my $version = "1";
 | 
						|
 | 
						|
my $comments = '';                     # Comments for the IVP run
 | 
						|
my $dataFile = '';                     # Input data file
 | 
						|
my $decode = '';                       # String specified by the --decode operand.
 | 
						|
my $disable = '';                      # Disable scheduled IVP from running.
 | 
						|
my $displayHelp = 0;                   # Display help information
 | 
						|
my $driver = '';                       # Name of driver script
 | 
						|
my $driverLoc = '/var/opt/xcat/ivp';   # Local directory containing the driver script, if it exists
 | 
						|
my $encode = '';                       # String specified by the --encode operand.
 | 
						|
my $enable = '';                       # Enable scheduled IVP to run.
 | 
						|
my $endTime = '';                      # Human readable end time
 | 
						|
my %hosts;                             # Information on host nodes known by xCAT MN
 | 
						|
my $id = '';                           # Id of the IVP run
 | 
						|
my %ignored;                           # List of ignored messages
 | 
						|
my $ignoreCnt = 0;                     # Number of times we ignored a message
 | 
						|
my $issueCmdOverIUCV = '';             # Issue a command to a node over IUCV
 | 
						|
my $issueCmdToNode = '';               # Issue a command to a node using IUCV or SSH
 | 
						|
my %localIPs;                          # Hash of the Local IP addresses for the xCAT MN system
 | 
						|
my $logDir = '/var/log/xcat/ivp';      # Log location
 | 
						|
my $logFile = '';                      # Log file name and location
 | 
						|
my $logFileHandle;                     # File handle for the log file.
 | 
						|
my @ivpSummary;                        # Summary output lines for an IVP run.
 | 
						|
my $locApplSystemRole = '/var/lib/sspmod/appliance_system_role';
 | 
						|
my %mnInfo;                            # Managed node environment information
 | 
						|
my %msgsToIgnore;                      # Hash of messages to ignore
 | 
						|
my $needToFinishLogFile = 0;           # If 1 then finishLogFile() needs to be called
 | 
						|
my $nodeName = '';                     # Name of node to be verified
 | 
						|
my $notify = 0;                        # Notify a user
 | 
						|
my $notifyOnErrorOrWarning = 0;        # Indicates a log file should be sent if the need to notify
 | 
						|
                                       #   a user was determined.
 | 
						|
my $openstackIP = '';                  # IP address of the OpenStack node
 | 
						|
my $openstackUser = 'root';            # User on the OpenStack system that can access the
 | 
						|
                                       # OpenStack configuration files
 | 
						|
my $orchParms = '';                    # Orchestrator parms to be stored in the zvmivp table
 | 
						|
my $prepParms = '';                    # Parameters to pass to the preparation script
 | 
						|
my $remove = 0;                        # Remove a scheduled IVP
 | 
						|
my $runBasicIVP = 0;                   # Run the basic xCAT IVP
 | 
						|
my $runCron = 0;                       # Cron job invocation to run a possible set of IVPs
 | 
						|
                                       # on a periodic basis.
 | 
						|
my $runFullIVP = 0;                    # Run the full end to end IVP (compute node and xCAT)
 | 
						|
my $schedule = '';                     # Hours to schedule an automated IVP
 | 
						|
my $scheduledType = '';                # Type of IVP to schedule ('fullivp' or 'basicivp')
 | 
						|
my $startTime = '';                    # Human readable start time
 | 
						|
my $tgtOS = '';                        # Target Node's distro & version
 | 
						|
my $todayDate = '';                    # Today's date in the form 'yyyy-mm-dd'
 | 
						|
my $verifyAccess = 0;                  # Verify system can be accessed
 | 
						|
my $verifyCaptureReqs = 0;             # Verify systems meets capture requirements
 | 
						|
my $verifyCloudInit = 0;               # Verify cloud-init installed
 | 
						|
my $verifyXcatconf4z = 0;              # Verify xcatconf4z
 | 
						|
my $versionOpt = 0;                    # Show version information flag
 | 
						|
my $warnErrCnt = 0;                    # Count of warnings and error messages for a verify set
 | 
						|
my $zhcpTarget = '';                   # ZHCP server that is related to this verification
 | 
						|
my $zvmHost = '';                      # z/VM host related to this verification
 | 
						|
my $zxcatParms = '';                   # Parmeters to pass to zxcatIVP
 | 
						|
 | 
						|
# Routines to drive based on the selected test.
 | 
						|
my %verifySets = (
 | 
						|
    '$decode ne \'\'' =>
 | 
						|
         [ '',                        # Do not show a function banner.
 | 
						|
           'encodeDecodeString()',
 | 
						|
         ],
 | 
						|
    '$disable and ! $remove and $schedule eq \'\'' =>
 | 
						|
         [ 'Disabling an IVP run',
 | 
						|
           'enableDisableRun( $id )',
 | 
						|
         ],
 | 
						|
    '$enable and ! $remove and $schedule eq \'\'' =>
 | 
						|
         [ 'Enabling an IVP run',
 | 
						|
           'enableDisableRun( $id )',
 | 
						|
         ],
 | 
						|
    '$encode ne \'\'' =>
 | 
						|
         [ 'Encoding a string',
 | 
						|
           'encodeDecodeString()',
 | 
						|
         ],
 | 
						|
    '$issueCmdOverIUCV ne \'\'' =>
 | 
						|
         [ 'Issue a command to a node using IUCV',
 | 
						|
           'cmdOnVM( \'onlyIUCV\' )',
 | 
						|
         ],
 | 
						|
    '$issueCmdToNode ne \'\'' =>
 | 
						|
         [ 'Issue a command to a node using IUCV or SSH',
 | 
						|
           'cmdOnVM( \'either\' )',
 | 
						|
         ],
 | 
						|
    '$remove' =>
 | 
						|
         [ 'Remove an automated periodic IVP',
 | 
						|
           'removeIVP( $id )',
 | 
						|
         ],
 | 
						|
    '$runBasicIVP' =>
 | 
						|
         [ 'Verifying the basic general setup of xCAT',
 | 
						|
           'addLogHeader( \'basicivp\' )',
 | 
						|
           'verifyBasicXCAT()',
 | 
						|
         ],
 | 
						|
    '$runCron' =>
 | 
						|
         [ 'Cron job for automated verification',
 | 
						|
           'driveCronList()',
 | 
						|
         ],
 | 
						|
    '$runFullIVP' =>
 | 
						|
         [ 'Verifying the full end-to-end setup of the xCAT and the compute node',
 | 
						|
           'addLogHeader( \'fullivp\' )',
 | 
						|
           'checkForDefault( \'openstackIP\', \'--openstackIP was not specified\', \'xCAT_master\' )',
 | 
						|
           'verifyAccess( $openstackIP ); $rc = 0',
 | 
						|
           'getDistro( $openstackIP )',
 | 
						|
           'runPrepScript()',
 | 
						|
           'runDriverScript()',
 | 
						|
         ],
 | 
						|
    '$schedule ne \'\'' =>
 | 
						|
         [ 'Scheduling an automated periodic IVP',
 | 
						|
           'scheduleIVP()',
 | 
						|
         ],
 | 
						|
    '$verifyAccess' =>
 | 
						|
         [ 'Verifying access to the system',
 | 
						|
           'verifyPower( $nodeName )',
 | 
						|
           'verifyAccess( $nodeName )'
 | 
						|
         ],
 | 
						|
    '$verifyCaptureReqs' =>
 | 
						|
         [ 'Verifying system meets the image requirements',
 | 
						|
           'verifyPower( $nodeName )',
 | 
						|
           'verifyAccess( $nodeName )',
 | 
						|
           'getDistro( $nodeName )',
 | 
						|
           'verifyDistro()',
 | 
						|
         ],
 | 
						|
    '$verifyCloudInit' =>
 | 
						|
         [ 'Verifying cloud-init is installed and configured',
 | 
						|
           'verifyPower( $nodeName )',
 | 
						|
           'verifyAccess( $nodeName )',
 | 
						|
           'getDistro( $nodeName )',
 | 
						|
           'verifyService($nodeName, "cloud-config,2,3,4,5 cloud-final,2,3,4,5 cloud-init,2,3,4,5 cloud-init-local,2,3,4,5")',
 | 
						|
           'showCILevel()',
 | 
						|
         ],
 | 
						|
    '$verifyXcatconf4z' =>
 | 
						|
         [ 'Verifying xcatconf4z is installed and configured',
 | 
						|
           'verifyPower( $nodeName )',
 | 
						|
           'verifyAccess( $nodeName )',
 | 
						|
           'getDistro( $nodeName )',
 | 
						|
           'verifyXcatconf4z( $nodeName )',
 | 
						|
         ],
 | 
						|
    '$test' =>
 | 
						|
         [ 'Script test functon.',
 | 
						|
           'verifyLogResponse()',
 | 
						|
         ],
 | 
						|
    );
 | 
						|
 | 
						|
 | 
						|
# set the usage message
 | 
						|
my $usage_string = "Usage:\n
 | 
						|
    $0 -n <node> <options>\n
 | 
						|
    or\n
 | 
						|
    $0 <options>\n
 | 
						|
    or\n
 | 
						|
    $0 -v\n
 | 
						|
    or\n
 | 
						|
    $0 [ -h | --help ]\n
 | 
						|
    The following options are supported:\n
 | 
						|
      -a | --access
 | 
						|
                          Verify access from xCAT MN to node.
 | 
						|
      --basicivp
 | 
						|
                          Run the basic xCAT IVP.
 | 
						|
      --capturereqs
 | 
						|
                          Verify that node meets system capture
 | 
						|
                          requirements for OpenStack.
 | 
						|
      --cmdoveriucv <cmd>
 | 
						|
                          Issue a command to a node using IUCV.
 | 
						|
                          Specify a period for <cmd> when combining this
 | 
						|
                          option with the --file option.
 | 
						|
      --cmdtonode <cmd>   Issue a command to a node using IUCV or SSH
 | 
						|
                          if IUCV is not available.
 | 
						|
                          Specify a period for <cmd> when combining this
 | 
						|
                          option with the --file option.
 | 
						|
      -c | --cloudinit
 | 
						|
                          Verify that node has cloud-init installed.
 | 
						|
      --comments
 | 
						|
                          Comments to specify on the IVP run.
 | 
						|
      --cron
 | 
						|
                          Driven as a cron job to run a set of periodic
 | 
						|
                          IVPs.
 | 
						|
      --decode <parm>
 | 
						|
                          Decode an encoded string.  This is used to
 | 
						|
                          view encoded values in the zvmivp table.
 | 
						|
      --disable           Indicates that the IVP being scheduled should
 | 
						|
                          be disabled from running.
 | 
						|
      --enable            Indicates that the IVP being scheduled should
 | 
						|
                          be enabled to run.  This is the default when
 | 
						|
                          neither --disable or --enable is specified.
 | 
						|
      --encode <parm>
 | 
						|
                          Encode a string.  This used for debug in order
 | 
						|
                          to create a string to compare to an encoded
 | 
						|
                          string from the zvmivp table. The <parm> must be
 | 
						|
                          an ASCII string.  This function does not support
 | 
						|
                          encoding a UTF-8 character string.
 | 
						|
      --file              File location containing additional input.
 | 
						|
                          When used with the --cmdoveriucv or --cmdtonode
 | 
						|
                          operands, this file contains the command to issue.
 | 
						|
      --fullivp
 | 
						|
                          Run the full end-to-end IVP.  This
 | 
						|
                          verification checks the compute node and builds
 | 
						|
                          a driver script which is then used to check
 | 
						|
                          the xCAT environment based on the values
 | 
						|
                          gathered in the driver script.
 | 
						|
      -h | --help
 | 
						|
                          Display help information.
 | 
						|
      -i | --id <idToRun>
 | 
						|
                          ID to associate with the IVP run.
 | 
						|
      --ignore <val>
 | 
						|
                          Blank or comma separated list of message ids or
 | 
						|
                          message severities to ignore.  Ignored messages are
 | 
						|
                          not counted as failures and do not produce messages.
 | 
						|
                          Instead the number of ignored messages and their
 | 
						|
                          message numbers are displayed at the end of
 | 
						|
                          processing.  Recognized message severities:
 | 
						|
                          'bypass', 'info', 'warning', 'error'.
 | 
						|
      --notify
 | 
						|
                          Notification of IVP failures should be sent
 | 
						|
                          to a z/VM userid.
 | 
						|
      -n | --node <node>
 | 
						|
                          Node name of system to verify.
 | 
						|
      --openstackip <ipAddr>
 | 
						|
                          IP address of the OpenStack compute node.
 | 
						|
      --openstackuser <user>
 | 
						|
                          User to use to access the compute node.
 | 
						|
                          The user defaults to 'root'.
 | 
						|
      --orchparms <parms>
 | 
						|
                          Parameters to be stored in the zvmivp table. These
 | 
						|
                          parameters are passed to this routine when a
 | 
						|
                          scheduled IVP is driven.
 | 
						|
      --prepparms <parms>
 | 
						|
                          Parameters to pass to the preparation script as
 | 
						|
                          part of a full IVP.
 | 
						|
      --remove
 | 
						|
                          Indicates that an IVP in the zvmivp table should be
 | 
						|
                          removed.  The id is specified with the --id
 | 
						|
                          operand.
 | 
						|
      --schedule <hours>
 | 
						|
                          List of hours (in 24 hour format) to periodically
 | 
						|
                          run the IVP.  Multiple hours are separated by blanks.
 | 
						|
                          For example, \'0 6 12 18 20\'.
 | 
						|
      --type < basicivp | fullivp >
 | 
						|
                          Type of IVP to be scheduled.
 | 
						|
      -v
 | 
						|
                          Display the version of this script.
 | 
						|
      -x | --xcatconf4z
 | 
						|
                          Verify that node has xcatconf4z installed.
 | 
						|
      --zxcatparms <parms>
 | 
						|
                          Parameters to pass to the zxcatIVP script.\n";
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   addLogHeader
 | 
						|
 | 
						|
    Description : Add a header to the log file.
 | 
						|
    Arguments   : None
 | 
						|
    Returns     : 0 - No error
 | 
						|
                  non-zero - Terminating error detected.
 | 
						|
    Example     : $rc = addLogHeader();
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub addLogHeader {
 | 
						|
    my ( $hType ) = @_;
 | 
						|
 | 
						|
    logResponse( 'DF', '*NONFORMATTED*', '*******************************************************************************' );
 | 
						|
 | 
						|
    # Generate the header based on the header type.
 | 
						|
    if ( $hType eq 'basicivp' ) {
 | 
						|
        logResponse( 'DF', 'GENERIC_RESPONSE_NOINDENT', "This log file was created for a basic xCAT IVP. It consists of output from ".
 | 
						|
                           "zxcatIVP that validates the xCAT management node (MN) and the ZHCP Agents that are used by ".
 | 
						|
                           "the xCAT MN node to manage the z/VM hosts." );
 | 
						|
    } elsif ( $hType eq 'fullivp' ) {
 | 
						|
        logResponse( 'DF', 'GENERIC_RESPONSE_NOINDENT', "This log file was created for a full xCAT IVP which validates the z/VM OpenStack ".
 | 
						|
                           "configuration files, the xCAT management node (MN) and the ZHCP Agents that are used by ".
 | 
						|
                           "the xCAT MN node to manage the z/VM host. The log file contains the following output: output ".
 | 
						|
                           "from the preparation script that validated the OpenStack properties, the contents of the ".
 | 
						|
                           "driver script created by the preparation script to drive the second part of the IVP, output ".
 | 
						|
                           "of the zxcatIVP run that is driven by the driver script to complete the full IVP." );
 | 
						|
    } else {
 | 
						|
        logResponse( 'DF', 'GENERIC_RESPONSE', "VerifyNode log file." );
 | 
						|
    }
 | 
						|
 | 
						|
    logResponse( 'DF', '*NONFORMATTED*', '*******************************************************************************' );
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   checkForDefault
 | 
						|
 | 
						|
    Description : Determine if a default is needed for
 | 
						|
                  the specified property and set it if
 | 
						|
                  it is needed.  Currently, this routine
 | 
						|
                  is only used for the master IP address.
 | 
						|
    Arguments   : Name of property
 | 
						|
                  String to use in a DFLT01 message.
 | 
						|
                  Default or function to perform.
 | 
						|
    Returns     : 0 - No error
 | 
						|
                  non-zero - Terminating error detected.
 | 
						|
    Example     : $rc = checkForDefault( 'openStackIP', '--ip was not specified', 'xCAT_master' );
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub checkForDefault {
 | 
						|
    my ( $prop, $reasonString, $default ) = @_;
 | 
						|
    my $additionalInfo = '';
 | 
						|
    my $rc = 0;
 | 
						|
    my $val;
 | 
						|
 | 
						|
    eval( "\$val = \$$prop" );
 | 
						|
    if ( $val eq '' ) {
 | 
						|
        if ( $default eq 'xCAT_master' ) {
 | 
						|
            $default = '';
 | 
						|
            if ( exists $mnInfo{'ip'} ) {
 | 
						|
                $default = $mnInfo{'ip'};
 | 
						|
                $additionalInfo = 'The value came from the IP address used as the xCAT MN\'s ' .
 | 
						|
                    'master IP address that was specified in the site table.';
 | 
						|
            } else {
 | 
						|
                # Use one of the local IPv4 IPs.  We don't support IPv6.
 | 
						|
                if ( keys %localIPs > 0 ) {
 | 
						|
                    # Can't find the MN IP so use the first local IPv4 IP.
 | 
						|
                    foreach my $ip ( keys %localIPs ) {
 | 
						|
                        if ( $ip =~ /:/ ) {
 | 
						|
                            next;
 | 
						|
                        } else {
 | 
						|
                            $default = $ip;
 | 
						|
                            $additionalInfo = 'The function could not determine the master IP address for ' .
 | 
						|
                                'the xCAT MN so the first local IPv4 address was used.';
 | 
						|
                            last;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    if ( $default eq '' ) {
 | 
						|
                        $default = '127.0.0.1';
 | 
						|
                        $additionalInfo = 'The function could not determine the IP address for the xCAT MN ' .
 | 
						|
                            'and could not find any IPv4 addresses on the system so \'127.0.0.1\' will be used ' .
 | 
						|
                            'in the hope that it will work.';
 | 
						|
                    }
 | 
						|
                } else {
 | 
						|
                    # Don't know the local IPs.
 | 
						|
                    # Default to the IPv4 loopback and let it fail.
 | 
						|
                    $default = '127.0.0.1';
 | 
						|
                    $additionalInfo = 'The function cound not determine the IP addresses on the ' .
 | 
						|
                        'xCAT MN system so \'127.0.0.1\' was used.';
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if ( $rc == 0 ) {
 | 
						|
            # Found a default, set it in the property.
 | 
						|
            eval( "\$$prop = \'$default\'" );
 | 
						|
            logResponse( 'DF', 'DFLT01', $reasonString, $default, $additionalInfo );
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return $rc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   cmdOnVM
 | 
						|
 | 
						|
    Description : Send a command to a node and show the result.
 | 
						|
    Arguments   : Target function, either 'onlyIUCV' or 'either'.
 | 
						|
    Returns     : Return code:
 | 
						|
                      0 - Normal Linux success
 | 
						|
                      255 - Unable to SSH to system
 | 
						|
                      non-zero - command error
 | 
						|
                  Output from the command or a error string on an SSH failure.
 | 
						|
    Example     : $rc = cmdOnVM( 'onlyIUCV' );
 | 
						|
                  $rc = cmdOnVM( 'either' );
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub cmdOnVM {
 | 
						|
    my ( $targetFunc ) = @_;
 | 
						|
    my $cmd = '';
 | 
						|
    my $hcp = '';
 | 
						|
    my @lines;
 | 
						|
    my $rc = 0;
 | 
						|
    my $out = '';
 | 
						|
    my $sudo;
 | 
						|
    my $user;
 | 
						|
    my $userid = '';
 | 
						|
 | 
						|
    # Get the command to issue.
 | 
						|
    if ( $targetFunc eq 'onlyIUCV' ) {
 | 
						|
        if ( $issueCmdOverIUCV ne '.' ) {
 | 
						|
            $cmd = $issueCmdOverIUCV;
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        if ( $issueCmdToNode ne '.' ) {
 | 
						|
            $cmd = $issueCmdToNode;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    # Use the data file if it was specified.
 | 
						|
    if ( $dataFile ne '' ) {
 | 
						|
        if ( -e $dataFile ) {
 | 
						|
            open my $handle, '<', $dataFile;
 | 
						|
            chomp( @lines = <$handle> );
 | 
						|
            close $handle;
 | 
						|
            if ( $lines[0] ne '' ) {
 | 
						|
                $cmd = $lines[0];
 | 
						|
            } else {
 | 
						|
                logResponse( 'DF', 'GENERIC_RESPONSE', "$dataFile does not have anything in the first line.");
 | 
						|
                goto FINISH_cmdUsingIUCV;
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            logResponse( 'DF', 'GENERIC_RESPONSE', "$dataFile does not exist.");
 | 
						|
            goto FINISH_cmdUsingIUCV;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    # Verify that we have a command to issue.
 | 
						|
    if ( $cmd eq '' ) {
 | 
						|
        logResponse( 'DF', 'GENERIC_RESPONSE', "A command to issue was not specified.");
 | 
						|
        goto FINISH_cmdUsingIUCV;
 | 
						|
    }
 | 
						|
 | 
						|
    ($user, $sudo) = xCAT::zvmUtils->getSudoer();
 | 
						|
 | 
						|
    # Get the required properties (hcp, userid, user) from the node
 | 
						|
    $out = `/opt/xcat/bin/lsdef $nodeName -i hcp,userid`;
 | 
						|
    $rc = $?;
 | 
						|
    if ( $rc eq 0 ) {
 | 
						|
        my $fndNode = 0;
 | 
						|
        @lines = split( '\n', $out );
 | 
						|
        my $host = '';
 | 
						|
        foreach my $line ( @lines ) {
 | 
						|
            $line =~ s/^\s+|\s+$//g;         # trim blanks from both ends of the string
 | 
						|
            if ( $line =~ /Object name:/ ) {
 | 
						|
                $fndNode = 1;
 | 
						|
                next;
 | 
						|
            } elsif ( $line =~ /hcp\=/ ) {
 | 
						|
                ($hcp) = $line =~ m/hcp\=(.*)/;
 | 
						|
                next;
 | 
						|
            } elsif ( $line =~ /userid\=/ ) {
 | 
						|
                ($userid) = $line =~ m/userid\=(.*)/;
 | 
						|
                next;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if ( $fndNode != 1 ) {
 | 
						|
            logResponse( 'DF', 'GENERIC_RESPONSE', "'$nodeName' is not an xCAT node." );
 | 
						|
            goto FINISH_cmdUsingIUCV;
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        $rc = logResponse( 'DFS', 'GNRL01', "$cmd", $rc, $out );
 | 
						|
        goto FINISH_cmdUsingIUCV;
 | 
						|
    }
 | 
						|
 | 
						|
    # Send the command through IUCV
 | 
						|
    logResponse( 'DF', '*NONFORMATTED*', "\n**************************\nData for the function call\n**************************" );
 | 
						|
    logResponse( 'DF', '*NONFORMATTED*',  "       Node: $nodeName" );
 | 
						|
    if ( $targetFunc eq 'onlyIUCV' ) {
 | 
						|
        logResponse( 'DF', '*NONFORMATTED*',  "z/VM userid: $userid" );
 | 
						|
        logResponse( 'DF', '*NONFORMATTED*',  "        HCP: $hcp" );
 | 
						|
        logResponse( 'DF', '*NONFORMATTED*',  "       User: $user" );
 | 
						|
        logResponse( 'DF', '*NONFORMATTED*',  "   Function: xCAT::zvmUtils->execcmdthroughIUCV" );
 | 
						|
    } else {
 | 
						|
        logResponse( 'DF', '*NONFORMATTED*',  "       User: $user" );
 | 
						|
        logResponse( 'DF', '*NONFORMATTED*',  "   Function: xCAT::zvmUtils->execcmdonVM" );
 | 
						|
    }
 | 
						|
    logResponse( 'DF', '*NONFORMATTED*', "        Cmd: $cmd" );
 | 
						|
 | 
						|
    logResponse( 'DF', '*NONFORMATTED*', "\n*********************\nInvoking the function\n*********************" );
 | 
						|
    if ( $targetFunc eq 'onlyIUCV' ) {
 | 
						|
        $out = xCAT::zvmUtils->execcmdthroughIUCV( $user, $hcp, $userid, $cmd );
 | 
						|
    } else {
 | 
						|
        $out = xCAT::zvmUtils->execcmdonVM( $user, $nodeName, $cmd );
 | 
						|
    }
 | 
						|
    logResponse( 'DF', '*NONFORMATTED*', "\n******\nResult\n******\n$out" );
 | 
						|
 | 
						|
FINISH_cmdUsingIUCV:
 | 
						|
    return $rc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   driveCronList
 | 
						|
 | 
						|
    Description : Run thru the list of IVPs and run any that
 | 
						|
                  are due to be run.
 | 
						|
    Arguments   : None.
 | 
						|
    Returns     : 0 - No error
 | 
						|
                  non-zero - Terminating error detected.
 | 
						|
    Example     : $rc = driveCronList();
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub driveCronList {
 | 
						|
    my $attemptedRuns = 0;
 | 
						|
    my $disabledRuns = 0;
 | 
						|
    my @ivps;
 | 
						|
    my $out = '';
 | 
						|
    my $rc = 0;
 | 
						|
    my $totalRunsInTable = 0;
 | 
						|
 | 
						|
    # Determine the timestamp and other time related information.
 | 
						|
    my ($sec,  $min,  $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
 | 
						|
    $year = $year + 1900;
 | 
						|
    $todayDate = sprintf( "%04d-%02d-%02d", $year, $mon + 1, $mday );
 | 
						|
    $startTime = sprintf( "%02d:%02d:%02d on %04d-%02d-%02d",
 | 
						|
                           $hour, $min, $sec, $year, $mon + 1, $mday );
 | 
						|
    my $currTime = sprintf( "%04d-%02d-%02d_%02d:%02d:%02d",
 | 
						|
                           $year, $mon + 1, $mday, $hour, $min, $sec);
 | 
						|
    my $newLastRun = "$year $yday $hour";
 | 
						|
 | 
						|
    logResponse( 'DFS', '*NONFORMATTED*', "CRON job run started at $startTime." );
 | 
						|
 | 
						|
    # Read the z/VM IVP table to get the list of known IVP runs.
 | 
						|
    $out = `/opt/xcat/sbin/tabdump zvmivp | grep -v "^#"`;
 | 
						|
    $rc = $?;
 | 
						|
    my @lines = split( '\n', $out );
 | 
						|
    $totalRunsInTable = scalar( @lines );
 | 
						|
    if ( $totalRunsInTable != 0 ) {
 | 
						|
        my $row = 0;
 | 
						|
        my $nowTotalHours = ( ( $year ) * 8784 ) + ( $yday   * 24 ) + $hour;
 | 
						|
        foreach my $line ( @lines ) {
 | 
						|
            $row++;
 | 
						|
            chomp( $line );
 | 
						|
            my @field = split( ',', $line );
 | 
						|
            for ( my $i=0; $i < scalar( @field ); $i++ ) {
 | 
						|
                $field[$i] =~ s/^\"|\"$//g;         # trim quotes from both ends of the string
 | 
						|
            }
 | 
						|
 | 
						|
            # Process the fields from the zvmIVP table.  Each row is related to a
 | 
						|
            # scheduled run.
 | 
						|
            # Field 0 - Unique IVP ID
 | 
						|
            #       1 - IP property for the OpenStack system
 | 
						|
            #       2 - Schedule, hours to run the IVP
 | 
						|
            #       3 - Last time IVP was run, ( year day hour )
 | 
						|
            #       4 - Type of run, e.g. basicivp, fullivp
 | 
						|
            #       5 - OpenStack user to access the config files
 | 
						|
            #       6 - Parameters to pass to the orchestrator, verifynode
 | 
						|
            #       7 - Parameters to pass to the preparator script, prep_zxcatIVP
 | 
						|
            #       8 - Parameters to pass to the main IVP script, zxcatIVP.pl
 | 
						|
            #       9 - Comments related to the IVP run
 | 
						|
            #      10 - Disabled, 1 or YES equals disabled
 | 
						|
            my %ivpRun;
 | 
						|
            if ( defined $field[0] and $field[0] ne '' ) {
 | 
						|
                $ivpRun{'id'} = $field[0];
 | 
						|
            } else {
 | 
						|
                logResponse( 'DS', 'GENERIC_RESPONSE', "Row $row in the ivp table missing a ".
 | 
						|
                                   "required property, \'id\'.  The row will be treated as disabled." );
 | 
						|
                $disabledRuns++;
 | 
						|
                next;
 | 
						|
            }
 | 
						|
 | 
						|
            if ( defined $field[10] and ($field[10] eq '1'  or uc( $field[10] ) eq 'YES') ) {
 | 
						|
                # IVP run is disabled
 | 
						|
                logResponse( 'DS', 'GENERIC_RESPONSE', "Row $row, ID($ivpRun{'id'}), in the ivp table is ".
 | 
						|
                                                       "disabled and will not be processed." );
 | 
						|
                $disabledRuns++;
 | 
						|
                next;
 | 
						|
            }
 | 
						|
 | 
						|
            if ( defined $field[1] and $field[1] ne '' ) {
 | 
						|
                $ivpRun{'ip'} = $field[1];
 | 
						|
            } else {
 | 
						|
                # Assume this is a local xCAT IVP run
 | 
						|
                $ivpRun{'ip'} = 'xcat';
 | 
						|
                logResponse( 'DS', 'GENERIC_RESPONSE', "Row $row, ID($ivpRun{'id'}), in the ivp table " .
 | 
						|
                                                       "has no value specified for the \'ip\' property. " .
 | 
						|
                                                       "The IVP run will be against the system which is " .
 | 
						|
                                                       "running the xCAT management node." );
 | 
						|
            }
 | 
						|
 | 
						|
            if ( defined $field[2] and $field[2] ne '' ) {
 | 
						|
                $ivpRun{'schedule'} = hexDecode( $field[2] );
 | 
						|
            } else {
 | 
						|
                # Default run time is 1 AM
 | 
						|
                $ivpRun{'schedule'} = '1';
 | 
						|
            }
 | 
						|
 | 
						|
            my $lRYear;
 | 
						|
            my $lRYDay;
 | 
						|
            my $lRHour;
 | 
						|
 | 
						|
            if ( defined $field[3] and $field[3] ne '' ) {
 | 
						|
                $ivpRun{'last_run'} = $field[3];
 | 
						|
                my @parts = split ( '\s', $ivpRun{'last_run'} );
 | 
						|
                if ( defined $parts[0] and $parts[0] ne '' ) {
 | 
						|
                    $lRYear = $parts[0];
 | 
						|
                } else {
 | 
						|
                    # Missing year, set default to immediately, 0.
 | 
						|
                    $lRYear = 0;
 | 
						|
                }
 | 
						|
                if ( defined $parts[1] and $parts[1] ne '' ) {
 | 
						|
                    $lRYDay = $parts[1];
 | 
						|
                } else {
 | 
						|
                    # Missing day number, set default to immediately, 0.
 | 
						|
                    $lRYDay = 0;
 | 
						|
                }
 | 
						|
                if ( defined $parts[2] and $parts[2] ne '' ) {
 | 
						|
                    $lRHour = $parts[2];
 | 
						|
                } else {
 | 
						|
                    # Missing hour, set default to immediately, -1.
 | 
						|
                    $lRHour = 0;
 | 
						|
                }
 | 
						|
            } else {
 | 
						|
                # Force a schedule run
 | 
						|
                $lRYear = 0;
 | 
						|
                $lRYDay = 0;
 | 
						|
                $lRHour = -1;
 | 
						|
            }
 | 
						|
            $ivpRun{'last_run'} = "$lRYear $lRYDay $lRHour";
 | 
						|
 | 
						|
            # Weed out any runs that are not due to be run.
 | 
						|
            # Calculate the difference (since 2000) between the last run hour and the current hour,
 | 
						|
            # ignoring leap years by saying every year is a leap year.
 | 
						|
            my $totalHourDiff = $nowTotalHours - (( ( $lRYear ) * 8784 ) + ( $lRYDay * 24 ) + $lRHour);
 | 
						|
 | 
						|
            if ( $totalHourDiff == 0 ) {
 | 
						|
                # Same hour of the same day of the same year for some reason so ignore this IVP row.
 | 
						|
                logResponse( 'DS', 'GENERIC_RESPONSE', "Row $row, ID($ivpRun{'id'}), in the ivp table ".
 | 
						|
                                                       "is being ignored because it was already run this hour." );
 | 
						|
                next;
 | 
						|
            } else {
 | 
						|
                # Determine the range of hours that are of interest within a 24 hour time period.  Anything
 | 
						|
                # that is more than 24 hours old is automatically overdue and should be run.
 | 
						|
                if ( $totalHourDiff < 24) {
 | 
						|
                    my $todayStartHour;
 | 
						|
                    my $yesterdayStartHour;
 | 
						|
                    if ( $yday > $lRYDay ) {
 | 
						|
                        # Last run yesterday
 | 
						|
                        $todayStartHour = 0;
 | 
						|
                        $yesterdayStartHour = $lRHour + 1;
 | 
						|
                    } else {
 | 
						|
                        # Last run today
 | 
						|
                        $todayStartHour = $hour - $totalHourDiff;
 | 
						|
                        $yesterdayStartHour = 24;
 | 
						|
                    }
 | 
						|
 | 
						|
                    # Less than a day so we need to worry about which scheduled hours were missed.
 | 
						|
                    my $overdue = 0;
 | 
						|
                    my @schedHours = split ( '\s', $ivpRun{'schedule'} );
 | 
						|
                    foreach my $sHour ( @schedHours ) {
 | 
						|
                        if ( $sHour == 0 and $sHour ne '0' ) {
 | 
						|
                            # not numeric, ignore
 | 
						|
                            logResponse( 'DS', 'GENERIC_RESPONSE', "Row $row, ID($ivpRun{'id'}), in the ivp table ".
 | 
						|
                                                                   "contains as schedule hour that is non-numeric: $sHour. ".
 | 
						|
                                                                   "The value will be ignored." );
 | 
						|
                            next;
 | 
						|
                        }
 | 
						|
                        if (( $sHour >= $yesterdayStartHour ) or
 | 
						|
                             ( $sHour > $todayStartHour and $sHour <= $hour ) ) {
 | 
						|
                            logResponse( 'DS', 'GENERIC_RESPONSE', "Row $row, ID($ivpRun{'id'}), in the ivp table ".
 | 
						|
                                                                   "is due to be run. Scheduled hour: $sHour, last run: $lRHour." );
 | 
						|
                            $overdue = 1;
 | 
						|
                            last;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    if ( $overdue == 0 ) {
 | 
						|
                        # did not find a scheduled hour that is due
 | 
						|
                        logResponse( 'DS', 'GENERIC_RESPONSE', "Row $row, ID($ivpRun{'id'}), in the ivp table is not ".
 | 
						|
                                                               "due to be run this hour." );
 | 
						|
                        next;
 | 
						|
                    }
 | 
						|
                } else {
 | 
						|
                   logResponse( 'DS', 'GENERIC_RESPONSE', "Row $row, ID($ivpRun{'id'}), in the ivp table ".
 | 
						|
                                                          "is due to be run. Last run over 24 hours ago." );
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            if ( defined $field[4] and $field[4] ne '' ) {
 | 
						|
                $ivpRun{'type_of_run'} = lc( $field[4] );
 | 
						|
            } else {
 | 
						|
                $ivpRun{'type_of_run'} = 'not specified';
 | 
						|
            }
 | 
						|
            if ( $ivpRun{'type_of_run'} ne 'basicivp' and $ivpRun{'type_of_run'} ne 'fullivp' ) {
 | 
						|
                my $badValue = $ivpRun{'type_of_run'};
 | 
						|
                if ( exists $mnInfo{'ip'} and ( $ivpRun{'ip'} eq $mnInfo{'ip'} )) {
 | 
						|
                    if (( $mnInfo{'role'} eq 'controller' ) or
 | 
						|
                          ( $mnInfo{'role'} eq 'compute' ) or
 | 
						|
                          ( $mnInfo{'role'} eq 'compute_mn' )) {
 | 
						|
                        $ivpRun{'type_of_run'} = 'fullivp';
 | 
						|
                    } else {
 | 
						|
                        $ivpRun{'type_of_run'} = 'basicivp';
 | 
						|
                    }
 | 
						|
                } else {
 | 
						|
                    $ivpRun{'type_of_run'} = 'basicivp';
 | 
						|
                }
 | 
						|
                logResponse( 'DS', 'GENERIC_RESPONSE', "Row $row, ID($ivpRun{'id'}), in the ivp table contains ".
 | 
						|
                                                       "an unknown run type value of \'$badValue\'. Instead ".
 | 
						|
                                                       "a run type of \'$ivpRun{'type_of_run'}\' will be performed." );
 | 
						|
            }
 | 
						|
 | 
						|
            if ( defined $field[5] and $field[5] ne '' ) {
 | 
						|
                $ivpRun{'access_user'} = hexDecode( $field[5] );
 | 
						|
            } else {
 | 
						|
                $ivpRun{'access_user'} = '';
 | 
						|
            }
 | 
						|
 | 
						|
            if ( defined $field[6] and $field[6] ne '' ) {
 | 
						|
                $ivpRun{'orch_parms'} = hexDecode( $field[6] );
 | 
						|
            } else {
 | 
						|
                $ivpRun{'orch_parms'} = '';
 | 
						|
            }
 | 
						|
 | 
						|
            if ( defined $field[7] and $field[7] ne '' ) {
 | 
						|
                $ivpRun{'prep_parms'} = hexDecode( $field[7] );
 | 
						|
            } else {
 | 
						|
                $ivpRun{'prep_parms'} = '';
 | 
						|
            }
 | 
						|
 | 
						|
            if ( defined $field[8] and $field[8] ne '' ) {
 | 
						|
                # Ensure that it is reencoded to pass along to do the actual work.
 | 
						|
                $ivpRun{'main_ivp_parms'} = hexEncode( $field[8] );
 | 
						|
            } else {
 | 
						|
                $ivpRun{'main_ivp_parms'} = '';
 | 
						|
            }
 | 
						|
 | 
						|
            if ( defined $field[9] and $field[9] ne '' ) {
 | 
						|
                $ivpRun{'comments'} = hexDecode( $field[9] );
 | 
						|
            } else {
 | 
						|
                $ivpRun{'comments'} = '';
 | 
						|
            }
 | 
						|
 | 
						|
            push @ivps, \%ivpRun;
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        # Table is empty.  Create a single run for the z/VM related to the
 | 
						|
        # xCAT MN.
 | 
						|
        logResponse( 'DS', 'GENERIC_RESPONSE', "The ivp table is empty. Default IVPs will be enabled." );
 | 
						|
        if ( exists $mnInfo{'node'} ) {
 | 
						|
            # First IVP is a full IVP for an OpenStack related xCAT at 1 am.
 | 
						|
            # Otherwise it is a basic IVP.
 | 
						|
            my %ivpRun;
 | 
						|
            $ivpRun{'id'} = 1;
 | 
						|
            if ( exists $mnInfo{'ip'} ) {
 | 
						|
                $ivpRun{'ip'} = $mnInfo{'ip'};
 | 
						|
            } else {
 | 
						|
                $ivpRun{'ip'} = 'xcat';
 | 
						|
            }
 | 
						|
            $ivpRun{'schedule'} = '1';
 | 
						|
            if ( $mnInfo{'role'} eq 'controller' or $mnInfo{'role'} eq 'compute' or $mnInfo{'role'} eq 'compute_mn' ) {
 | 
						|
                $ivpRun{'type_of_run'} = 'fullivp';
 | 
						|
                $ivpRun{'access_user'} = 'root';
 | 
						|
            } else {
 | 
						|
                $ivpRun{'type_of_run'} = 'basicivp';
 | 
						|
                $ivpRun{'access_user'} = '';
 | 
						|
            }
 | 
						|
            $ivpRun{'orch_parms'} = '';
 | 
						|
            $ivpRun{'prep_parms'} = '';
 | 
						|
            $ivpRun{'main_ivp_parms'} = '';
 | 
						|
            $ivpRun{'comments'} = 'Default Full IVP run';
 | 
						|
            $ivpRun{'defaultRun'} = 'run';
 | 
						|
            push @ivps, \%ivpRun;
 | 
						|
            $totalRunsInTable++;
 | 
						|
 | 
						|
            # Second IVP is a basic IVP run each hour except for 1 am when a full IVP is run.
 | 
						|
            my %ivpRun2;
 | 
						|
            $ivpRun2{'id'} = 2;
 | 
						|
            if ( exists $mnInfo{'ip'} ) {
 | 
						|
                $ivpRun2{'ip'} = $mnInfo{'ip'};
 | 
						|
            } else {
 | 
						|
                $ivpRun2{'ip'} = 'xcat';
 | 
						|
            }
 | 
						|
            $ivpRun2{'schedule'} = '0 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23';
 | 
						|
            $ivpRun2{'type_of_run'} = 'basicivp';
 | 
						|
            $ivpRun2{'access_user'} = '';
 | 
						|
            $ivpRun2{'orch_parms'} = '';
 | 
						|
            $ivpRun2{'prep_parms'} = '';
 | 
						|
            $ivpRun2{'main_ivp_parms'} = '';
 | 
						|
            $ivpRun2{'comments'} = 'Default Basic IVP run';
 | 
						|
            $ivpRun2{'defaultRun'} = 'runLater';
 | 
						|
            push @ivps, \%ivpRun2;
 | 
						|
            $totalRunsInTable++;
 | 
						|
        } else {
 | 
						|
            # xCAT MN does not exist as a node so we will only do a basic IVP the system.
 | 
						|
            # This is a very abnormal case.  We deal in the abnormal so let's run some type
 | 
						|
            # of IVP but not define it in the table.
 | 
						|
            logResponse( 'DFS', 'MN03' );
 | 
						|
            my %ivpRun;
 | 
						|
            $ivpRun{'id'} = 1;
 | 
						|
            if ( exists $mnInfo{'ip'} ) {
 | 
						|
                $ivpRun{'ip'} = $mnInfo{'ip'};
 | 
						|
            } else {
 | 
						|
                $ivpRun{'ip'} = 'xcat';
 | 
						|
            }
 | 
						|
            $ivpRun{'schedule'} = '0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23';
 | 
						|
            $ivpRun{'type_of_run'} = 'basicivp';
 | 
						|
            $ivpRun{'access_user'} = '';
 | 
						|
            $ivpRun{'orch_parms'} = '';
 | 
						|
            $ivpRun{'prep_parms'} = '';
 | 
						|
            $ivpRun{'main_ivp_parms'} = '';
 | 
						|
            $ivpRun{'comments'} = 'Default Basic IVP run';
 | 
						|
            $ivpRun{'defaultRun'} = 'noTableUpdate';
 | 
						|
            push @ivps, \%ivpRun;
 | 
						|
            $totalRunsInTable++;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    # Handle pruning, if necessary.
 | 
						|
    if ( $hour == 0 ) {
 | 
						|
        pruneLogs( $year, $mon + 1, $mday );
 | 
						|
    }
 | 
						|
 | 
						|
    # Go thru the list of IVPs and drive a run for each IVP
 | 
						|
    # that is due to be run.
 | 
						|
    foreach my $ivp ( @ivps ) {
 | 
						|
        my %ivpRun = %$ivp;
 | 
						|
 | 
						|
        # Build the verify node command.
 | 
						|
        my $cmd = '/opt/xcat/bin/verifynode -n xcat --notify';
 | 
						|
 | 
						|
        if ( $ivpRun{'type_of_run'} eq 'fullivp' ) {
 | 
						|
            $cmd = "$cmd --fullivp --openstackip \'$ivpRun{'ip'}\' --openstackuser \'" . hexEncode( $ivpRun{'access_user'} ) . "\'";
 | 
						|
        } else {
 | 
						|
            $cmd = "$cmd --basicivp";
 | 
						|
        }
 | 
						|
 | 
						|
        if ( $ivpRun{'orch_parms'} ne '' ) {
 | 
						|
            $cmd = "$cmd $ivpRun{'orch_parms'}";    # Don't hex encode orchestrator parms
 | 
						|
        }
 | 
						|
 | 
						|
        if ( $ivpRun{'prep_parms'} ne '' ) {
 | 
						|
            $cmd = "$cmd --prepparms \'" . hexEncode( $ivpRun{'prep_parms'} ) . "\'";
 | 
						|
        }
 | 
						|
 | 
						|
        if ( $ivpRun{'main_ivp_parms'} ne '' ) {
 | 
						|
            $cmd = "$cmd --zxcatparms \'" . hexEncode( $ivpRun{'main_ivp_parms'} ) . "\'";
 | 
						|
        }
 | 
						|
 | 
						|
        # Update the table to indicate the time we start the IVP run.
 | 
						|
        if ( ! exists $ivpRun{'defaultRun'} ) {
 | 
						|
            my $chtabCmd = "/opt/xcat/sbin/chtab id=\'$ivpRun{'id'}\' zvmivp.last_run=\'$newLastRun\'";
 | 
						|
            $out = `$chtabCmd`;
 | 
						|
            $rc = $?;
 | 
						|
            if ( $rc != 0 ) {
 | 
						|
                logResponse( 'DS', '*NONFORMATTED*', "\'$chtabCmd\' failed for IVP ID($ivpRun{'id'}), ip: $ivpRun{'ip'}, rc: $rc, out: $out\n" );
 | 
						|
            }
 | 
						|
        } elsif ( $ivpRun{'defaultRun'} ne 'noTableUpdate' ) {
 | 
						|
            logResponse( 'DS', '*NONFORMATTED*', "Adding IVP ID($ivpRun{'id'}) to the z/VM IVP table: $ivpRun{'comments'}\n" );
 | 
						|
            my $chtabCmd = "/opt/xcat/sbin/chtab id=\'$ivpRun{'id'}\' ".
 | 
						|
                                                "zvmivp.ip=\'$ivpRun{'ip'}\' ".
 | 
						|
                                                "zvmivp.schedule=\'$ivpRun{'schedule'}\' ".
 | 
						|
                                                "zvmivp.last_run=\'$newLastRun\' ".
 | 
						|
                                                "zvmivp.type_of_run=\'$ivpRun{'type_of_run'}\' ".
 | 
						|
                                                "zvmivp.access_user=\'" . hexEncode( $ivpRun{'access_user'} ) . "\' ".
 | 
						|
                                                "zvmivp.comments=\'" . hexEncode( $ivpRun{'comments'} ) . "\' ";
 | 
						|
            $out = `$chtabCmd`;
 | 
						|
            $rc = $?;
 | 
						|
            if ( $rc != 0 ) {
 | 
						|
                logResponse( 'DS', '*NONFORMATTED*', "\'$chtabCmd\' failed for ID($ivpRun{'id'}), ip: $ivpRun{'ip'}, rc: $rc, out: $out\n" );
 | 
						|
            }
 | 
						|
 | 
						|
            # Skip running this one if it is marked 'runLater'.
 | 
						|
            # A basic IVP is not needed if a full IVP is going to be run.
 | 
						|
            if ( $ivpRun{'defaultRun'}  eq 'runLater' ) {
 | 
						|
                logResponse( 'DS', '*NONFORMATTED*', "Ignoring IVP ID($ivpRun{'id'}) for this hour. It will be run next hour. IVP comment: $ivpRun{'comments'}\n" );
 | 
						|
                next;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        # Drive the run.
 | 
						|
        $attemptedRuns++;
 | 
						|
        my $logComments = '';
 | 
						|
        if ( $ivpRun{'comments'} eq '' ) {
 | 
						|
            $logComments = "Running IVP ID($ivpRun{'id'})";
 | 
						|
        } else {
 | 
						|
            $logComments = "Running IVP ID($ivpRun{'id'}) - $ivpRun{'comments'}";
 | 
						|
        }
 | 
						|
        logResponse( 'DS', '*NONFORMATTED*',  "$logComments" );
 | 
						|
        $out = `$cmd`;
 | 
						|
        $rc = $?;
 | 
						|
        if ( $rc != 0 ) {
 | 
						|
            logResponse( 'DS', '*NONFORMATTED*', "The IVP run for ID($ivpRun{'id'}) returned a ".
 | 
						|
                                                 "non-zero return code, rc: $rc\n" );
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    logResponse( 'DFS', '*NONFORMATTED*', "IVP CRON results: $totalRunsInTable runs considered, $disabledRuns runs disabled, $attemptedRuns runs attempted" );
 | 
						|
    $rc = 0;
 | 
						|
    return $rc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   enableDisableRun
 | 
						|
 | 
						|
    Description : Enable or Disable command line function.
 | 
						|
    Arguments   : ID of the IVP to be disabled
 | 
						|
                  Global input set by command operands are used
 | 
						|
                    by this routine:
 | 
						|
                    $disable  - Disable a run.
 | 
						|
                    $enable   - Enable a run.
 | 
						|
    Returns     : 0 - No error
 | 
						|
                  non-zero - Terminating error detected.
 | 
						|
    Example     : $rc = enableDisableRun();
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub enableDisableRun {
 | 
						|
    my ( $id ) = @_;
 | 
						|
    my %ids;
 | 
						|
    my $rc = 0;
 | 
						|
 | 
						|
    if ( $id eq '' ) {
 | 
						|
        logResponse( 'DF', 'OPER01', '--id' );
 | 
						|
        goto FINISH_enableDisableRun;
 | 
						|
    }
 | 
						|
 | 
						|
    # Get the list of IVP ids in the zvmivp table.
 | 
						|
    my $cmd = '/opt/xcat/sbin/tabdump zvmivp | grep -v "^#"';
 | 
						|
    my $out = `$cmd`;
 | 
						|
    $rc = $?;
 | 
						|
    if ( $rc ne 0 ) {
 | 
						|
        logResponse( 'DF', 'GNRL04', $cmd, $rc, $out );
 | 
						|
        goto FINISH_enableDisableRun;
 | 
						|
    }
 | 
						|
 | 
						|
    my @lines = split( '\n', $out );
 | 
						|
    foreach my $line ( @lines ) {
 | 
						|
        chomp( $line );
 | 
						|
        my ($ivpId, $junk) = split( ',', $line, 2 );
 | 
						|
        $ivpId =~ s/^\"|\"$//g;         # trim quotes from both ends of the string
 | 
						|
        $ivpId =~ s/^\s+|\s+$//g;       # trim spaces from both ends of the string
 | 
						|
        if ( $ivpId ne '' ) {
 | 
						|
            $ids{$ivpId} = 1;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    # Validate the specified id.
 | 
						|
    if ( ! exists $ids{$id} ) {
 | 
						|
        logResponse( 'DF', 'ID03', $id );
 | 
						|
    }
 | 
						|
 | 
						|
    my $action;
 | 
						|
    my $disableFlag = '';
 | 
						|
    if ( $disable ) {
 | 
						|
        $disableFlag = 'YES';
 | 
						|
        $action = 'disable';
 | 
						|
    } else {
 | 
						|
        $action = 'enable';
 | 
						|
    }
 | 
						|
 | 
						|
    # Update the table.
 | 
						|
    logResponse( 'DS', '*NONFORMATTED*', "Updating the z/VM IVP table (zvmivp) to $action $id" );
 | 
						|
    my $chtabCmd = "/opt/xcat/sbin/chtab id='$id' zvmivp.disable=\'$disableFlag\'";
 | 
						|
    $out = `$chtabCmd`;
 | 
						|
    $rc = $?;
 | 
						|
    if ( $rc != 0 ) {
 | 
						|
        logResponse( 'DS', '*NONFORMATTED*', "\'$chtabCmd\' failed for ID($id), rc: $rc, out: $out\n" );
 | 
						|
        $rc = 1;
 | 
						|
    }
 | 
						|
 | 
						|
FINISH_enableDisableRun:
 | 
						|
    return $rc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   encodeDecodeString
 | 
						|
 | 
						|
    Description : Encode and decode command line function.
 | 
						|
    Arguments   : Global input set by command operands are used
 | 
						|
                    by this routine:
 | 
						|
                    $decode - String to be decoded if not ''.
 | 
						|
                    $encode - String to be encoded if not ''.
 | 
						|
    Returns     : 0 - No error
 | 
						|
                  non-zero - Terminating error detected.
 | 
						|
    Example     : $rc = encodeDecodeString();
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub encodeDecodeString {
 | 
						|
    my $newVal = '';
 | 
						|
    if ( $decode ne '' ) {
 | 
						|
        binmode(STDOUT, ":utf8");
 | 
						|
        print( "Value is: '" . hexDecode( $decode ) . "'\n" );
 | 
						|
    }
 | 
						|
 | 
						|
    if ( $encode ne '' ) {
 | 
						|
        print( "Value is: '" . hexEncode( $encode ) . "'\n" );
 | 
						|
    }
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   finishLogFile
 | 
						|
 | 
						|
    Description : Complete the log file for the run and
 | 
						|
                  send it to the notify user if necessary.
 | 
						|
    Arguments   : None
 | 
						|
    Returns     : 0 - No error
 | 
						|
                  non-zero - Terminating error detected.
 | 
						|
    Example     : $rc = finishLogFile();
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub finishLogFile {
 | 
						|
    my $rc = 0;
 | 
						|
    $needToFinishLogFile = 0;
 | 
						|
 | 
						|
    # Add the summary information to the log file.
 | 
						|
    my ($sec,  $min,  $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
 | 
						|
    $endTime = sprintf("%02d:%02d:%02d on %04d-%02d-%02d",
 | 
						|
                           $hour, $min, $sec, $year + 1900, $mon + 1, $mday );
 | 
						|
 | 
						|
    logResponse( 'DF', '*NONFORMATTED*', '*******************************************************************************' );
 | 
						|
    logResponse( 'DF', 'GENERIC_RESPONSE', 'Results of the IVP run:\n' );
 | 
						|
    logResponse( 'DF', 'GENERIC_RESPONSE', "Run started at $startTime and ended at $endTime." );
 | 
						|
    foreach my $line ( @ivpSummary ) {
 | 
						|
        logResponse( 'DF', 'GENERIC_RESPONSE', $line );
 | 
						|
    }
 | 
						|
    if ( $ignoreCnt != 0 ){
 | 
						|
        logResponse( 'DFS', 'GENERIC_RESPONSE', "The orchestrator script (verifynode) ignored messages $ignoreCnt times." );
 | 
						|
        my @ignoreArray = sort keys %ignored;
 | 
						|
        my $ignoreList = join ( ', ', @ignoreArray );
 | 
						|
        logResponse( 'DFS', 'GENERIC_RESPONSE', "Message Ids of ignored messages by verifynode: $ignoreList" );
 | 
						|
    }
 | 
						|
    logResponse( 'DF', '*NONFORMATTED*', '*******************************************************************************' );
 | 
						|
 | 
						|
    # Notify the z/VM userid, if necessary.
 | 
						|
    if ( $notify and $notifyOnErrorOrWarning ) {
 | 
						|
        notifyUser();
 | 
						|
    }
 | 
						|
 | 
						|
FINISH_finishLogFile:
 | 
						|
    return $rc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   getDistro
 | 
						|
 | 
						|
    Description : Create the dummy image file.
 | 
						|
    Arguments   : Node name or IP address
 | 
						|
    Returns     : 0 - No error
 | 
						|
                  non-zero - Terminating error detected.
 | 
						|
    Example     : $rc = getDistro();
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub getDistro {
 | 
						|
    my ( $nodeOrIP ) = @_;
 | 
						|
    my $rc = 0;
 | 
						|
 | 
						|
    $tgtOS = xCAT::zvmUtils->getOsVersion( $::SUDOER, $nodeOrIP );
 | 
						|
 | 
						|
FINISH_getDistro:
 | 
						|
    return $rc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   getLocalIPs
 | 
						|
 | 
						|
    Description : Get the IP addresses from ifconfig.
 | 
						|
    Arguments   : Node name or IP address
 | 
						|
    Returns     : return code (Currently always 0)
 | 
						|
                    0 - No error
 | 
						|
                    non-zero - Terminating error detected.
 | 
						|
                  Hash of local IP addresses
 | 
						|
    Example     : $rc = getLocalIPs();
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub getLocalIPs {
 | 
						|
    my $ip;
 | 
						|
    my $junk;
 | 
						|
    my $rc = 0;
 | 
						|
 | 
						|
    my $out = `/sbin/ip addr | grep -e '^\\s*inet' -e '^\\s*inet6'`;
 | 
						|
    my @lines = split( '\n', $out );
 | 
						|
    foreach my $line ( @lines ) {
 | 
						|
        my @parts = split( ' ', $line );
 | 
						|
        ($ip) = split( '/', $parts[1], 2 );
 | 
						|
        $localIPs{$ip} = 1;
 | 
						|
    }
 | 
						|
 | 
						|
FINISH_getLocalIPs:
 | 
						|
    return $rc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   getMNInfo
 | 
						|
 | 
						|
    Description : Get information related to the xCAT MN
 | 
						|
                  and the z/VM system where it is running.
 | 
						|
    Arguments   : None
 | 
						|
    Returns     : 0 - No error
 | 
						|
                  non-zero - Terminating error detected.
 | 
						|
    Example     : $rc = getMNInfo();
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub getMNInfo {
 | 
						|
    my $cmd;
 | 
						|
    my $hostNode;
 | 
						|
    my @lines;
 | 
						|
    my $masterIP = '';
 | 
						|
    my $out = '';
 | 
						|
    my @parts;
 | 
						|
    my $rc = 0;
 | 
						|
    my $xcatMN;
 | 
						|
 | 
						|
    # Get the list of Local IP addresses
 | 
						|
    getLocalIPs();
 | 
						|
 | 
						|
    # Wait up to 10 minutes for xcatd to come up.
 | 
						|
    my $sleepTime = 60;
 | 
						|
    my $maxWaits = 10;
 | 
						|
    for ( my $i=1; $i<=$maxWaits; $i++ ) {
 | 
						|
        # lsdef uses the xCAT daemon.  We use that to see if it is started.
 | 
						|
        `/opt/xcat/bin/lsdef`;
 | 
						|
        if ( $? == 0 ) {
 | 
						|
            last;
 | 
						|
        } else {
 | 
						|
            logResponse( 'DFS', 'WAIT01', $sleepTime, $i, $maxWaits );
 | 
						|
            sleep( $sleepTime );
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    # Get information related to all of the host nodes
 | 
						|
    $cmd = '/opt/xcat/bin/lsdef -w mgt=zvm -w hosttype=zvm -i hcp';
 | 
						|
    $out = `$cmd`;
 | 
						|
    $rc = $?;
 | 
						|
    if ( $rc == 0 ) {
 | 
						|
        @lines = split( '\n', $out );
 | 
						|
        my $host = '';
 | 
						|
        foreach my $line ( @lines ) {
 | 
						|
            $line =~ s/^\s+|\s+$//g;         # trim blanks from both ends of the string
 | 
						|
            if ( $line =~ /Object name: / ) {
 | 
						|
                ($host) = $line =~ m/Object name: (.*)/;
 | 
						|
                next;
 | 
						|
            } elsif ( $line =~ /hcp\=/ ) {
 | 
						|
                ($hosts{$host}{'hcp'}) = $line  =~ m/hcp\=(.*)/;
 | 
						|
                next;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        $rc = logResponse( 'DFS', 'GNRL01', "$cmd", $rc, $out );
 | 
						|
        $notify = 1;
 | 
						|
    }
 | 
						|
 | 
						|
    # Get key info related to the xCAT MN and the notify targets from the site table.
 | 
						|
    $mnInfo{'PruneIVP'} = 7;
 | 
						|
    $cmd = "/opt/xcat/sbin/tabdump site";
 | 
						|
    $out = `$cmd`;
 | 
						|
    $rc = $?;
 | 
						|
    if ( $rc == 0 ) {
 | 
						|
        @lines = split( '\n', $out );
 | 
						|
        @lines = grep( /^\"master\"|^\"zvmnotify\"|^\"zvmpruneivp\"/, @lines );
 | 
						|
        foreach my $line ( @lines ) {
 | 
						|
            $line =~ s/^\s+|\s+$//g;         # trim blanks from both ends of the string
 | 
						|
            @parts = split( ',', $line );
 | 
						|
            $parts[1] =~ s/\"//g;
 | 
						|
            if ( $parts[0] =~ /^\"master\"/ ) {
 | 
						|
                $masterIP = $parts[1];
 | 
						|
            } elsif ( $parts[0] =~ /^\"zvmnotify\"/ ) {
 | 
						|
                my @notifyInfo = split( ';', $parts[1] );
 | 
						|
                my $notifyHost = '';
 | 
						|
                my $notifyUser = '';
 | 
						|
                foreach my $hostUser ( @notifyInfo ) {
 | 
						|
                    ($notifyHost) = $hostUser =~ m/(.*)\(/;
 | 
						|
                    ($notifyUser) = $hostUser =~ m/\((.*)\)/;
 | 
						|
                    if ( defined $notifyHost and $notifyHost ne '' and defined $notifyUser and $notifyUser ne '' ) {
 | 
						|
                        $hosts{$notifyHost}{'notifyUser'} = uc( $notifyUser );
 | 
						|
                    } else {
 | 
						|
                        $rc = logResponse( 'DFS', 'SITE01', 'zvmnotify', $parts[1], $hostUser );
 | 
						|
                        $notify = 1;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            } elsif ( $parts[0] =~ /^\"zvmpruneivp\"/ ) {
 | 
						|
                $mnInfo{'PruneIVP'} = $parts[1];
 | 
						|
            }
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        # Unable to read the site table
 | 
						|
        $rc = logResponse( 'DFS', 'GNRL01', "$cmd", $rc, $out );
 | 
						|
        $notify = 1;
 | 
						|
    }
 | 
						|
 | 
						|
    # Find a node that has the same address as the master IP and then find
 | 
						|
    # the host node that relates to that node.
 | 
						|
    if ( $masterIP eq '' ) {
 | 
						|
        # Unable to get the master value
 | 
						|
        $rc = logResponse( 'DFS', 'SITE02', 'master' );
 | 
						|
    } else {
 | 
						|
        $cmd = "/opt/xcat/bin/lsdef -w ip=$masterIP -i hcp";
 | 
						|
        $out = `$cmd`;
 | 
						|
        $rc = $?;
 | 
						|
        if ( $rc == 0 ) {
 | 
						|
            @lines = split( '\n', $out );
 | 
						|
            foreach my $line ( @lines ) {
 | 
						|
                $line =~ s/^\s+|\s+$//g;         # trim blanks from both ends of the string
 | 
						|
                if ( $line =~ /Object name: / ) {
 | 
						|
                    ($xcatMN) = $line =~ m/Object name: (.*)/;
 | 
						|
                    $mnInfo{'node'} = $xcatMN;
 | 
						|
                    $mnInfo{'ip'} = $masterIP;
 | 
						|
                    next;
 | 
						|
                } elsif ( $line =~ /hcp\=/ ) {
 | 
						|
                    ($mnInfo{'hcp'}) = $line  =~ m/hcp\=(.*)/;
 | 
						|
                    next;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            $rc = logResponse( 'DFS', 'MN01', $masterIP, $cmd, $rc, $out );
 | 
						|
        }
 | 
						|
 | 
						|
        # Find the host node which uses the hcp.
 | 
						|
        foreach $hostNode ( keys %hosts ) {
 | 
						|
            if ( exists $hosts{$hostNode}{'hcp'} and $hosts{$hostNode}{'hcp'} eq $mnInfo{'hcp'} ) {
 | 
						|
                if ( exists $hosts{$hostNode}{'notify'} ) {
 | 
						|
                    $hosts{$hostNode}{'notify'} = $hosts{$hostNode}{'notify'} . 'm';
 | 
						|
                } else {
 | 
						|
                    $hosts{$hostNode}{'notify'} = 'm';
 | 
						|
                }
 | 
						|
                $mnInfo{'host'} = $hostNode;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    # The following is useful in a z/VM CMA system only.
 | 
						|
    # As a safety measure, in case the site table is lost or does not have zvmnotify property,
 | 
						|
    # read the OPNCLOUD application system role file to find the value of the 'notify' property
 | 
						|
    # and remember it with the xCAT MN information.
 | 
						|
    # Also, determine the system role.
 | 
						|
    if ( -e $locApplSystemRole ) {
 | 
						|
        $out = `cat /var/lib/sspmod/appliance_system_role | grep -e '^notify\=' -e '^role\='`;
 | 
						|
        @lines = split( '\n', $out );
 | 
						|
        foreach my $line ( @lines ) {
 | 
						|
            $line =~ s/^\s+|\s+$//g;         # trim blanks from both ends of the string
 | 
						|
            my ($key, $value) = split( '=', $line, 2 );
 | 
						|
            #($mnInfo{'notifyUser'}) = $line  =~ m/^notify\=(.*)/;
 | 
						|
            if ( $key eq 'role' ) {
 | 
						|
                $mnInfo{'role'} = lc( $value );
 | 
						|
            }
 | 
						|
            if ( $key eq 'notify' ) {
 | 
						|
                $mnInfo{'notifyUser'} = uc( $value );
 | 
						|
            }
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        # Not CMA.  Indicate role is not set.
 | 
						|
        $mnInfo{'role'} = '';
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   getOpenStackLevel
 | 
						|
 | 
						|
    Description : Get the OpenStack version level as a
 | 
						|
                  name.
 | 
						|
    Arguments   : IP address of OpenStack compute node.
 | 
						|
    Returns     : string - OpenStack version name
 | 
						|
                    (e.g. NEWTON), or
 | 
						|
                  null string - error
 | 
						|
    Example     : $level = getOpenStackLevel();
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub getOpenStackLevel {
 | 
						|
    my ( $nodeOrIP, $openstackUser ) = @_;
 | 
						|
    my $cmd;
 | 
						|
    my $level = '';
 | 
						|
    my $numWords = 0;
 | 
						|
    my $out = '';
 | 
						|
    my @parts;
 | 
						|
    my $rc;
 | 
						|
    my %openStackVersion;
 | 
						|
 | 
						|
    # Get the list of known versions
 | 
						|
    $cmd = 'cat /opt/xcat/openstack.versions';
 | 
						|
    $out = `$cmd`;
 | 
						|
    $rc = $?;
 | 
						|
    if ( $rc != 0 ) {
 | 
						|
        logResponse( 'DFS', 'GNRL01', $cmd, $rc, $out );
 | 
						|
        $level = '';
 | 
						|
        goto FINISH_getOpenStackLevel;
 | 
						|
    }
 | 
						|
 | 
						|
    my @versionLines = split ( /\n/, $out );
 | 
						|
    foreach my $versionLine ( @versionLines ) {
 | 
						|
        if ( $versionLine =~ /^#/ ) { next; }
 | 
						|
        @parts = split( ' ', $versionLine );
 | 
						|
        $openStackVersion{$parts[0]} = $parts[1];
 | 
						|
    }
 | 
						|
 | 
						|
    # Get the version information from the OpenStack node
 | 
						|
    $cmd = "nova-manage --version 2>&1";
 | 
						|
    ($rc, $out) = sshToNode( $openstackIP, $openstackUser, $cmd );
 | 
						|
    if ( $rc != 0 ) {
 | 
						|
        # SSH failed, message already sent.
 | 
						|
        goto FINISH_getOpenStackLevel;
 | 
						|
    }
 | 
						|
    $out =~ s/^\s+|\s+$//g;         # trim blanks from both ends of the string
 | 
						|
    ++$numWords while $out =~ /\S+/g;
 | 
						|
    if ( $numWords != 1 ) {
 | 
						|
        logResponse( 'DFS', 'GOSL01', $cmd, $openstackIP, $rc, $out );
 | 
						|
        goto FINISH_getOpenStackLevel;
 | 
						|
    }
 | 
						|
 | 
						|
    @parts = split( '\.', $out );
 | 
						|
    if ( !exists $parts[0] or !exists $parts[1] ) {
 | 
						|
        logResponse( 'DFS', 'GOSL01', $cmd, $openstackIP, $rc, $out );
 | 
						|
        goto FINISH_getOpenStackLevel;
 | 
						|
    } elsif ( exists $openStackVersion{"$parts[0]."} ) {
 | 
						|
        $level = $openStackVersion{"$parts[0]."}
 | 
						|
    } elsif ( exists $openStackVersion{"$parts[0].$parts[1]."} ) {
 | 
						|
        $level = $openStackVersion{"$parts[0].$parts[1]."}
 | 
						|
    } else {
 | 
						|
        logResponse( 'DFS', 'GOSL02', $cmd, $openstackIP, $rc, $out );
 | 
						|
        goto FINISH_getOpenStackLevel;
 | 
						|
    }
 | 
						|
 | 
						|
FINISH_getOpenStackLevel:
 | 
						|
    return $level;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   hexDecode
 | 
						|
 | 
						|
    Description : Convert a string of printable hex
 | 
						|
                  characters (4 hex characters per actual
 | 
						|
                  character) into the actual string that
 | 
						|
                  it represents.  The string should
 | 
						|
                  begin with 'HexEncoded:' which indicates
 | 
						|
                  that it is encoded.  The routine tolerates
 | 
						|
                  getting called with a string that is not
 | 
						|
                  not encoded and will return the string that
 | 
						|
                  was passed to it instead of trying to decode
 | 
						|
                  it.
 | 
						|
    Arguments   : printable hex value
 | 
						|
    Returns     : Perl string
 | 
						|
    Example     : $rc = hexDecode();
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub hexDecode {
 | 
						|
    my ( $hexVal ) = @_;
 | 
						|
    my $result = '';
 | 
						|
 | 
						|
    if ( $hexVal =~ /^HexEncoded:/ ) {
 | 
						|
        ($hexVal) = $hexVal =~ m/HexEncoded:(.*)/;
 | 
						|
        my @hexes = unpack( "(a4)*", $hexVal);
 | 
						|
        for ( my $i = 0; $i < scalar(@hexes); $i++ ) {
 | 
						|
            $result .= chr( hex( $hexes[$i] ) );
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        $result = $hexVal;
 | 
						|
    }
 | 
						|
 | 
						|
    return $result;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   hexEncode
 | 
						|
 | 
						|
    Description : Convert a string into a string of
 | 
						|
                  printable hex characters in which each
 | 
						|
                  character in the original string is
 | 
						|
                  represented by the 2 byte (4 char) hex
 | 
						|
                  code value.  The string is preceded by
 | 
						|
                  'HexEncoded:' to indicate that it has
 | 
						|
                  been encoded.  The routine will tolerate
 | 
						|
                  getting called with a string that has
 | 
						|
                  already been encoded and not reencode it.
 | 
						|
    Arguments   : ASCII or Unicode string
 | 
						|
    Returns     : Hex string
 | 
						|
    Example     : $rc = hexEncode();
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub hexEncode {
 | 
						|
    my ( $str ) = @_;
 | 
						|
    my $hex;
 | 
						|
    my $result = $str;   # All work done within the result variable.
 | 
						|
 | 
						|
    if ( $result ne '' ) {
 | 
						|
        # Encode the string if is not already encoded.  Otherwise, leave it alone.
 | 
						|
        if ( $result !~ /^HexEncoded:/ ) {
 | 
						|
            $result =~ s/(.)/sprintf("%04x",ord($1))/eg;
 | 
						|
            $result = "HexEncoded:$result";
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return $result;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   logResponse
 | 
						|
 | 
						|
    Description : Build and log the response.
 | 
						|
    Arguments   : Target destination for the response.  This is
 | 
						|
                    string which can contain a charater for each
 | 
						|
                    possible destination, e.g 'DSF'. The values are:
 | 
						|
                      D - send to STDOUT
 | 
						|
                      S - send to syslog
 | 
						|
                      F - send to the log file
 | 
						|
                    The default is 'DF' so that we send the output
 | 
						|
                    to STDOUT and put it in the log file.
 | 
						|
                  message ID or special flag:
 | 
						|
                    *NONFORMATTED* indicates that the message build should not
 | 
						|
                      be invoked but instead the message substitutions are
 | 
						|
                      lines for the message to be produced.
 | 
						|
                    *RESET* indicates that the message counter should be reset.
 | 
						|
                  Array of message substitutions
 | 
						|
    Returns     : 0 - No error, general response or info message detected.
 | 
						|
                  1 - Non-terminating message detected.
 | 
						|
                  2 - Terminating message detected.
 | 
						|
    Example     : $rc = logResponse( 'D', 'VX01' );
 | 
						|
                  $rc = logResponse( '', 'VX03', $nodeName, $sub2);
 | 
						|
                  $rc = logResponse( 'DFS', 'VX03', $nodeName, 'sub2a');
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub logResponse {
 | 
						|
    my ( $dest, $msgId, @msgSubs ) = @_;
 | 
						|
    my $rc = 0;
 | 
						|
    my $extraInfo = '';
 | 
						|
    my $msg = '';
 | 
						|
    my @msgLines;
 | 
						|
    my $sev;
 | 
						|
    my $line;
 | 
						|
 | 
						|
    if ( $msgId eq '*RESET*' ) {
 | 
						|
        $warnErrCnt = 0;
 | 
						|
        goto FINISH_logResponse;
 | 
						|
    } elsif ( $msgId eq '*NONFORMATTED*' ) {
 | 
						|
        $rc = 0;
 | 
						|
        if ( @msgSubs ) {
 | 
						|
            foreach my $line ( @msgSubs ) {
 | 
						|
                $msg = "$msg$line\n";
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            $msg = '\n';
 | 
						|
        }
 | 
						|
        $sev = 0;
 | 
						|
    } else {
 | 
						|
        ( $rc, $sev, $msg, $extraInfo ) = xCAT::zvmMsgs->buildMsg('VERIFYNODE', $msgId, \@msgSubs);
 | 
						|
        if ( defined $msgsToIgnore{$msgId} ) {
 | 
						|
            # Ignore this message id
 | 
						|
            $ignored{$msgId} = 1;
 | 
						|
            $ignoreCnt += 1;
 | 
						|
            print( "Message $msgId is being ignored but would have occurred here.\n" );
 | 
						|
            goto FINISH_logResponse;
 | 
						|
        } elsif ( defined $msgsToIgnore{$sev} ) {
 | 
						|
            # Ignoring all messages of this severity.
 | 
						|
            $ignored{$msgId} = 1;
 | 
						|
            $ignoreCnt += 1;
 | 
						|
            print( "Message $msgId is being ignored but would have occurred here.\n" );
 | 
						|
            goto FINISH_logResponse;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ( $sev >= 4 ) {
 | 
						|
        $warnErrCnt += 1;
 | 
						|
    }
 | 
						|
 | 
						|
    # Send the message to the requested destination.
 | 
						|
    if ( $dest =~ 'D' ) {
 | 
						|
        print "$msg";                        # Send message to STDOUT
 | 
						|
    }
 | 
						|
    if ( $dest =~ 'F' and defined $logFileHandle ) {
 | 
						|
        print $logFileHandle $msg;
 | 
						|
    }
 | 
						|
    if ( $dest =~ 'S' ) {
 | 
						|
        my $logMsg = $msg;
 | 
						|
        $logMsg =~ s/\t//g;
 | 
						|
        $logMsg =~ s/\n/ /g;
 | 
						|
        syslog( 'err', $logMsg );
 | 
						|
    }
 | 
						|
 | 
						|
    # Send the extra info to the requested destination (never send it to syslog).
 | 
						|
    if ( $extraInfo ne '' ) {
 | 
						|
        if ( $dest =~ 'D' ) {
 | 
						|
            print "$extraInfo";
 | 
						|
        }
 | 
						|
        if ( $dest =~ 'F' and defined $logFileHandle ) {
 | 
						|
            print $logFileHandle $msg;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
FINISH_logResponse:
 | 
						|
    return $rc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   notifyUser
 | 
						|
 | 
						|
    Description : Notify a z/VM user.  Send a message
 | 
						|
                  and the log as a SPOOL file.
 | 
						|
    Arguments   : Node name or IP address
 | 
						|
    Returns     : 0 - Always ok.
 | 
						|
    Example     : $rc = notifyUser();
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub notifyUser {
 | 
						|
    my $cmd;
 | 
						|
    my $host;
 | 
						|
    my @hostOrder;
 | 
						|
    my $msg = '';
 | 
						|
    my $out = '';
 | 
						|
    my $rc = 0;
 | 
						|
    my $tempFile;
 | 
						|
    my $th;
 | 
						|
 | 
						|
    # Determine who we should notify based on the host related to the verification.
 | 
						|
    # The driver script would have set the host related to an full IVP (if we can trust it).
 | 
						|
    # If we cannot get to the host related to the run then we fall back to sending
 | 
						|
    # the notification to the user on the host in which the xCAT MN is running.
 | 
						|
    # If that fails then "tough luck, Chuck".
 | 
						|
    my $mnAdded = 0;
 | 
						|
    foreach $host ( keys %hosts ) {
 | 
						|
        if ( exists $hosts{$host}{'notify'} and exists $hosts{$host}{'hcp'} and exists $hosts{$host}{'notifyUser'} ) {
 | 
						|
            if ( $hosts{$host}{'notify'} =~ /d/ ) {
 | 
						|
                # Driver script specified hosts go on the top of the stack.
 | 
						|
                push @hostOrder, $host;
 | 
						|
                if ( $hosts{$host}{'notify'} =~ /m/ ) {
 | 
						|
                    # The host related to the MN is already in the list
 | 
						|
                    $mnAdded = 1;
 | 
						|
                }
 | 
						|
            } elsif ( $hosts{$host}{'notify'} =~ /m/ ) {
 | 
						|
                # Management node systems go on the bottom as a fall back plan.
 | 
						|
                unshift @hostOrder, $host;
 | 
						|
                $mnAdded = 1;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if ( $mnAdded == 0 and exists $mnInfo{'hcp'} and exists $mnInfo{'notifyUser'} ) {
 | 
						|
        # Did not find a host related to this management node but we have the
 | 
						|
        # necessary information to send the notification so add a dummy host
 | 
						|
        # to the hosts hash and add the dummy host to the end of the hostOrder
 | 
						|
        # stack to be used when all other notification attemps fail.
 | 
						|
        $host = '*DEFAULT_MN_HOST*';
 | 
						|
        $hosts{$host}{'notify'} = 'm';
 | 
						|
        $hosts{$host}{'notifyUser'} = $mnInfo{'notifyUser'};
 | 
						|
        $hosts{$host}{'hcp'} = $mnInfo{'hcp'};
 | 
						|
        unshift @hostOrder, $host;
 | 
						|
    }
 | 
						|
 | 
						|
    # Prepare the message.
 | 
						|
    $msg = "The xCAT IVP detected some possible issues. A log file is being sent to your reader.";
 | 
						|
 | 
						|
    # Prepare the log file by removing tabs and splitting the log file at 80 character lines.
 | 
						|
    $tempFile = mktemp( "$logDir/$logFile.XXXXXX" );
 | 
						|
    `expand $logDir/$logFile | fold -w 80 1>$tempFile`;
 | 
						|
 | 
						|
    # Send the message and log file to the first entity in the host order list that lets us
 | 
						|
    # successfully do so.
 | 
						|
    my $done = 0;
 | 
						|
    my $failed = 0;
 | 
						|
    foreach $host ( @hostOrder ) {
 | 
						|
        # Check if zHCP's punch is online and online it if it is not.
 | 
						|
        ($rc, $out) = sshToNode( $hosts{$host}{'hcp'}, '', 'cat /sys/bus/ccw/drivers/vmur/0.0.000d/online' );
 | 
						|
        chomp( $out );
 | 
						|
        if ($rc != 0 or $out != 1) {
 | 
						|
            $cmd = '/sbin/cio_ignore -r 000d;/sbin/chccwdev -e 000d';
 | 
						|
            ($rc, $out) = sshToNode( $hosts{$host}{'hcp'}, '', $cmd );
 | 
						|
            chomp( $out );
 | 
						|
            if ( $rc != 0 or !( $out =~ m/Done$/i ) ) {
 | 
						|
                $rc = logResponse( 'DFS', 'GNRL03', $hosts{$host}{'hcp'},  $cmd, $rc, $out );
 | 
						|
                next;
 | 
						|
            }
 | 
						|
            ($rc, $out) = sshToNode( $hosts{$host}{'hcp'}, '', 'which udevadm &> /dev/null && udevadm settle || udevsettle' );
 | 
						|
            # Don't worry about the udevadm settle.  If it remains a problem then we will see it on the next command to ZHCP.
 | 
						|
        }
 | 
						|
 | 
						|
        # Send log file.  It will exist temporarily on the ZHCP agent in the /tmp directory
 | 
						|
        # under its original log file name.
 | 
						|
        $rc = xCAT::zvmUtils->sendFile( 'root', $hosts{$host}{'hcp'}, "$tempFile", "/tmp/$logFile" );
 | 
						|
        if ( $rc != 0 ) {
 | 
						|
            # An error is not a problem because the zhcp node could be logged off.
 | 
						|
            next;
 | 
						|
        }
 | 
						|
 | 
						|
        # Punch the file from the ZHCP agent to the target user.
 | 
						|
        $out = xCAT::zvmCPUtils->punch2Reader( 'root', $hosts{$host}{'hcp'}, $hosts{$host}{'notifyUser'}, "/tmp/$logFile", 'XCAT_IVP.RESULTS', '-t', 'A' );
 | 
						|
        if ( $out ne 'Done' ) {
 | 
						|
            $rc = logResponse( 'DFS', 'GNRL02', "/tmp/$logFile", $hosts{$host}{'hcp'}, $hosts{$host}{'notifyUser'}, $host, "$logDir/$logFile", $out );
 | 
						|
            $failed = 1;
 | 
						|
        }
 | 
						|
 | 
						|
        # Clean up the ZHCP node.
 | 
						|
        ($rc, $out) = sshToNode( $hosts{$host}{'hcp'}, '', "rm -f /tmp/$logFile" );
 | 
						|
        if ( $rc != 0 ) {
 | 
						|
            $rc = logResponse( 'DFS', 'GNRL03', $hosts{$host}{'hcp'},  "rm -f /tmp/$logFile", $rc, $out );
 | 
						|
            next;
 | 
						|
        }
 | 
						|
 | 
						|
        # Try another host if we failed to send the file.
 | 
						|
        if ( $failed ) {
 | 
						|
            $failed = 0;
 | 
						|
            next;
 | 
						|
        }
 | 
						|
 | 
						|
        # Send a message if the user is logged on the system.
 | 
						|
        ($rc, $out) = sshToNode( $hosts{$host}{'hcp'}, '', "vmcp query user $hosts{$host}{'notifyUser'}" );
 | 
						|
        if ( $rc != 0 ) {
 | 
						|
            # User is either not logged on or we had a problem issuing the command.  Not important, leave.
 | 
						|
            last;
 | 
						|
        }
 | 
						|
        $out = uc( $out );
 | 
						|
        if ( $out =~ /^$hosts{$host}{'notifyUser'}/ ) {
 | 
						|
            my ($userStatus, $junk) = split '\s', $out, 2;
 | 
						|
            chomp( $userStatus );
 | 
						|
            $userStatus =~ s/^\s+|\s+$//g;       # trim both ends of the string
 | 
						|
            if ( $userStatus eq 'SSI' or $userStatus eq 'DSC' ) {
 | 
						|
                logResponse( 'DFS', 'MSG01', $hosts{$host}{'notifyUser'}, $host, $userStatus );
 | 
						|
                last;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        # Don't worry if message still does not work. It is only a message.
 | 
						|
        ($rc, $out) = sshToNode( $hosts{$host}{'hcp'}, '', "vmcp message $hosts{$host}{'notifyUser'} $msg" );
 | 
						|
        last;
 | 
						|
    }
 | 
						|
 | 
						|
    # Remove the temporary log file from the xCAT MN system.
 | 
						|
    $out = `rm -f $tempFile`;
 | 
						|
    $rc = $?;
 | 
						|
    if ( $rc != 0 ) {
 | 
						|
        logResponse( 'DFS', 'GNRL01', "rm -f $tempFile", $rc, $out );
 | 
						|
    }
 | 
						|
 | 
						|
    $rc = 0;
 | 
						|
    return $rc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
 | 
						|
=head3   pruneLogs
 | 
						|
 | 
						|
    Description : Compress and prune log files. The number of days to wait
 | 
						|
                  before pruning is specified in the site table with the
 | 
						|
                  zvmpruneivp property.  If the property does not exist
 | 
						|
                  or Management node information does not exist because of
 | 
						|
                  some reason then the default is to prune logs that are
 | 
						|
                  7 days or older.
 | 
						|
    Arguments   : Current year
 | 
						|
                  Current month (numeric)
 | 
						|
                  Current day (Julian day, numeric)
 | 
						|
    Returns     : None.
 | 
						|
    Example     : pruneLogs( $year, $mon + 1, $mday );
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub pruneLogs{
 | 
						|
    my ( $year, $month, $day ) = @_;
 | 
						|
 | 
						|
    my @lines;
 | 
						|
    my $pruneOffset = 0;
 | 
						|
    my $out;
 | 
						|
    my $pruneDate = '';
 | 
						|
    my $rc;
 | 
						|
    my $removed = 0;
 | 
						|
    my $zipOut;
 | 
						|
    my $zipped = 0;
 | 
						|
    logResponse( 'DFS', '*NONFORMATTED*', "CRON job is pruning log files." );
 | 
						|
 | 
						|
    # Determine the prune date value.
 | 
						|
    if ( ! exists $mnInfo{'PruneIVP'} or $mnInfo{'PruneIVP'} eq '' ) {
 | 
						|
        $pruneOffset = 7;
 | 
						|
    } else {
 | 
						|
        if ( looks_like_number( $mnInfo{'PruneIVP'} ) ) {
 | 
						|
            $pruneOffset = $mnInfo{'PruneIVP'};
 | 
						|
        } else {
 | 
						|
            $pruneOffset = 7;
 | 
						|
            logResponse( 'DFS', 'TP01', 'zvmpruneivp', 'site', 'not numeric', $mnInfo{'PruneIVP'}, $pruneOffset );
 | 
						|
        }
 | 
						|
    }
 | 
						|
    $pruneDate = strftime "%Y-%m-%d", 0, 0, 0, $day - $pruneOffset, $month-1, $year-1900;
 | 
						|
    logResponse( 'DFS', '*NONFORMATTED*', "Prune date: $pruneDate." );
 | 
						|
 | 
						|
    # Zip any log files that are not for today.  Current log files are similar to
 | 
						|
    # /var/log/xcat/ivp/IVP_XCAT_2016-09-19_01:01:03.log and will have .gz appended to the name
 | 
						|
    # after they have been zipped.
 | 
						|
    $out = `ls -1 /var/log/xcat/ivp/*.log`;
 | 
						|
    $rc = $?;
 | 
						|
    if ( $rc == 0 ) {
 | 
						|
        @lines = split( '\n', $out );
 | 
						|
        foreach my $fqFile ( @lines ) {
 | 
						|
            chomp( $fqFile );
 | 
						|
            my ($file) = $fqFile =~ /\/var\/log\/xcat\/ivp\/(.*)/;
 | 
						|
            my @parts = split( '_', $file );
 | 
						|
            if ( ! defined $parts[0] or $parts[0] ne 'IVP' or
 | 
						|
                 ! defined $parts[1] or ! defined $parts[2] or
 | 
						|
                 $parts[2] eq $todayDate ) {
 | 
						|
                next;
 | 
						|
            }
 | 
						|
            #logResponse( 'DFS', 'GENERIC_RESPONSE',  "ZIPPING: $file\n" );
 | 
						|
            $zipOut = `gzip $fqFile 2>&1`;
 | 
						|
            $rc = $?;
 | 
						|
            if ( $rc != 0 ) {
 | 
						|
                logResponse( 'DF', 'GENERIC_RESPONSE', "Unable to gzip $fqFile, rc: $rc, out: $out" );
 | 
						|
            } else {
 | 
						|
                $zipped++;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    # Prune any gzipped files that are too old.
 | 
						|
    $out = `ls -1 /var/log/xcat/ivp/*.log.gz`;
 | 
						|
    $rc = $?;
 | 
						|
    if ( $rc == 0 ) {
 | 
						|
        @lines = split( '\n', $out );
 | 
						|
        foreach my $fqFile ( @lines ) {
 | 
						|
            chomp( $fqFile );
 | 
						|
            my ($file) = $fqFile =~ /\/var\/log\/xcat\/ivp\/(.*)/;
 | 
						|
            my @parts = split( '_', $file );
 | 
						|
            if ( ! defined $parts[0] or $parts[0] ne 'IVP' or
 | 
						|
                 ! defined $parts[1] or ! defined $parts[2] or
 | 
						|
                 $parts[2] ge $todayDate ) {
 | 
						|
                next;
 | 
						|
            }
 | 
						|
            if ( $parts[2] ge $pruneDate ) {
 | 
						|
                next;
 | 
						|
            }
 | 
						|
 | 
						|
            #logResponse( 'DFS', 'GENERIC_RESPONSE',  "REMOVING: $file\n" );
 | 
						|
            $zipOut = `rm $fqFile 2>&1`;
 | 
						|
            $rc = $?;
 | 
						|
            if ( $rc != 0 ) {
 | 
						|
                logResponse( 'DF', 'GENERIC_RESPONSE', "Unable to remove \'rm $fqFile\', rc: $rc, out: $out" );
 | 
						|
            } else {
 | 
						|
                $removed++;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    logResponse( 'DFS', '*NONFORMATTED*', "IVP log pruning completed, zipped: $zipped, pruned: $removed." );
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   removeIVP
 | 
						|
 | 
						|
    Description : Remove an automated IVP.
 | 
						|
    Arguments   : ID of the IVP to be removed
 | 
						|
    Returns     : 0 - No error
 | 
						|
                  non-zero - Terminating error detected.
 | 
						|
    Example     : $rc = removeIVP();
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub removeIVP {
 | 
						|
    my ( $id ) = @_;
 | 
						|
    my $cmd;
 | 
						|
    my $out;
 | 
						|
    my $rc;
 | 
						|
    my $ivpId;
 | 
						|
    my %ids;
 | 
						|
    my $junk;
 | 
						|
 | 
						|
    # Get the list of IVP ids in the zvmivp table.
 | 
						|
    $cmd = '/opt/xcat/sbin/tabdump zvmivp | grep -v "^#"';
 | 
						|
    $out = `$cmd`;
 | 
						|
    $rc = $?;
 | 
						|
    if ( $rc ne 0 ) {
 | 
						|
        logResponse( 'DF', 'GNRL04', $cmd, $rc, $out );
 | 
						|
        goto FINISH_removeIVP;
 | 
						|
    }
 | 
						|
    my @lines = split( '\n', $out );
 | 
						|
    foreach my $line ( @lines ) {
 | 
						|
        chomp( $line );
 | 
						|
        my ($ivpId, $junk) = split( ',', $line, 2 );
 | 
						|
        $ivpId =~ s/^\"|\"$//g;         # trim quotes from both ends of the string
 | 
						|
        $ivpId =~ s/^\s+|\s+$//g;       # trim spaces from both ends of the string
 | 
						|
        if ( $ivpId ne '' ) {
 | 
						|
            $ids{$ivpId} = 1;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    # Validate the specified id.
 | 
						|
    if ( $id eq '' or ! exists $ids{$id} ) {
 | 
						|
        logResponse( 'DF', 'ID03', $id );
 | 
						|
    }
 | 
						|
 | 
						|
    # Update the table.
 | 
						|
    logResponse( 'DS', '*NONFORMATTED*', "Updating the z/VM IVP table (zvmivp) to remove $id" );
 | 
						|
    my $chtabCmd = "/opt/xcat/sbin/chtab -d id=\'$id\' zvmivp";
 | 
						|
    $out = `$chtabCmd`;
 | 
						|
    $rc = $?;
 | 
						|
    if ( $rc != 0 ) {
 | 
						|
        logResponse( 'DS', '*NONFORMATTED*', "\'$chtabCmd\' failed for ID($id), rc: $rc, out: $out\n" );
 | 
						|
        $rc = 1;
 | 
						|
    }
 | 
						|
 | 
						|
FINISH_removeIVP:
 | 
						|
    return $rc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   runDriverScript
 | 
						|
 | 
						|
    Description : Run a downloaded driver script.
 | 
						|
    Arguments   : This routine is driven from the action
 | 
						|
                    table, verifySets.  It takes global
 | 
						|
                    input that can be set as command
 | 
						|
                    input or by precursor routines.
 | 
						|
                    The input variables include:
 | 
						|
                    $driver - Driver script name
 | 
						|
                    $driverLoc - Location of the driver script
 | 
						|
                    $hosts - Infor for defined host nodes
 | 
						|
                    $infoCnt - Count of warnings that were generated
 | 
						|
                    $warningCnt - Count of warnings that were generated
 | 
						|
                    $zxcatParms - Command line parms to
 | 
						|
                      pass to zxcatIVP
 | 
						|
    Returns     : 0 - No error
 | 
						|
                  non-zero - Terminating error detected.
 | 
						|
    Example     : $rc = runDriverScript();
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub runDriverScript{
 | 
						|
    my $infoCnt = 0;
 | 
						|
    my @lines;
 | 
						|
    my $out;
 | 
						|
    my $rc = 0;
 | 
						|
    my $warningCnt = 0;
 | 
						|
 | 
						|
    # Analyze the driver script to determine the z/VM host that it intends to support.
 | 
						|
    my $hostNodeZhcp = '';
 | 
						|
    my $hostNode = `cat $driverLoc/$driver | grep "^export zxcatIVP_hostNode\=" | sed '/^export zxcatIVP_hostNode\=*/!d; s///; s/\"//g;q'`;
 | 
						|
    chomp( $hostNode );
 | 
						|
 | 
						|
    if ( $hostNode ne '' ) {
 | 
						|
        if ( exists $hosts{$hostNode}{'hcp'} ) {
 | 
						|
            if ( exists $hosts{$hostNode}{'notify'} ) {
 | 
						|
                $hosts{$hostNode}{'notify'} = $hosts{$hostNode}{'notify'} . 'd';
 | 
						|
            } else {
 | 
						|
                $hosts{$hostNode}{'notify'} = 'd';
 | 
						|
            }
 | 
						|
            $zhcpTarget = $hosts{$hostNode}{'hcp'};
 | 
						|
            $zvmHost = $hostNode;
 | 
						|
            push @ivpSummary, "The ZHCP related to the host, \'$hostNode\', identified in the driver script has been identified ".
 | 
						|
                "as \'$zhcpTarget\'.";
 | 
						|
        } else {
 | 
						|
            $rc = logResponse( 'DFS', 'DRIV03', $zvmHost );
 | 
						|
            $notify = 1;
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        # Driver script did not specify the host node.
 | 
						|
        $rc = logResponse( 'DFS', 'DRIV02', "$driverLoc/$driver", 'zxcatIVP_hostNode' );
 | 
						|
        $notify = 1;
 | 
						|
    }
 | 
						|
 | 
						|
    # Analyze the driver script to determine the ZHCP node that it intends to support.
 | 
						|
    my $zhcpNode = `cat $driverLoc/$driver | grep "^export zxcatIVP_zhcpNode\=" | sed '/^export zxcatIVP_zhcpNode\=*/!d; s///; s/\"//g;q'`;
 | 
						|
    chomp( $zhcpNode );
 | 
						|
    my $zhcpHcp = `/opt/xcat/bin/lsdef $zhcpNode | grep "hcp\=" | sed '/hcp\=*/!d; s///; s/\"//g;q'`;
 | 
						|
    if ( $zhcpHcp ne '' ) {
 | 
						|
        $zhcpHcp =~ s/^\s+|\s+$//g;       # trim both ends of the string
 | 
						|
        $zhcpTarget = $zhcpHcp;
 | 
						|
        foreach $hostNode ( keys %hosts ) {
 | 
						|
            if ( exists $hosts{$hostNode}{'hcp'} and $hosts{$hostNode}{'hcp'} eq $zhcpHcp ) {
 | 
						|
                if ( exists $hosts{$hostNode}{'notify'} ) {
 | 
						|
                    $hosts{$hostNode}{'notify'} = $hosts{$hostNode}{'notify'} . 'd';
 | 
						|
                } else {
 | 
						|
                    $hosts{$hostNode}{'notify'} = 'd';
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    my $exportCmd = '';
 | 
						|
    if ( $zxcatParms ne '' ) {
 | 
						|
        $ENV{zxcatIVP_moreCmdOps}=$zxcatParms;
 | 
						|
    } else {
 | 
						|
        delete $ENV{zxcatIVP_moreCmdOps};
 | 
						|
    }
 | 
						|
 | 
						|
    logResponse( 'DF', '*NONFORMATTED*', '*******************************************************************************' );
 | 
						|
    logResponse( 'DF', 'GENERIC_RESPONSE_NOINDENT', "Using the driver script to drive the IVP. The output from the run follows." );
 | 
						|
    logResponse( 'DF', '*NONFORMATTED*', '*******************************************************************************' );
 | 
						|
    $out = `chmod +x $driverLoc/$driver`;
 | 
						|
    $out = `$driverLoc/$driver`;
 | 
						|
    $rc = $?;
 | 
						|
    if ( $rc != 0 ) {
 | 
						|
        $rc = logResponse( 'DFS', 'DRIV01', "$driverLoc/$driver", $rc, $out );
 | 
						|
        $notify = 1;
 | 
						|
        goto FINISH_runDriverScript;
 | 
						|
    }
 | 
						|
 | 
						|
    # Determine how many warnings and information messages were generated so that we can
 | 
						|
    # produce a summary message upon completion of the IVP.
 | 
						|
    @lines = split( '\n', $out );
 | 
						|
    foreach my $line ( @lines ) {
 | 
						|
        if ( $line =~ /^Warning \(/ ) { $warningCnt++; }
 | 
						|
        if ( $line =~ /^Info \(/ ) { $infoCnt++; }
 | 
						|
    }
 | 
						|
    push @ivpSummary, "The driver script generated $warningCnt warnings and $infoCnt information messages.";
 | 
						|
    logResponse( 'DF', '*NONFORMATTED*', $out );
 | 
						|
 | 
						|
FINISH_runDriverScript:
 | 
						|
    if ( $warningCnt != 0 ) {
 | 
						|
        $notify = 1;
 | 
						|
    }
 | 
						|
    return $rc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   runPrepScript
 | 
						|
 | 
						|
    Description : Push the appropriate level of preparation
 | 
						|
                  script to a compute node and run it to
 | 
						|
                  validate the system and build the driver
 | 
						|
                  script.
 | 
						|
    Arguments   : Global defaults set as command line parameters provide input
 | 
						|
                    to this routine:
 | 
						|
                    $driver - Name of driver script
 | 
						|
                    $driverLoc - Location of the driver script
 | 
						|
                    $infoCnt - Count of warnings that were generated
 | 
						|
                    $openstackIP - IP for OpenStack compute node
 | 
						|
                    $openstackUser - User for OpenStack compute node
 | 
						|
                    $prepParms - Parms for preparation script
 | 
						|
                    $warnErrCnt - Count of warnings and errors that were generated
 | 
						|
    Returns     : 0 - No error
 | 
						|
                  non-zero - Terminating error detected.
 | 
						|
    Example     : $rc = runPrepScript();
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub runPrepScript {
 | 
						|
    my $cmd = '';
 | 
						|
    my $infoCnt = 0;
 | 
						|
    my $line;
 | 
						|
    my @lines;
 | 
						|
    my $out = '';
 | 
						|
    my $rc = 0;
 | 
						|
    my $retRC = 0;
 | 
						|
    my $tmpDir = '';
 | 
						|
    my $warningCnt = 0;
 | 
						|
 | 
						|
    # Determine the name of the driver script based on the IP address for the compute node.
 | 
						|
    $driver = "zxcatIVPDriver_$openstackIP.sh";
 | 
						|
 | 
						|
    # Create the local IVP directory.
 | 
						|
    if ( !-d $driverLoc ) {
 | 
						|
        $out = `mkdir -m a=rwx,g=rx,o= -p $driverLoc`;
 | 
						|
        $rc = $?;
 | 
						|
        if ( $rc != 0 ) {
 | 
						|
            $rc = logResponse( 'DFS', 'PREP01', $driverLoc, $rc, $out );
 | 
						|
            $notify = 1;
 | 
						|
            goto FINISH_runPrepScript;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    # Determine the OpenStack level.
 | 
						|
    my $level = getOpenStackLevel( $openstackIP, $openstackUser );
 | 
						|
    if ( $level eq '' ) {
 | 
						|
        $notify = 1;
 | 
						|
        $rc = logResponse( 'DFS', 'PREP06', $openstackIP );
 | 
						|
        goto FINISH_runPrepScript;
 | 
						|
    }
 | 
						|
    my $levelLetter = substr( $level, 0, 1);
 | 
						|
    push @ivpSummary, "OpenStack system at $openstackIP is running the Nova $level release.";
 | 
						|
 | 
						|
    # Determine the appropriate preparation script to send to the compute node.
 | 
						|
    my $prepDir = '/opt/xcat/share/xcat/tools/zvm';
 | 
						|
    my $prepScript = "prep_zxcatIVP_$level.pl";
 | 
						|
    logResponse( 'DF', 'GENERIC_RESPONSE', "Attempting to push $prepScript to the OpenStack system ".
 | 
						|
                       "at $openstackIP. It will be used to validate the OpenStack environment and create ".
 | 
						|
                       "a driver script to be used for the validation on the xCAT management node." );
 | 
						|
    my $runPrepScript = 1;
 | 
						|
 | 
						|
    # Create a directory on the compute node to hold the preparation script and driver script.
 | 
						|
    $cmd = 'mktemp -d /tmp/xCAT.XXXXXXXXXX';
 | 
						|
    ($rc, $tmpDir) = sshToNode( $openstackIP, $openstackUser, $cmd );
 | 
						|
    if ( $rc != 0 ) {
 | 
						|
        # Unable to create the directory.  Let's see if we have an old driver script that we can use.
 | 
						|
        $rc = logResponse( 'DFS', 'PREP02', $openstackIP, "$driverLoc/$driver", $cmd, $rc, $out );
 | 
						|
        $notify = 1;
 | 
						|
        goto FINISH_runPrepScript;
 | 
						|
    } else {
 | 
						|
        # Push the preparation script to the compute node and run it.
 | 
						|
        chomp($tmpDir);
 | 
						|
        $cmd = "/usr/bin/scp $prepDir/$prepScript $openstackUser\@$openstackIP:$tmpDir";
 | 
						|
        $out = `/usr/bin/scp "$prepDir/$prepScript" "$openstackUser\@$openstackIP:$tmpDir"`;
 | 
						|
        $rc = $?;
 | 
						|
        if ( $rc != 0 ) {
 | 
						|
            # Unable to push the preparation script.  Let's see if we have an old driver script that we can use.
 | 
						|
            $rc = logResponse( 'DFS', 'PREP02', $openstackIP, "$driverLoc/$driver", $cmd, $rc, $out );
 | 
						|
            $notify = 1;
 | 
						|
            goto FINISH_runPrepScript;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ( $runPrepScript ) {
 | 
						|
        # Run the preparation script.
 | 
						|
        ($rc, $out) = sshToNode( $openstackIP, $openstackUser, "chmod +x $tmpDir/$prepScript");
 | 
						|
        ($rc, $out) = sshToNode( $openstackIP, $openstackUser, "$tmpDir/$prepScript '--driver' $tmpDir/$driver $prepParms" );
 | 
						|
        logResponse( 'DF', '*NONFORMATTED*', '*******************************************************************************' );
 | 
						|
        logResponse( 'DF', 'GENERIC_RESPONSE_NOINDENT', "The output from the preparation script that is run on the compute node follows. ".
 | 
						|
                     "The preparation script validates the z/VM related OpenStack configuration file properties." );
 | 
						|
        logResponse( 'DF', '*NONFORMATTED*', '*******************************************************************************' );
 | 
						|
        logResponse( 'DF', '*NONFORMATTED*', $out );
 | 
						|
 | 
						|
        # Determine how many warnings were generated so that we can produce a summary message upon completion of the IVP.
 | 
						|
        if ( $levelLetter gt 'L' ) {
 | 
						|
            @lines = split( '\n', $out );
 | 
						|
            foreach $line ( @lines ) {
 | 
						|
                if ( $line =~ /^Warning \(/ ) { $warningCnt++; }
 | 
						|
                if ( $line =~ /^Info \(/ ) { $infoCnt++; }
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            @lines = split( '\n', $out );
 | 
						|
            foreach $line ( @lines ) {
 | 
						|
                if ( $line =~ /^Warning:/ ) { $warningCnt++; }
 | 
						|
                if ( $line =~ /^Info:/ ) { $infoCnt++; }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        push @ivpSummary, "The preparation script generated $warningCnt warnings and $infoCnt information messages.";
 | 
						|
 | 
						|
        # Pull back the driver script.
 | 
						|
        if ( -e "$driverLoc/$driver" ) {
 | 
						|
            $out = `mv -f $driverLoc/$driver $driverLoc/$driver.old`;
 | 
						|
            $rc = $?;
 | 
						|
            if ( $rc != 0 ) {
 | 
						|
                logResponse( 'S', 'GENERIC_RESPONSE', "Unable to move $driverLoc/$driver to $driverLoc/$driver.old, rc: $rc" );
 | 
						|
                $notify = 1;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        $cmd = "/usr/bin/scp $openstackUser\@$openstackIP:$tmpDir/$driver $driverLoc/$driver";
 | 
						|
        $out = `/usr/bin/scp "$openstackUser\@$openstackIP:$tmpDir/$driver" "$driverLoc/$driver"`;
 | 
						|
        $rc = $?;
 | 
						|
        if ( $rc != 0 ) {
 | 
						|
            $rc = logResponse( 'DFS', 'PREP04', "$driverLoc/$driver", $openstackIP, $cmd, $rc, $out );
 | 
						|
            $notify = 1;
 | 
						|
            goto FINISH_runPrepScript;
 | 
						|
        }
 | 
						|
 | 
						|
        $cmd = "chmod 660 $driverLoc/$driver 2>&1";
 | 
						|
        $out = `$cmd`;
 | 
						|
        $rc = $?;
 | 
						|
        if ( $rc != 0 ) {
 | 
						|
            logResponse( 'FS', 'PREP07', "$driverLoc/$driver", $cmd, $rc, $out );
 | 
						|
            $notify = 1;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
FINISH_runPrepScript:
 | 
						|
    if ( !-s "$driverLoc/$driver"  && -s "$driverLoc/$driver.old" ) {
 | 
						|
        # New driver does not exist but old driver exists, use the old one.
 | 
						|
        $out = `mv -f $driverLoc/$driver.old $driverLoc/$driver`;
 | 
						|
        $rc = $?;
 | 
						|
        if ( $rc != 0 ) {
 | 
						|
            logResponse( 'S', 'GENERIC_RESPONSE', "Unable to move $driverLoc/$driver.old to $driverLoc/$driver, rc: $rc" );
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ( -s "$driverLoc/$driver" ) {
 | 
						|
        $retRC = 0;
 | 
						|
        # Add the driver script to the log file.
 | 
						|
        $out = `cat $driverLoc/$driver`;
 | 
						|
        logResponse( 'F', '*NONFORMATTED*', '*******************************************************************************' );
 | 
						|
        logResponse( 'F', 'GENERIC_RESPONSE_NOINDENT', "The contents of the driver script used for the rest of this IVP follows. ".
 | 
						|
                     "The driver script is used to run the rest of the IVP on the xCAT Management Node." );
 | 
						|
        logResponse( 'F', 'GENERIC_RESPONSE_NOINDENT', 'Note: Any line which set a password related property has been removed.' );
 | 
						|
        logResponse( 'F', '*NONFORMATTED*', '*******************************************************************************' );
 | 
						|
        $out = `echo "$out" | grep -v "^export zxcatIVP_xcatUserPw"`;
 | 
						|
        logResponse( 'F', '*NONFORMATTED*', $out );
 | 
						|
    }
 | 
						|
 | 
						|
    if ( $warningCnt != 0 ) {
 | 
						|
        $notify = 1;
 | 
						|
    }
 | 
						|
 | 
						|
    if ( $tmpDir ne '' ) {
 | 
						|
        $cmd = "rm -Rf $tmpDir 2>&1";
 | 
						|
        ($rc, $out) = sshToNode( $openstackIP, $openstackUser, "$cmd");
 | 
						|
        $rc = $?;
 | 
						|
        if ( $rc != 0 ) {
 | 
						|
            $rc = logResponse( 'DFS', 'CLNUP01', $openstackIP, $tmpDir, $cmd, $rc, $out );
 | 
						|
            $notify = 1;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return $retRC;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   scheduleIVP
 | 
						|
 | 
						|
    Description : Schedule an automated IVP.
 | 
						|
    Arguments   : Global defaults set as command line parameters provide input
 | 
						|
                    to this routine:
 | 
						|
                    $comments - Comments for IVP
 | 
						|
                    $disable - Disable option
 | 
						|
                    $id - ID to update or 'NEW'
 | 
						|
                    $openstackIP - IP for OpenStack compute node
 | 
						|
                    $openstackUser - User for OpenStack compute node
 | 
						|
                    $orchParms - Parms for this script when IVP run
 | 
						|
                    $prepParms - Parms for preparation script
 | 
						|
                    $schedule - Hours to schedule
 | 
						|
                    $scheduledType - Type of IVP
 | 
						|
                    $zxcatParms - Parms for zxcatIVP script
 | 
						|
    Returns     : 0 - No error
 | 
						|
                  non-zero - Terminating error detected.
 | 
						|
    Example     : $rc = scheduleIVP();
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub scheduleIVP {
 | 
						|
    my $cmd;
 | 
						|
    my $out;
 | 
						|
    my $rc;
 | 
						|
    my $ivpId;
 | 
						|
    my %ids;
 | 
						|
    my $junk;
 | 
						|
 | 
						|
    # Get the list of IVP ids in the zvmivp table.
 | 
						|
    $cmd = '/opt/xcat/sbin/tabdump zvmivp | grep -v "^#"';
 | 
						|
    $out = `$cmd`;
 | 
						|
    $rc = $?;
 | 
						|
    if ( $rc ne 0 ) {
 | 
						|
        logResponse( 'DF', 'GNRL04', $cmd, $rc, $out );
 | 
						|
        goto FINISH_scheduleIVP;
 | 
						|
    }
 | 
						|
    my @lines = split( '\n', $out );
 | 
						|
    foreach my $line ( @lines ) {
 | 
						|
        chomp( $line );
 | 
						|
        my ($ivpId, $junk) = split( ',', $line, 2 );
 | 
						|
        $ivpId =~ s/^\"|\"$//g;         # trim quotes from both ends of the string
 | 
						|
        $ivpId =~ s/^\s+|\s+$//g;       # trim spaces from both ends of the string
 | 
						|
        if ( $ivpId ne '' ) {
 | 
						|
            $ids{$ivpId} = 1;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    # Validate the specified id.  Either generate a new ID if this is a new
 | 
						|
    # request (specified as 'new' or omitted or use the id that was passed.
 | 
						|
    if ( $id eq '' or $id eq 'NEW' ) {
 | 
						|
        # Generate the new Id
 | 
						|
        my $i;
 | 
						|
        for ( $i = 10; $i < 10010; $i++ ) {
 | 
						|
            if ( ! exists $ids{$i} ) {
 | 
						|
                last;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if ( $i <= 10010 ) {
 | 
						|
            $id = $i;
 | 
						|
        } else {
 | 
						|
            # Could not find an available number in the first 10000 IDs.
 | 
						|
            logResponse( 'DF', 'ID01' );
 | 
						|
            goto FINISH_scheduleIVP;
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        # Validate the Id
 | 
						|
        if ( ! exists $ids{$id} ) {
 | 
						|
            logResponse( 'DF', 'ID02', $id );
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ( $scheduledType eq '' ) {
 | 
						|
        logResponse( 'DF', 'OPER01', '--type' );
 | 
						|
        goto FINISH_scheduleIVP;
 | 
						|
    }
 | 
						|
    $scheduledType = lc( $scheduledType );
 | 
						|
    if ( $scheduledType ne 'basicivp' and $scheduledType ne 'fullivp' ) {
 | 
						|
        logResponse( 'DF', 'OPER02', '--type', $scheduledType, '\'basicivp\' or \'fullivp\'' );
 | 
						|
        goto FINISH_scheduleIVP;
 | 
						|
    }
 | 
						|
    if ( $scheduledType eq 'basicivp' ) {
 | 
						|
        # Ignore any FULLIVP parms
 | 
						|
        $openstackIP = '';
 | 
						|
        $openstackUser = '';
 | 
						|
        $prepParms = '';
 | 
						|
    }
 | 
						|
 | 
						|
    # Normalize the schedule.
 | 
						|
    my %hours;
 | 
						|
    my @parts = split( ' ', $schedule );
 | 
						|
    foreach my $hour ( @parts ) {
 | 
						|
        $hour =~ s/^\s+|\s+$//g;         # trim spaces from both ends of the string
 | 
						|
        $hours{$hour} = 1;
 | 
						|
    }
 | 
						|
    $schedule = '';
 | 
						|
    for ( my $hour = 0; $hour <= 23; $hour++ ) {
 | 
						|
        if ( exists $hours{$hour} ) {
 | 
						|
            $schedule = "$schedule $hour";
 | 
						|
            delete $hours{$hour};
 | 
						|
        }
 | 
						|
    }
 | 
						|
    $schedule =~ s/^\s+|\s+$//g;         # trim spaces from both ends of the string
 | 
						|
    my (@leftOver) = keys %hours;
 | 
						|
    if ( scalar @leftOver != 0 ) {
 | 
						|
        my $badValues = join( '\' and \'', @leftOver );
 | 
						|
        logResponse( 'DF', 'OPER02', '--schedule', $badValues, '0-23' );
 | 
						|
        goto FINISH_scheduleIVP;
 | 
						|
    }
 | 
						|
 | 
						|
    if ( $comments =~ /,/ ) {
 | 
						|
        $comments =~ s/,//g;         # trim commas from the string
 | 
						|
    }
 | 
						|
 | 
						|
    my $disableFlag = '';
 | 
						|
    if ( $disable == 1 ) {
 | 
						|
        $disableFlag = 'YES';
 | 
						|
    }
 | 
						|
 | 
						|
    # Update the table.
 | 
						|
    logResponse( 'DS', '*NONFORMATTED*', "Updating the z/VM IVP table (zvmivp) for $id" );
 | 
						|
    my $chtabCmd = "/opt/xcat/sbin/chtab id=\'$id\' ".
 | 
						|
                   "zvmivp.ip=\'$openstackIP\' ".
 | 
						|
                   "zvmivp.schedule=\'$schedule\' ".
 | 
						|
                   "zvmivp.last_run=\'\' ".
 | 
						|
                   "zvmivp.type_of_run=\'$scheduledType\' ".
 | 
						|
                   "zvmivp.access_user=\'" . hexEncode( $openstackUser ) . "\' ".
 | 
						|
                   "zvmivp.orch_parms=\'" . hexEncode( $orchParms ) . "\' ".
 | 
						|
                   "zvmivp.prep_parms=\'" . hexEncode( $prepParms ) . "\' ".
 | 
						|
                   "zvmivp.main_ivp_parms=\'" . hexEncode( $zxcatParms ) . "\' ".
 | 
						|
                   "zvmivp.comments=\'" . hexEncode( $comments ) . "\' ".
 | 
						|
                   "zvmivp.disable=\'$disableFlag\'";
 | 
						|
    $out = `$chtabCmd`;
 | 
						|
    $rc = $?;
 | 
						|
    if ( $rc != 0 ) {
 | 
						|
        logResponse( 'DS', '*NONFORMATTED*', "\'$chtabCmd\' failed for ID($id), rc: $rc, out: $out\n" );
 | 
						|
        $rc = 1;
 | 
						|
    }
 | 
						|
 | 
						|
FINISH_scheduleIVP:
 | 
						|
    return $rc;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   setupLogFile
 | 
						|
 | 
						|
    Description : Set up the log file for this run.
 | 
						|
    Arguments   : None
 | 
						|
    Returns     : 0 - No error
 | 
						|
                  non-zero - Terminating error detected.
 | 
						|
    Example     : $rc = setupLogFile();
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub setupLogFile {
 | 
						|
    my $out;
 | 
						|
    my $rc = 0;
 | 
						|
    my $ipString = '';
 | 
						|
 | 
						|
    # Indicate that the log file will need to be finished.
 | 
						|
    # This is a safety in case something goes wrong during
 | 
						|
    # the IVP run and causes the program to break.
 | 
						|
    $needToFinishLogFile = 1;
 | 
						|
 | 
						|
    # Determine the IP address to associate with the log file.
 | 
						|
    if ( $openstackIP eq '' ) {
 | 
						|
        # Must be doing either a generic zxcatIVP or a full
 | 
						|
        # IVP for the compute node sharing the system with this
 | 
						|
        # xCAT MN.  Use the string "XCAT".
 | 
						|
        $ipString = 'XCAT';
 | 
						|
    } else {
 | 
						|
        if ( exists $localIPs{$openstackIP} ) {
 | 
						|
            $ipString = 'XCAT';
 | 
						|
        } else {
 | 
						|
            $ipString = $openstackIP;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    # Determine the timestamp to use for the log.
 | 
						|
    my ($sec,  $min,  $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
 | 
						|
    $startTime = sprintf("%02d:%02d:%02d on %04d-%02d-%02d",
 | 
						|
                           $hour, $min, $sec, $year + 1900, $mon + 1, $mday );
 | 
						|
    my $currTime = sprintf("%04d-%02d-%02d_%02d:%02d:%02d",
 | 
						|
                           $year + 1900, $mon + 1, $mday, $hour, $min, $sec);
 | 
						|
 | 
						|
    # If the log directory does not exist then create it.
 | 
						|
    if ( !-d $logDir ) {
 | 
						|
        # Directory did not exist.  Create it.
 | 
						|
        $out = `mkdir -p $logDir`;
 | 
						|
        $rc = $?;
 | 
						|
        if ( $rc != 0 ) {
 | 
						|
            logResponse( 'DFS', 'GENERIC_RESPONSE', 'Failed to set up the log directory.  IVP will run without a log file.' );
 | 
						|
            $rc = 0;     # Continue processing.
 | 
						|
            goto FINISH_setupLogFile;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    # Create the log file.
 | 
						|
    $logFile = "IVP\_$ipString\_$currTime\.log";
 | 
						|
    open $logFileHandle, ">", "$logDir/$logFile";
 | 
						|
    $rc = $?;
 | 
						|
    if ( $rc != 0 ) {
 | 
						|
        logResponse( 'DFS', 'GENERIC_RESPONSE', "Failed to open the log file: $logFile.  IVP will run without a log file. $!" );
 | 
						|
        $rc = 0;     # Continue processing.
 | 
						|
        goto FINISH_setupLogFile;
 | 
						|
    }
 | 
						|
    $out = `chmod 644 "$logDir/$logFile"`;
 | 
						|
 | 
						|
    push @ivpSummary, "The following logfile was created for this run: $logFile";
 | 
						|
 | 
						|
FINISH_setupLogFile:
 | 
						|
    return $rc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   showCILevel
 | 
						|
 | 
						|
    Description : Show the cloud-init version installed
 | 
						|
                  in the node.
 | 
						|
    Arguments   : None
 | 
						|
    Returns     : 0 - No error
 | 
						|
                  non-zero - Terminating error detected.
 | 
						|
    Example     : $rc = showCILevel();
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub showCILevel {
 | 
						|
    my $ciLevel = '';
 | 
						|
    my $out = '';
 | 
						|
    my $rc = 0;
 | 
						|
 | 
						|
    # Attempted to obtain the version using the routine
 | 
						|
    # accessible through the $PATH variable.
 | 
						|
    ($rc, $out) = sshToNode( $nodeName, '', 'cloud-init --version 2>&1');
 | 
						|
    if ( $rc == 255 ) {
 | 
						|
        logResponse( 'DF', 'GENERIC_RESPONSE', $out );
 | 
						|
        goto FINISH_showCILevel;
 | 
						|
    } elsif ( $rc == 0 ) {
 | 
						|
        if ( $out =~ /^cloud-init / ) {
 | 
						|
            ($ciLevel) = $out =~ /^cloud-init (.*)/;
 | 
						|
            my $msgText = "Version of cloud-init: $ciLevel";
 | 
						|
            logResponse( 'DF', 'GENERIC_RESPONSE', $msgText );
 | 
						|
            # <todo> Add code to compare the version to what is available in xcat.
 | 
						|
            goto FINISH_showCILevel;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    # Attempt to locate the version in the various cloud-init scripts
 | 
						|
    # in the target node.
 | 
						|
    # <todo> Add support to look for versions on the node if the invocation
 | 
						|
    # using the path did not show the version.
 | 
						|
 | 
						|
FINISH_showCILevel:
 | 
						|
    return $rc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   showHelp
 | 
						|
 | 
						|
    Description : Show the help inforamtion.
 | 
						|
    Arguments   : None.
 | 
						|
    Returns     : None.
 | 
						|
    Example     : showHelp();
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub showHelp{
 | 
						|
    print "$0 verify the capabilities of a node.\n\n";
 | 
						|
    print $usage_string;
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   sshToNode
 | 
						|
 | 
						|
    Description : SSH to a node and issue a command.
 | 
						|
                  Check for SSH errors.
 | 
						|
    Arguments   : Node name or IP address/DNS name
 | 
						|
                  user if we need to specify SUDO
 | 
						|
                  Command to issue
 | 
						|
                  Options (char string):
 | 
						|
                    q - Quiet, Don't generate an error message on failure
 | 
						|
    Returns     : Return code:
 | 
						|
                      0 - Normal Linux success
 | 
						|
                      255 - Unable to SSH to system
 | 
						|
                      non-zero - command error
 | 
						|
                  Output from the command or a error string on an SSH failure.
 | 
						|
    Example     : ($rc, $out) = sshToNode( $nodeName, $user, $command );
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub sshToNode{
 | 
						|
    my ( $nodeName, $user, $cmd, $options ) = @_;
 | 
						|
    my $rc = 0;
 | 
						|
    my $out = '';
 | 
						|
 | 
						|
    if ( ! defined $options ) {
 | 
						|
        $options = '';
 | 
						|
    }
 | 
						|
 | 
						|
    if ( $user eq '' ) {
 | 
						|
        $out = `ssh $nodeName -qoBatchMode=yes '$cmd'`;
 | 
						|
        $rc = $? >> 8;
 | 
						|
    } else {
 | 
						|
        $out = `ssh $user\@$nodeName -qoBatchMode=yes '$cmd'`;
 | 
						|
        $rc = $? >> 8;
 | 
						|
    }
 | 
						|
 | 
						|
    if ( $rc == 255 and $options !~ /q/ ) {
 | 
						|
        logResponse( 'DFS', 'VSTN01', $nodeName );  # Keep $rc = 255.
 | 
						|
        $out = "Unable to SSH to $nodeName";
 | 
						|
    }
 | 
						|
 | 
						|
    return ($rc, $out);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   verifyAccess
 | 
						|
 | 
						|
    Description : Verify the xCAT MN can access a system.
 | 
						|
    Arguments   : Node name or IP address
 | 
						|
    Returns     : 0 - No error
 | 
						|
                  non-zero - Terminating error detected.
 | 
						|
    Example     : $rc = verifyAccess();
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub verifyAccess{
 | 
						|
    my ( $nodeOrIP ) = @_;
 | 
						|
 | 
						|
    my $rc = 0;
 | 
						|
    my $out = '';
 | 
						|
 | 
						|
    ($rc, $out) = sshToNode( $nodeOrIP, '', 'pwd 2>/dev/null' );
 | 
						|
    goto FINISH_verifyAccess if ( $rc == 255 );    # Already generated a message
 | 
						|
    if ( $rc != 0 ) {
 | 
						|
        $rc = logResponse( 'DFS', 'VA01' );
 | 
						|
    }
 | 
						|
 | 
						|
FINISH_verifyAccess:
 | 
						|
    return $rc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   verifyBasicXCAT
 | 
						|
 | 
						|
    Description : Verify the basic setup of xCAT.
 | 
						|
    Arguments   : None
 | 
						|
    Returns     : 0 - No error
 | 
						|
                  non-zero - Terminating error detected.
 | 
						|
    Example     : $rc = verifyBasicXCAT();
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub verifyBasicXCAT{
 | 
						|
    my $infoCnt = 0;
 | 
						|
    my @lines;
 | 
						|
    my $rc = 0;
 | 
						|
    my $warningCnt = 0;
 | 
						|
 | 
						|
    $rc = logResponse( 'DF', 'GENERIC_RESPONSE', 'The IVP will be invoked with BYPASS messages suppressed. '.
 | 
						|
        'This is because a basic IVP run will produce a number of BYPASS messages due to the fact that '.
 | 
						|
        'it is not driven with a full set of configuration operands causing it to avoid some tests. '.
 | 
						|
        'Instead you will see an information line indicating that the message was ignored.' );
 | 
						|
    $ENV{'zxcatIVP_bypassMsg'} = 0;   # No bypass messages
 | 
						|
    $ENV{'zxcatIVP_moreCmdOps'} = $zxcatParms;
 | 
						|
    my $out = `/opt/xcat/bin/zxcatIVP.pl`;
 | 
						|
 | 
						|
    $rc = logResponse( 'DF', '*NONFORMATTED*', $out );
 | 
						|
    # Determine how many warnings were generated so that we can produce a summary message upon completion of the IVP.
 | 
						|
    @lines = split( '\n', $out );
 | 
						|
    foreach my $line ( @lines ) {
 | 
						|
        if ( $line =~ /^Warning/ ) { $warningCnt++; }
 | 
						|
        if ( $line =~ /^Info/ ) { $infoCnt++; }
 | 
						|
    }
 | 
						|
    push @ivpSummary, "The zxcatIVP.pl script generated $warningCnt warnings and $infoCnt information messages.";
 | 
						|
 | 
						|
FINISH_verifyBasicXCAT:
 | 
						|
    if ( $warningCnt != 0 ) {
 | 
						|
        $notify = 1;
 | 
						|
    }
 | 
						|
    return $rc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   verifyDistro
 | 
						|
 | 
						|
    Description : Verify that the distro is supported.
 | 
						|
    Arguments   : None
 | 
						|
    Returns     : 0 - No error
 | 
						|
                  non-zero - Terminating error detected.
 | 
						|
    Example     : $rc = verifyDistro();
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub verifyDistro{
 | 
						|
    my $rc = 0;
 | 
						|
 | 
						|
    my $supported = xCAT::zvmUtils->isOSVerSupported( $tgtOS );
 | 
						|
    if ( !$supported ) {
 | 
						|
        $rc = logResponse( 'DF', 'VD01', ($tgtOS) );
 | 
						|
    }
 | 
						|
 | 
						|
    return $rc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   verifyLogResponse
 | 
						|
 | 
						|
    Description : Script test function to test functioning
 | 
						|
                  of the logResponse() routine.
 | 
						|
    Arguments   : None
 | 
						|
    Returns     : 0 - No error
 | 
						|
                  non-zero - Terminating error detected.
 | 
						|
    Example     : $rc = verifyLogResponse();
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub verifyLogResponse{
 | 
						|
    my $rc = 0;
 | 
						|
    my $sub2 = 'sub2';
 | 
						|
 | 
						|
    $rc = logResponse( 'DF', 'VX01' );
 | 
						|
    print "rc: $rc\n";
 | 
						|
    logResponse( 'DF', 'VPF01', ($nodeName, 0, 'result message') );
 | 
						|
    $rc = logResponse( 'DF', 'VX03', $nodeName, $sub2);
 | 
						|
    print "rc: $rc\n";
 | 
						|
    $rc = logResponse( 'DF', 'VX03', $nodeName, 'sub2a');
 | 
						|
    print "rc: $rc\n";
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   verifyPower
 | 
						|
 | 
						|
    Description : Verify the node is powered on.
 | 
						|
    Arguments   : None
 | 
						|
    Returns     : 0 - No error
 | 
						|
                  non-zero - Terminating error detected.
 | 
						|
    Example     : $rc = verifyPower();
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub verifyPower {
 | 
						|
    my ( $nodeName ) = @_;
 | 
						|
    my $rc = 0;
 | 
						|
    my $powerState;
 | 
						|
 | 
						|
    my $out = `/opt/xcat/bin/rpower $nodeName stat 2>&1`;
 | 
						|
    $rc = $?;
 | 
						|
    if ( $rc != 0 ) {
 | 
						|
        $rc = logResponse( 'DF', 'VPF01', ($nodeName, $rc, $out) );
 | 
						|
        goto FINISH_verifyPower if ( $rc > 0 );
 | 
						|
    }
 | 
						|
 | 
						|
    $out = lc( $out );
 | 
						|
    if ( $out =~ /$nodeName: / ) {
 | 
						|
        chomp $out;
 | 
						|
        ($powerState) = $out =~ /$nodeName: (.*)/;
 | 
						|
    }
 | 
						|
 | 
						|
    if ( $powerState ne 'on' ) {
 | 
						|
        $rc = logResponse( 'DFS', 'VP02', ($nodeName) );
 | 
						|
    }
 | 
						|
 | 
						|
FINISH_verifyPower:
 | 
						|
    return $rc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   verifyService
 | 
						|
 | 
						|
    Description : Verify that specified services are running.
 | 
						|
    Arguments   : Node name or IP address
 | 
						|
                  Blank delimitted list of service names
 | 
						|
                    service name begins with the name and
 | 
						|
                    has a comma separated list of run levels
 | 
						|
                    which are to be verified as 'on'
 | 
						|
    Returns     : 0 - No error
 | 
						|
                  non-zero - Terminating error detected.
 | 
						|
    Example     : $rc = verifyService();
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub verifyService {
 | 
						|
    my ( $nodeOrIP, $namesAndLevels ) = @_;
 | 
						|
    my @serviceList = split ( / /, $namesAndLevels );
 | 
						|
 | 
						|
    my $rc = 0;
 | 
						|
    my $serviceOut = '';
 | 
						|
 | 
						|
    # Get the list of service names and run levels into an array.
 | 
						|
 | 
						|
    # Get the list of configured services.  The output looks similar to:
 | 
						|
    # service_name    0:off   1:off   2:off   3:off   4:off   5:off   6:off
 | 
						|
    ($rc, $serviceOut) = sshToNode( $nodeOrIP, '', "chkconfig --list 2>&1" );
 | 
						|
    goto FINISH_verifyService if ( $rc == 255 );
 | 
						|
 | 
						|
    # Look for missing services
 | 
						|
    my @missingService;
 | 
						|
    my @foundService;
 | 
						|
    my @nonrunningService;
 | 
						|
    foreach my $serviceInfo ( @serviceList ) {
 | 
						|
        my @offLevels;
 | 
						|
        my $levels;
 | 
						|
        my @serviceRunLevels = split( /,/, $serviceInfo );
 | 
						|
        my $service = shift @serviceRunLevels;
 | 
						|
        ($levels) = $serviceOut =~ /^$service(.*)\s(.*)\n/m;
 | 
						|
        $levels =~ s/^\s+|\s+$//g if ( defined $levels );
 | 
						|
        if (( defined $levels ) and ( $levels ne '' )) {
 | 
						|
            # Verify the run levels are enabled.
 | 
						|
            foreach my $level ( @serviceRunLevels ) {
 | 
						|
                if ( $levels !~ /$level:on/ ) {
 | 
						|
                    push @offLevels, $level;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            if ( @offLevels ) {
 | 
						|
                $levels = join(", ", @offLevels);
 | 
						|
                $rc = logResponse( 'DF', 'VS06', $service, $levels );
 | 
						|
                goto FINISH_verifyService if ( $rc > 0 );
 | 
						|
            } else {
 | 
						|
                push @foundService, $service;
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            push @nonrunningService, $service;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ( @foundService ) {
 | 
						|
        my $list = join(", ", @foundService);
 | 
						|
        $rc = logResponse( 'DF', 'GENERIC_RESPONSE', "The following services are configured to start: $list" );
 | 
						|
        goto FINISH_verifyService if ( $rc > 0 );
 | 
						|
    }
 | 
						|
    if ( @nonrunningService ) {
 | 
						|
        my $list = join(", ", @nonrunningService);
 | 
						|
        $rc = logResponse( 'DF', 'VS05', $list );
 | 
						|
        goto FINISH_verifyService if ( $rc > 0 );
 | 
						|
    }
 | 
						|
 | 
						|
FINISH_verifyService:
 | 
						|
    return $rc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   verifyXcatconf4z
 | 
						|
 | 
						|
    Description : Verify xcatconf4z is properly installed
 | 
						|
                  and is the correct version.
 | 
						|
    Arguments   : Node name or IP address
 | 
						|
    Returns     : 0 - No error
 | 
						|
                  non-zero - Terminating error detected.
 | 
						|
    Example     : $rc = verifyXcatconf4z();
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub verifyXcatconf4z{
 | 
						|
    my ( $nodeOrIP ) = @_;
 | 
						|
    my $rc = 0;
 | 
						|
    my $out;
 | 
						|
    my ($mnVersion, $tgtVersion);
 | 
						|
 | 
						|
    # Verify service is installed
 | 
						|
    $rc = verifyService( $nodeOrIP, 'xcatconf4z,2,3,5' );
 | 
						|
    goto FINISH_verifyXcatconf4z if ( $rc == 255 );
 | 
						|
 | 
						|
    # Get the xCAT MN's xcatconf4z version level.
 | 
						|
    $out = `/opt/xcat/share/xcat/scripts/xcatconf4z version`;
 | 
						|
    if ( $out =~ /xcatconf4z version: / ) {
 | 
						|
        chomp $out;
 | 
						|
        ($mnVersion) = $out =~ /xcatconf4z version: (.*)/;
 | 
						|
    } else {
 | 
						|
        $rc = logResponse( 'DFS', 'VX01' );
 | 
						|
        goto FINISH_verifyXcatconf4z if ( $rc > 0 );
 | 
						|
    }
 | 
						|
 | 
						|
    # <todo> Verify that the node contains xcatconf4z in the correct location and is executable.
 | 
						|
    #$out = `ssh $nodeOrIP 'ls -al /opt/xcatconf4z 2>&1'`;
 | 
						|
    ($rc, $out) = sshToNode( $nodeOrIP, '', 'ls -al /opt/xcatconf4z 2>&1');
 | 
						|
    goto FINISH_verifyXcatconf4z if ( $rc == 255 );
 | 
						|
    if ( $out =~ /No such file or directory/ ) {
 | 
						|
        $rc = logResponse( 'DF', 'VX06' );
 | 
						|
        goto FINISH_verifyXcatconf4z if ( $rc > 0 );
 | 
						|
    } else {
 | 
						|
        # <todo> Verify that it is executable
 | 
						|
    }
 | 
						|
 | 
						|
    # Get the node's xcatconf4z version level.
 | 
						|
    #$out = `ssh $nodeOrIP '/opt/xcatconf4z version'`;
 | 
						|
    ($rc, $out) = sshToNode( $nodeOrIP, '', '/opt/xcatconf4z version');
 | 
						|
    goto FINISH_verifyXcatconf4z if ( $rc == 255 );
 | 
						|
    if ( $out =~ /xcatconf4z version: / ) {
 | 
						|
        chomp $out;
 | 
						|
        ($tgtVersion) = $out =~ /xcatconf4z version: (.*)/;
 | 
						|
    } else {
 | 
						|
        $rc = logResponse( 'DF', 'VX02' );
 | 
						|
        goto FINISH_verifyXcatconf4z if ( $rc > 0 );
 | 
						|
    }
 | 
						|
 | 
						|
    # Verify the version is up to date.
 | 
						|
    if ( defined $tgtVersion ) {
 | 
						|
        if ( $mnVersion > $tgtVersion ) {
 | 
						|
            $rc = logResponse( 'DF', 'VX03', ($tgtVersion, $mnVersion) );
 | 
						|
            goto FINISH_verifyXcatconf4z if ( $rc > 0 );
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    # Verify that authorized senders is setup.
 | 
						|
    #$out = `ssh $nodeOrIP '/opt/xcatconf4z status'`;
 | 
						|
    ($rc, $out) = sshToNode( $nodeOrIP, '', '/opt/xcatconf4z status');
 | 
						|
    goto verifyXcatconf4z if ( $rc == 255 );
 | 
						|
    if ( $out =~ /xcatconf4z is disabled / ) {
 | 
						|
        $rc = logResponse( 'DF', 'VX04' );
 | 
						|
        goto FINISH_verifyXcatconf4z if ( $rc > 0 );
 | 
						|
    } else {
 | 
						|
        # Get list of authorized users and put out an info message.
 | 
						|
    }
 | 
						|
 | 
						|
    # Verify that mkisofs is available
 | 
						|
    ($rc, $out) = sshToNode( $nodeOrIP, '', 'stat /opt/bin/mkisofs');
 | 
						|
    goto verifyXcatconf4z if ( $rc == 255 );
 | 
						|
    if ( $rc != 0 ) {
 | 
						|
        $rc = logResponse( 'DF', 'VX07' );
 | 
						|
        goto FINISH_verifyXcatconf4z if ( $rc > 0 );
 | 
						|
    }
 | 
						|
 | 
						|
FINISH_verifyXcatconf4z:
 | 
						|
    return $rc;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#*****************************************************************************
 | 
						|
# Main routine
 | 
						|
#*****************************************************************************
 | 
						|
my $ignoreOpt;
 | 
						|
my $rc = 0;
 | 
						|
my $thisScript = $0;
 | 
						|
my $out;
 | 
						|
 | 
						|
# Parse the arguments
 | 
						|
$Getopt::Long::ignorecase = 0;
 | 
						|
Getopt::Long::Configure( "bundling" );
 | 
						|
if (!GetOptions(
 | 
						|
         'a|access'        => \$verifyAccess,
 | 
						|
         'basicivp'        => \$runBasicIVP,
 | 
						|
         'capturereqs'     => \$verifyCaptureReqs,
 | 
						|
         'c|cloudinit'     => \$verifyCloudInit,
 | 
						|
         'comments=s'      => \$comments,
 | 
						|
         'cron'            => \$runCron,
 | 
						|
         'decode=s'        => \$decode,
 | 
						|
         'disable'         => \$disable,
 | 
						|
         'enable'          => \$enable,
 | 
						|
         'encode=s'        => \$encode,
 | 
						|
         'file=s'          => \$dataFile,
 | 
						|
         'fullivp'         => \$runFullIVP,
 | 
						|
         'h|help'          => \$displayHelp,
 | 
						|
         'i|id=s'          => \$id,
 | 
						|
         'ignore=s'        => \$ignoreOpt,
 | 
						|
         'cmdoveriucv=s'   => \$issueCmdOverIUCV,
 | 
						|
         'cmdtonode=s'     => \$issueCmdToNode,
 | 
						|
         'n|node=s'        => \$nodeName,
 | 
						|
         'notify'          => \$notifyOnErrorOrWarning,
 | 
						|
         'openstackuser=s' => \$openstackUser,
 | 
						|
         'openstackip=s'   => \$openstackIP,
 | 
						|
         'orchparms=s'     => \$orchParms,
 | 
						|
         'prepparms=s'     => \$prepParms,
 | 
						|
         'remove'          => \$remove,
 | 
						|
         'schedule=s'      => \$schedule,
 | 
						|
         'type=s'          => \$scheduledType,
 | 
						|
         'v|version'       => \$versionOpt,
 | 
						|
         'x|xcatconf4z'    => \$verifyXcatconf4z,
 | 
						|
         'zxcatparms=s'    => \$zxcatParms,
 | 
						|
      )) {
 | 
						|
    print $usage_string;
 | 
						|
}
 | 
						|
 | 
						|
if ( $versionOpt ) {
 | 
						|
    logResponse( 'DF', 'GENERIC_RESPONSE_NOINDENT', "Version: $version\n" );
 | 
						|
}
 | 
						|
 | 
						|
if ( $displayHelp ) {
 | 
						|
    showHelp();
 | 
						|
}
 | 
						|
 | 
						|
if ( $displayHelp or $versionOpt ) {
 | 
						|
    goto FINISH_main;
 | 
						|
}
 | 
						|
 | 
						|
# Convert any encoded operand values back to their unencoded value.
 | 
						|
my @convertibleParms = ( 'comments', 'nodeName', 'openstackUser', 'orchParms', 'prepParms', 'zxcatParms' );
 | 
						|
foreach my $parmName ( @convertibleParms ) {
 | 
						|
    eval( "\$$parmName = hexDecode( \$$parmName )" );
 | 
						|
}
 | 
						|
 | 
						|
if ( $schedule eq '' and $orchParms ne '' ) {
 | 
						|
    # If not scheduling an IVP run and orchestrator parms are present then use them.
 | 
						|
    my $unrecognizedOps = '';
 | 
						|
    $rc = GetOptionsFromString(
 | 
						|
        $orchParms,
 | 
						|
        'ignore=s'        => \$ignoreOpt,
 | 
						|
        );
 | 
						|
    if ( $rc == 0 ) {
 | 
						|
        print "Unrecognized option in --orchParms. ".
 | 
						|
              "Only --ignore is allowed as an orchestrator option for an immediate run.\n";
 | 
						|
        $rc = 2;
 | 
						|
        goto FINISH_main;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
# Handle messages to ignore.
 | 
						|
if ( defined( $ignoreOpt ) ) {
 | 
						|
    # Make hash from the specified ignore operands
 | 
						|
    $ignoreOpt = uc( $ignoreOpt );
 | 
						|
    my @ingoreList;
 | 
						|
    if ( $ignoreOpt =~ ',' ) {
 | 
						|
        @ingoreList = split( ',', $ignoreOpt );
 | 
						|
    } else {
 | 
						|
        @ingoreList = split( ' ', $ignoreOpt );
 | 
						|
    }
 | 
						|
 | 
						|
    %msgsToIgnore = map { $_ => 1 } @ingoreList;
 | 
						|
 | 
						|
    # Convert general severity type operands to their numeric value.
 | 
						|
    if ( $msgsToIgnore{'BYPASS'} ) {
 | 
						|
        delete $msgsToIgnore{'BYPASS'};
 | 
						|
        $msgsToIgnore{'2'} = 1;
 | 
						|
    }
 | 
						|
    if ( $msgsToIgnore{'INFO'} ) {
 | 
						|
        delete $msgsToIgnore{'INFO'};
 | 
						|
        $msgsToIgnore{'3'} = 1;
 | 
						|
    }
 | 
						|
    if ( $msgsToIgnore{'WARNING'} ) {
 | 
						|
        delete $msgsToIgnore{'WARNING'};
 | 
						|
        $msgsToIgnore{'4'} = 1;
 | 
						|
    }
 | 
						|
    if ( $msgsToIgnore{'ERROR'} ) {
 | 
						|
        delete $msgsToIgnore{'ERROR'};
 | 
						|
        $msgsToIgnore{'5'} = 1;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
if ( $openstackIP ne '' ) {
 | 
						|
    $openstackIP = uc( $openstackIP );
 | 
						|
}
 | 
						|
 | 
						|
# Handle the combinations of disable and enable options.
 | 
						|
if ( $disable eq '' ) {
 | 
						|
    $disable = 0;
 | 
						|
}
 | 
						|
if ( $enable eq '' ) {
 | 
						|
    $enable = 0;
 | 
						|
}
 | 
						|
if ( $disable == 1 and $enable == 1 ) {
 | 
						|
    $rc = logResponse( 'DFS', 'OPER03', '--disable and --enable' );
 | 
						|
    goto FINISH_main;
 | 
						|
}
 | 
						|
 | 
						|
if ( $runFullIVP or $runBasicIVP ) {
 | 
						|
    # Set up a log file for an IVP run.
 | 
						|
    setupLogFile();
 | 
						|
}
 | 
						|
 | 
						|
# Determine the information about the xCAT managed node and the z/VM
 | 
						|
# host environment where it is running (if running on z/VM).
 | 
						|
getMNInfo();
 | 
						|
 | 
						|
if ( $decode ne '' or
 | 
						|
     $disable or
 | 
						|
     $enable or
 | 
						|
     $encode ne '' or
 | 
						|
     $runFullIVP or
 | 
						|
     $runCron or
 | 
						|
     $runBasicIVP or
 | 
						|
     $remove or
 | 
						|
     $schedule ne '' ) {
 | 
						|
    # IVP runs do not need the node.
 | 
						|
} elsif ( $nodeName eq '' ) {
 | 
						|
    $rc = logResponse( 'DFS', 'OPER01', '-n or --node' );
 | 
						|
    goto FINISH_main;
 | 
						|
}
 | 
						|
 | 
						|
($::SUDOER, $::SUDO) = xCAT::zvmUtils->getSudoer();
 | 
						|
 | 
						|
# Setup for a test run of logResponse.  Normally, commented out.
 | 
						|
#($verifyAccess, $verifyCaptureReqs, $verifyCloudInit, $verifyXcatconf4z) = 0;
 | 
						|
#my $test = 1;
 | 
						|
 | 
						|
# Run the selected tests
 | 
						|
foreach my $verify (keys %verifySets) {
 | 
						|
    if ( eval $verify ) {
 | 
						|
        if ( $verifySets{$verify}[0] ne '' ) {
 | 
						|
            logResponse( 'D', 'GENERIC_RESPONSE_NOINDENT', "\n********************************************************************\n" );
 | 
						|
            logResponse( 'D', 'GENERIC_RESPONSE_NOINDENT', "$verifySets{$verify}[0]\n" );
 | 
						|
            logResponse( 'D', 'GENERIC_RESPONSE_NOINDENT', "********************************************************************\n" );
 | 
						|
        }
 | 
						|
        my $size = @{$verifySets{$verify}};
 | 
						|
        logResponse( 'D', '*RESET*' );
 | 
						|
        for (my $i = 1; $i < $size; $i++) {
 | 
						|
            ($rc) = eval $verifySets{$verify}[$i];
 | 
						|
            if ( ! defined $rc ) {
 | 
						|
                logResponse( 'DFS', 'PERL01', $thisScript, $verifySets{$verify}[$i], $@ );
 | 
						|
                $rc = 666;
 | 
						|
                last;
 | 
						|
            }
 | 
						|
 | 
						|
            if ( $rc > 0 ) {
 | 
						|
                last;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if ( $warnErrCnt == 0 ) {
 | 
						|
            logResponse( 'DF', 'GENERIC_RESPONSE_NOINDENT', "\nProcessing completed." );
 | 
						|
        } else {
 | 
						|
            logResponse( 'DF', 'GENERIC_RESPONSE_NOINDENT', "\nProcessing completed with warning or error messages. " .
 | 
						|
                "See previous messages for information.\n" );
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
FINISH_main:
 | 
						|
if ( $needToFinishLogFile ) {
 | 
						|
    # A log file was started.  We need to complete it by adding the summary
 | 
						|
    # section.  If necessary, we will send the log file to the notify user.
 | 
						|
    finishLogFile();
 | 
						|
}
 | 
						|
 | 
						|
exit $rc;
 |