# 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 \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 () { # 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; }