mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-11-03 21:02:34 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			307 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			307 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
# IBM(c) 2016 EPL license http://www.eclipse.org/legal/epl-v10.html
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head1
 | 
						|
 | 
						|
    xCAT plugin to support z/VM (s390x) diagnostics command
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
package xCAT_plugin::zvmdiagnostics;
 | 
						|
 | 
						|
#use xCAT::Client;
 | 
						|
use xCAT::zvmUtils;
 | 
						|
 | 
						|
#use xCAT::zvmCPUtils;
 | 
						|
#use xCAT::MsgUtils;
 | 
						|
use Sys::Hostname;
 | 
						|
 | 
						|
#use xCAT::Table;
 | 
						|
#use xCAT::Utils;
 | 
						|
#use xCAT::TableUtils;
 | 
						|
#use xCAT::ServiceNodeUtils;
 | 
						|
#use xCAT::NetworkUtils;
 | 
						|
#use XML::Simple;
 | 
						|
#use File::Basename;
 | 
						|
#use File::Copy;
 | 
						|
#use File::Path;
 | 
						|
#use File::Temp;
 | 
						|
use Time::HiRes;
 | 
						|
use POSIX;
 | 
						|
use Getopt::Long;
 | 
						|
use strict;
 | 
						|
use warnings;
 | 
						|
 | 
						|
#use Cwd;
 | 
						|
# Set $DEBUGGING = 1 to get extra message logging
 | 
						|
my $DEBUGGING = 0;
 | 
						|
 | 
						|
# Common prefix for log messages
 | 
						|
my $ROUTINE = "zvmdiagnostics";
 | 
						|
my $COMMAND = "diagnostics";
 | 
						|
 | 
						|
my $NOTIFY_FILENAME = "/var/lib/sspmod/appliance_system_role";
 | 
						|
my $NOTIFY_KEYWORD = "notify";
 | 
						|
my $NOTIFY_KEYWORD_DELIMITER = "=";
 | 
						|
 | 
						|
# If the following line ("1;") is not included, you get:
 | 
						|
# /opt/xcat/lib/perl/xCAT_plugin/... did not return a true value
 | 
						|
# where ... is the name of this file
 | 
						|
