mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-10-31 11:22:27 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			159 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			159 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
| # IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
 | |
| 
 | |
| #This contains functions common to most plugins
 | |
| 
 | |
| package xCAT::Common;
 | |
| 
 | |
| use File::stat;
 | |
| use File::Copy;
 | |
| use xCAT::Usage;
 | |
| use Thread qw/yield/;
 | |
| use Storable qw/store_fd fd_retrieve/;
 | |
| 
 | |
| BEGIN
 | |
| {
 | |
|     $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
 | |
| }
 | |
| 
 | |
| 
 | |
| # forward_data is a function used to aggregate output passed up from a set of
 | |
| # children.  This is commonly used due to make absolutely certain multiple
 | |
| # writers trying to use a common file descriptor wouldn't corrupt each other.
 | |
| # So instead, each child is given a dedicated filehandle and the parent
 | |
| # uses this function to organize child data and send it up.
 | |
| # locking might be a more straightforward approach, but locking experiments
 | |
| # weren't as successful.
 | |
| sub forward_data {
 | |
|     my $callback  = shift;
 | |
|     my $fds       = shift;
 | |
|     my @ready_fds = $fds->can_read(1);
 | |
|     my $rfh;
 | |
|     my $rc = @ready_fds;
 | |
|     foreach $rfh (@ready_fds) {
 | |
|         my $responses;
 | |
|         eval {
 | |
|             $responses = fd_retrieve($rfh);
 | |
|         };
 | |
|         if ($@ and $@ =~ /^Magic number checking on storable file/) { #this most likely means we ran over the end of available input
 | |
|             $fds->remove($rfh);
 | |
|             close($rfh);
 | |
|         } else {
 | |
|             eval { print $rfh "ACK\n"; }; #Ignore ack loss due to child giving up and exiting, we don't actually explicitly care about the acks
 | |
|             foreach (@$responses) {
 | |
|                 $callback->($_);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     yield();    #Try to avoid useless iterations as much as possible
 | |
|     return $rc;
 | |
| }
 | |
| 
 | |
| #This function pairs with the above.
 | |
| #It either accepts pre-structured responses or the common ':' delimeted description/value pairs
 | |
| #for example:
 | |
| #  send_data('n1',"Temperature: cold","Voltage: normal"); #report normal text, two pieces of data
 | |
| #  send_data('n1',[1,"Timeout communicationg with foobar]); #Report an error with a code
 | |
| #  send_data({<custom response packet>},{<other custome response>});
 | |
| sub send_data {
 | |
|     my $node;
 | |
|     if (not ref $_[0]) {
 | |
|         $node = shift;
 | |
|     }
 | |
|     foreach (@_) {
 | |
|         my %output;
 | |
|         if (ref($_) eq HASH) {
 | |
|             store_fd([$_], $out);
 | |
|             yield();
 | |
|             waitforack($out);
 | |
|             next;
 | |
|         }
 | |
|         my $line;
 | |
|         my $rc;
 | |
|         if (ref($_) eq ARRAY) {
 | |
|             $rc   = $_->[0];
 | |
|             $line = $_->[1];
 | |
|         } else {
 | |
|             $line = $_;
 | |
|         }
 | |
| 
 | |
| 
 | |
|         (my $desc, my $text) = split(/:/, $line, 2);
 | |
|         unless ($text) {
 | |
|             $text = $desc;
 | |
|         } else {
 | |
|             $desc =~ s/^\s+//;
 | |
|             $desc =~ s/\s+$//;
 | |
|             if ($desc) {
 | |
|                 $output{node}->[0]->{data}->[0]->{desc}->[0] = $desc;
 | |
|             }
 | |
|         }
 | |
|         $text =~ s/^\s+//;
 | |
|         $text =~ s/\s+$//;
 | |
|         $output{node}->[0]->{name}->[0] = $node;
 | |
|         if ($rc) {
 | |
|             $output{node}->[0]->{errorcode} = $rc;
 | |
|             $output{node}->[0]->{error}->[0]->{contents}->[0] = $text;
 | |
|         } else {
 | |
|             $output{node}->[0]->{data}->[0]->{contents}->[0] = $text;
 | |
|         }
 | |
|         store_fd([ \%output ], $out);
 | |
|         yield();
 | |
|         waitforack($out);
 | |
|     }
 | |
| }
 | |
| 
 | |
| #This function is intended to be used to process a request through the usage
 | |
| #module.
 | |
| sub usage_noderange {
 | |
|     my $request  = shift;
 | |
|     my $callback = shift;
 | |
| 
 | |
|     #display usage statement if -h is present or no noderage is specified
 | |
|     my $noderange = $request->{node};           #Should be arrayref
 | |
|     my $command   = $request->{command}->[0];
 | |
|     my $extrargs  = $request->{arg};
 | |
|     my @exargs    = ($request->{arg});
 | |
|     if (ref($extrargs)) {
 | |
|         @exargs = @$extrargs;
 | |
|     }
 | |
| 
 | |
|     my $usage_string = xCAT::Usage->parseCommand($command, @exargs);
 | |
|     if ($usage_string) {
 | |
|         $callback->({ data => $usage_string });
 | |
|         $request = {};
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     if (!$noderange) {
 | |
|         $usage_string = "Missing Noderange\n";
 | |
|         $usage_string .= xCAT::Usage->getUsage($command);
 | |
|         $callback->({ error => [$usage_string], errorcode => [1] });
 | |
|         $request = {};
 | |
|         return;
 | |
|     }
 | |
| }
 | |
| 
 | |
| # copy, overwriting only if the source file is newer
 | |
| sub copy_if_newer {
 | |
|     my ($source, $dest) = @_;
 | |
| 
 | |
|     die "ERROR: source file doesn't exist\n" unless (-e $source);
 | |
| 
 | |
|     # resolve destination path
 | |
|     if ($dest =~ m/\/$/ || -d $dest) {
 | |
|         $dest .= '/' if ($dest !~ m/\/$/);
 | |
|         $dest .= $1  if $source =~ m/([^\/]+)$/;
 | |
|     }
 | |
| 
 | |
|     if (-e $dest) {
 | |
|         my $smtime = stat($source)->mtime;
 | |
|         my $dmtime = stat($dest)->mtime;
 | |
| 
 | |
|         return if ($smtime < $dmtime);
 | |
|     }
 | |
| 
 | |
|     copy($source, $dest);
 | |
| }
 | |
| 
 | |
| 1;
 |