1;
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  handled_commands
 | 
						|
 | 
						|
    Return list of commands handled by this plugin
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub handled_commands {
 | 
						|
    return { $COMMAND => $ROUTINE, };
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  preprocess_request
 | 
						|
 | 
						|
    Check and setup for hierarchy
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub preprocess_request {
 | 
						|
    my $req      = shift;
 | 
						|
    my $callback = shift;
 | 
						|
    my $SUBROUTINE = "preprocess_request";
 | 
						|
 | 
						|
    # Hash array
 | 
						|
    my %sn;
 | 
						|
 | 
						|
    # Scalar variable
 | 
						|
    my $sn;
 | 
						|
 | 
						|
    # Array
 | 
						|
    my @requests;
 | 
						|
 | 
						|
    if ( $DEBUGGING == 1 ) {
 | 
						|
        xCAT::zvmUtils->printSyslog("$ROUTINE $SUBROUTINE entry");
 | 
						|
    }
 | 
						|
 | 
						|
    # If already preprocessed, go straight to request
 | 
						|
    if ( $req->{_xcatpreprocessed}->[0] == 1 ) {
 | 
						|
        return [$req];
 | 
						|
    }
 | 
						|
    my $nodes   = $req->{node};
 | 
						|
    my $service = "xcat";
 | 
						|
 | 
						|
    # Find service nodes for requested nodes
 | 
						|
    # Build an individual request for each service node
 | 
						|
    if ($nodes) {
 | 
						|
        $sn = xCAT::ServiceNodeUtils->get_ServiceNode( $nodes, $service, "MN" );
 | 
						|
 | 
						|
        # Build each request for each service node
 | 
						|
        foreach my $snkey ( keys %$sn ) {
 | 
						|
            my $n = $sn->{$snkey};
 | 
						|
            print "snkey=$snkey, nodes=@$n\n";
 | 
						|
            my $reqcopy = {%$req};
 | 
						|
            $reqcopy->{node}                   = $sn->{$snkey};
 | 
						|
            $reqcopy->{'_xcatdest'}            = $snkey;
 | 
						|
            $reqcopy->{_xcatpreprocessed}->[0] = 1;
 | 
						|
            push @requests, $reqcopy;
 | 
						|
        }
 | 
						|
 | 
						|
        return \@requests;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
 | 
						|
        # Input error
 | 
						|
        my %rsp;
 | 
						|
        my $rsp;
 | 
						|
        $rsp->{data}->[0] =
 | 
						|
          "Input noderange missing. Usage: $ROUTINE <noderange> \n";
 | 
						|
        xCAT::MsgUtils->message( "I", $rsp, $callback, 0 );
 | 
						|
        return 1;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  process_request
 | 
						|
 | 
						|
    Process the command.  This is the main call.
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub process_request {
 | 
						|
    my $SUBROUTINE = "process_request";
 | 
						|
    my $request  = shift;
 | 
						|
    my $callback = shift;
 | 
						|
    my $nodes    = $request->{node};
 | 
						|
    my $command  = $request->{command}->[0];
 | 
						|
    my $args     = $request->{arg};
 | 
						|
    my $envs     = $request->{env};
 | 
						|
    $::STDIN = $request->{stdin}->[0];
 | 
						|
    my %rsp;
 | 
						|
    my $rsp;
 | 
						|
    my @nodes = @$nodes;
 | 
						|
    my $host  = hostname();
 | 
						|
 | 
						|
    if ( $DEBUGGING == 1 ) {
 | 
						|
        xCAT::zvmUtils->printSyslog("$ROUTINE $SUBROUTINE entry");
 | 
						|
    }
 | 
						|
 | 
						|
    # Process ID for xfork()
 | 
						|
    my $pid;
 | 
						|
 | 
						|
    # Child process IDs
 | 
						|
    my @children = ();
 | 
						|
 | 
						|
    #*** Collect or manage diagnostics***
 | 
						|
    if ( $command eq $COMMAND ) {
 | 
						|
        foreach (@nodes) {
 | 
						|
            $pid = xCAT::Utils->xfork();
 | 
						|
 | 
						|
            # Parent process
 | 
						|
            if ($pid) {
 | 
						|
                push( @children, $pid );
 | 
						|
            }
 | 
						|
 | 
						|
            # Child process
 | 
						|
            elsif ( $pid == 0 ) {
 | 
						|
                if ( xCAT::zvmUtils->isHypervisor($_) ) {
 | 
						|
                    #TODO should this be handled inside the subroutine, ala rmvm?
 | 
						|
                    if ( $DEBUGGING == 1 ) {
 | 
						|
                          xCAT::zvmUtils->printSyslog("$ROUTINE for hypervisor - semantically coherent?");
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                else {
 | 
						|
                    collectDiags( $callback, $_, $args );
 | 
						|
                }
 | 
						|
 | 
						|
                # Exit process
 | 
						|
                exit(0);
 | 
						|
            }
 | 
						|
            else {
 | 
						|
 | 
						|
                # Ran out of resources
 | 
						|
                die "Error: Could not fork\n";
 | 
						|
            }
 | 
						|
 | 
						|
        }    # End of foreach
 | 
						|
    }    # End of case
 | 
						|
 | 
						|
    # Wait for all processes to end
 | 
						|
    foreach (@children) {
 | 
						|
        waitpid( $_, 0 );
 | 
						|
    }
 | 
						|
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  collectDiags
 | 
						|
 | 
						|
    Description  : Collect diagnostics
 | 
						|
    Arguments    : Node to collect diagnostics about
 | 
						|
    Returns      : Nothing
 | 
						|
    Example      : collectDiags($callback, $node);
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub collectDiags {
 | 
						|
    my $SUBROUTINE = "collectDiags";
 | 
						|
 | 
						|
    # Get inputs
 | 
						|
    my ( $callback, $node, $args ) = @_;
 | 
						|
    my $rc;
 | 
						|
 | 
						|
    if ( $DEBUGGING == 1 ) {
 | 
						|
          xCAT::zvmUtils->printSyslog("$ROUTINE $SUBROUTINE entry");
 | 
						|
    }
 | 
						|
 | 
						|
    # Get node properties from 'zvm' table
 | 
						|
    my @propNames = ( 'hcp', 'userid', 'discovered' );
 | 
						|
    my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $node, @propNames );
 | 
						|
 | 
						|
    # Get zHCP
 | 
						|
    my $hcp = $propVals->{'hcp'};
 | 
						|
    if ( !$hcp ) {
 | 
						|
        xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing node HCP" );
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    # Get node user ID
 | 
						|
    my $userId = $propVals->{'userid'};
 | 
						|
    if ( !$userId ) {
 | 
						|
        xCAT::zvmUtils->printLn( $callback, "$node: (Error) Missing user ID" );
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    # Capitalize user ID
 | 
						|
    $userId =~ tr/a-z/A-Z/;
 | 
						|
 | 
						|
    if ( $DEBUGGING == 1 ) {
 | 
						|
        xCAT::zvmUtils->printSyslog("$ROUTINE $SUBROUTINE sudoer:$::SUDOER zHCP:$hcp sudo:$::SUDO userid:$::userId");
 | 
						|
    }
 | 
						|
    my $out;
 | 
						|
 | 
						|
    my $requestId   = "NoUpstreamRequestID";
 | 
						|
    my $objectId    = "NoUpstreamObjectID";
 | 
						|
    my $projectName = "NoUpstreamProjectName";
 | 
						|
    my $userUuid    = "NoUpstreamUserUuid";
 | 
						|
    if ($args) {
 | 
						|
        @ARGV = @$args;
 | 
						|
        xCAT::zvmUtils->printSyslog(
 | 
						|
            "$ROUTINE $SUBROUTINE for node:$node on zhcp:$hcp args @$args");
 | 
						|
 | 
						|
        # Parse options
 | 
						|
        GetOptions(
 | 
						|
            'requestid=s' => \$requestId    # Optional
 | 
						|
            , 'objectid=s' => \$objectId    # Optional
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    my $xcatnotify = "OPERATOR";  # Default value
 | 
						|
    my $xcatnotify_found = 0;     # Not found yet
 | 
						|
    my (@array, $varname);
 | 
						|
    open( FILE, "<$NOTIFY_FILENAME" );
 | 
						|
    #TODO If file not found ("should never happen"), log error but continue
 | 
						|
    while (<FILE>) {
 | 
						|
        # Find record in file with NOTIFY=something on it, optionally delimited with whitespace
 | 
						|
        next unless ( /^[\s]*$NOTIFY_KEYWORD[\s]*$NOTIFY_KEYWORD_DELIMITER[\s]*(\S+)[\s]*$/i );
 | 
						|
        $xcatnotify_found = 1;
 | 
						|
        $xcatnotify = $1;  # First parenthesized expression in regex above, that is: \S+
 | 
						|
        if ( $DEBUGGING == 1 ) {
 | 
						|
            xCAT::zvmUtils->printSyslog("$ROUTINE $SUBROUTINE xCAT will notify $xcatnotify.");
 | 
						|
        }
 | 
						|
        last; # Ignore anything past the first matching record.  Absent a bug elsewhere, there is only one value to find.
 | 
						|
    }
 | 
						|
    close(FILE);
 | 
						|
    if (not $xcatnotify_found) {
 | 
						|
        xCAT::zvmUtils->printSyslog(
 | 
						|
            "$ROUTINE $SUBROUTINE error: failed to parse $NOTIFY_KEYWORD$NOTIFY_KEYWORD_DELIMITER " .
 | 
						|
            "from $NOTIFY_FILENAME, defaulting to notify $xcatnotify");
 | 
						|
    }
 | 
						|
    #TODO add COZ... message ID
 | 
						|
    my $msg = "vmcp MSG $xcatnotify deployment failed: node $node userid $userId on zHCP $hcp";
 | 
						|
    xCAT::zvmUtils->printSyslog("$ROUTINE $SUBROUTINE $msg");
 | 
						|
    system($msg);
 | 
						|
    #TODO check system()'s rc
 | 
						|
 | 
						|
    #TODO Capture diagnostic files
 | 
						|
 | 
						|
    xCAT::zvmUtils->printSyslog("$ROUTINE $SUBROUTINE ... rest of implementation stubbed out ");
 | 
						|
 | 
						|
    if ( $DEBUGGING == 1 ) {
 | 
						|
        xCAT::zvmUtils->printSyslog("$ROUTINE $SUBROUTINE exit");
 | 
						|
    }
 | 
						|
    return;
 | 
						|
}
 | 
						|
 |