diff --git a/perl-xCAT/xCAT/Client.pm b/perl-xCAT/xCAT/Client.pm deleted file mode 100644 index e0934796d..000000000 --- a/perl-xCAT/xCAT/Client.pm +++ /dev/null @@ -1,1254 +0,0 @@ -#!/usr/bin/env perl -# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html -package xCAT::Client; -BEGIN -{ - $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : -d '/opt/xcat' ? '/opt/xcat' : '/usr'; -} - -# if AIX - make sure we include perl 5.8.2 in INC path. -# Needed to find perl dependencies shipped in deps tarball. -use Storable qw/nstore_fd fd_retrieve/; -if ($^O =~ /^aix/i) { - unshift(@INC, qw(/usr/opt/perl5/lib/5.8.2/aix-thread-multi /usr/opt/perl5/lib/5.8.2 /usr/opt/perl5/lib/site_perl/5.8.2/aix-thread-multi /usr/opt/perl5/lib/site_perl/5.8.2)); -} -use IO::Handle; - -my $inet6support; -if ($^O =~ /^aix/i) { # disable AIX IPV6 TODO fix - $inet6support = 0; -} else { - $inet6support=eval { require Socket6; 1; }; -} -if ($inet6support) { - $inet6support = eval { require IO::Socket::INET6; 1; }; -} -if ($inet6support) { - $inet6support = eval { require IO::Socket::SSL; IO::Socket::SSL->import('inet6'); 1;}; -} - -if ($^O =~ /^linux/i) { - # Is IPv6 enabled on the MN or xcat client node at all? - my $ipv6enabled = `ip addr | grep inet6`; - if (!$ipv6enabled) { - $inet6support = 0; - } -} - -unless ($inet6support) { - eval { require Socket }; - eval { require IO::Socket::INET }; - eval { require IO::Socket::SSL; IO::Socket::SSL->import('inet4') }; -} - - -use XML::Simple; #smaller than libxml.... -use Fcntl; -use POSIX qw/:errno_h/; -use IO::Select; -$XML::Simple::PREFERRED_PARSER='XML::Parser'; -#require Data::Dumper; -my $xcathost='localhost:3001'; -my $plugins_dir; -my %resps; -my $EXITCODE; # save the bitmask of all exit codes returned by calls to handle_response() -1; - - -sub rspclean { - my $response = shift; - my $callback = shift; - my $rsps = XMLin($response,SuppressEmpty=>undef,ForceArray=>1); - foreach my $rsp (@{$rsps->{xcatresponse}}) { - #add ESC back - foreach my $key (keys %$rsp) { - if (ref($rsp->{$key}) eq 'ARRAY') { - foreach my $text (@{$rsp->{$key}}) { - next unless defined $text; - $text =~ s/xxxxESCxxxx/\e/g; - } - } - else { - $rsp->{$key} =~ s/xxxxESCxxxx/\e/g; - } - } - $callback->($rsp); - if ($rsp->{serverdone}) { - return 1; - } - } - return 0; -} -sub send_request { - my $request = shift; - my $sock = shift; - my $encode = shift; - if ($encode eq "xml") { - my $msg=XMLout($request,RootName=>'xcatrequest',NoAttr=>1,KeyAttr=>[]); - if ($ENV{XCATXMLTRACE}) { print $msg; } - if($ENV{XCATXMLWARNING}) { - validateXML($msg); - } - print $sock $msg; - $sock->flush(); - } else { - nstore_fd($request,$sock); - $sock->flush(); - } -} -################################# -# submit_request will take an xCAT command and pass it to the xCAT -# server for execution. -# Note must not put a require or use for Utils.pm in the non-bypass path -# -# If the XCATBYPASS env var is set, the connection to the server/daemon -# will be bypassed and the plugin will be called directly. If it is -# set to one or more directories (separated by ":"), all perl modules -# in those directories will be loaded in as plugins (for duplicate -# commands, last one in wins). If it is set to any other value -# (e.g. "yes", "default", whatever string you want) the default plugin -# directory /opt/xcat/lib/perl/xCAT_plugin will be used. -# -# Input: -# Request hash - A hash ref containing the input command and args to be -# passed to the plugin. The the xcatd daemon (or this routine when -# XCATBYPASS) reads the {noderange} entry and builds a flattened array -# of nodes that gets added as request->{node} -# The format for the request hash is: -# { command => [ 'xcatcmd' ], -# noderange => [ 'noderange_string' ], -# arg => [ 'arg1', 'arg2', '...', 'argn' ] -# } -# Callback - A subroutine ref that will be called to process the output -# from the plugin. -# -# NOTE: The request hash will get converted to XML when passed to the -# xcatd daemon, and will get converted back to a hash before being -# passed to the plugin. The XMLin ForceArray option is used to -# force all XML constructs to be arrays so that the plugin code -# and callback routines can access the data consistently. -# The input request and the response hash created by the plugin should -# always create hashes with array values. -################################# -sub submit_request { - my $request = shift; - my $callback = shift; - my $keyfile = shift; - my $certfile = shift; - my $cafile = shift; - # get home directory - my @user = getpwuid($>); - my $homedir=$user[7]; - unless ($keyfile) { $keyfile = $homedir."/.xcat/client-cred.pem"; } - unless ($certfile) { $certfile = $homedir."/.xcat/client-cred.pem"; } - unless ($cafile) { $cafile = $homedir."/.xcat/ca.pem"; } - $xCAT::Client::EXITCODE = 0; # clear out exit code before invoking the plugin -if (ref($request) eq 'HASH') { # the request is an array, not pure XML - $request->{clienttype}->[0] = "cli"; # setup clienttype for auditlog -} -# If XCATBYPASS is set, invoke the plugin process_request method directly -# without going through the socket connection to the xcatd daemon - if ($ENV{XCATBYPASS}) { - #add current userid to the request - if (ref($request) eq 'HASH') { # the request is an array, not pure XML - if (!(defined($request->{username}))) { - $request->{username}->[0] = getpwuid($>); - } - - # only allow root to run - unless ($request->{username}->[0] =~ /root/) { - print ("WARNING: Only allow root to run XCATBYPASS mode, your current user ID is $request->{username}->[0].\n"); - return 0; - } - } - # Load plugins from either specified or default dir - require xCAT::Table; - my %cmd_handlers; - my @plugins_dirs = split('\:',$ENV{XCATBYPASS}); - if (-d $plugins_dirs[0]) { - foreach (@plugins_dirs) { - $plugins_dir = $_; - scan_plugins(); - } - } else { - # figure out default plugins dir - #my $sitetab=xCAT::Table->new('site'); - #unless ($sitetab) { - # print ("ERROR: Unable to open basic site table for configuration\n"); - #} - $plugins_dir=$::XCATROOT.'/lib/perl/xCAT_plugin'; - scan_plugins(); - } - - populate_site_hash(); - - # don't do XML transformation -- assume request is well-formed - # my $xmlreq=XMLout($request,RootName=>xcatrequest,NoAttr=>1,KeyAttr=>[]); - # $request = XMLin($xmlreq,SuppressEmpty=>undef,ForceArray=>1) ; - - - # Call the plugin directly - # ${"xCAT_plugin::".$modname."::"}{process_request}->($request,$callback); - plugin_command($request,undef,$callback); - return 0; - } - -# No XCATBYPASS, so establish a socket connection with the xcatd daemon -# and submit the request - if ($ENV{XCATHOST}) { - $xcathost=$ENV{XCATHOST}; - } - my %connargs=(); - if ($xcathost =~ s/%([^\]|:]*)//) { - $connargs{PeerScope} = $1; - } - $connargs{PeerAddr} = $xcathost; - $connargs{Timeout} = 15; - if ($connargs{PeerScope} and $connargs{PeerScope} =~ /[a-zA-Z]/) { #non-numeric, need to translate... - my @ipdata = `ip link`; - @ipdata = grep(/[^@]$connargs{PeerScope}(:|@)/,@ipdata); - if (scalar(@ipdata) != 1) { - print STDERR "Unable to identify scope ".$connargs{PeerScope}."\n"; - exit(1); - } - $connargs{PeerScope} = $ipdata[0]; - $connargs{PeerScope} =~ s/:.*//; - } - - - my $pclient; - if ($inet6support) { - $pclient = IO::Socket::INET6->new( - %connargs, - ); - } else { - $pclient = IO::Socket::INET->new( - PeerAddr => $xcathost, - Timeout => 15, - ); - } - unless ($pclient) { - print "Unable to open socket connection to xcatd daemon on $xcathost.\n"; - print "Verify that the xcatd daemon is running and that your SSL setup is correct.\n"; - if ($@ =~ /SSL Timeout/) { - die "Connection failure: SSL Timeout or incorrect certificates in ~/.xcat"; - } else { - die "Connection failure: $@" - } - } - my $client; - if (-r $keyfile and -r $certfile and -r $cafile) { - $client = IO::Socket::SSL->start_SSL($pclient, - SSL_key_file => $keyfile, - SSL_cert_file => $certfile, - SSL_ca_file => $cafile, - SSL_use_cert => 1, - Timeout => 0, - ); - } else { - $client = IO::Socket::SSL->start_SSL($pclient, - Timeout => 0, - ); - } - unless ($client) { - print "Unable to open socket connection to xcatd daemon on $xcathost.\n"; - print "Verify that the xcatd daemon is running and that your SSL setup is correct.\n"; - if ($@ =~ /SSL Timeout/) { - die "Connection failure: SSL Timeout or incorrect certificates in ~/.xcat"; - } else { - die "Connection failure: $@" - } - } - - my $msg; - my $encode = "xml"; - #storable encoding is unsafe, carry on with the unsafe xml scheme - #perhaps one day will support faster schemes - #my $encode = "storable"; - #my $straightprint=0; - #if ($ENV{XCATXMLTRACE} or $ENV{XCATXMLWARNING}) { $encode="xml"; } - if (ref($request) eq 'HASH') { # the request is an array, not pure XML - #print $client "xcatencoding: $encode\n"; - #my $encok=<$client>; - send_request($request,$client,$encode); - } else { #XML - $straightprint=1; - $msg=$request; - print $client $msg; - } - $SIG{TERM} = $SIG{INT} = sub { send_request({abortcommand=>[1]},$client,$encode); exit 0; }; - my $response; - my $rsp; - my $cleanexit=0; - if ($encode eq 'xml') { - my $massresponse=""; - my $nextcoalescetime=time()+1; - my $coalescenow=0; - my $flags=fcntl($client,F_GETFL,0); - $flags |= O_NONBLOCK; #select can be a bit.. fickle, make sysread work more easily... - fcntl($client,F_SETFL,$flags); - my $clientsel = new IO::Select; - $clientsel->add($client); - my $line; - my $newdata=0; - while (1) { - my $shouldexit; - if ($newdata and ($coalescenow or time() > $nextcoalescetime)) { - $coalescenow=0; - $newdata=0; - $nextcoalescetime=time()+1; - $massresponse .= ""; - $shouldexit = rspclean($massresponse,$callback); - $massresponse=""; - } - - if ($shouldexit) { - $cleanexit=1; - last; - } - $line = ""; - $clientsel->can_read(0.5); - my $readbytes; - do { $readbytes=sysread($client,$line,65535,length($line)); } while ($readbytes); - unless (length($line)) { - if (not defined $readbytes and $! == EAGAIN) { next; } - last; - } - $newdata=1; - $response .= $line; - if ($line =~ m/<\/xcatresponse>\s*\z/) { - if ($line =~ /serverdone/) { $coalescenow=1; } #if serverdone was detected, hint at coalesce code to flush things out now - #this means that coalesce can be triggered by stray words in the output prematurely, but that's harmless - #replace ESC with xxxxESCxxx because XMLin cannot handle it - $response =~ s/\e/xxxxESCxxxx/g; - - if ($ENV{XCATXMLTRACE}) { print $response; } - $massresponse.=$response; - $response=''; - if($ENV{XCATXMLWARNING}) { - validateXML($response); - } - } - } - if (not $cleanexit and $massresponse ne "") { - $massresponse .= ""; - $cleanexit = rspclean($massresponse,$callback); - } - } else { #storable encode - my $rsp; - eval { $rsp = fd_retrieve($client); }; - SERVERINPUT: while ($rsp) { - my @rsps; - if (ref $rsp eq 'ARRAY') { - @rsps = @$rsp; - } else { - @rsps = ($rsp); - } - foreach (@rsps) { - $callback->($_); - if ($_->{serverdone}) { - $cleanexit=1; - last SERVERINPUT; - } - } - $rsp = undef; - eval { $rsp = fd_retrieve($client); }; - } - } - $massresponse=""; - unless ($cleanexit) { - print STDERR "ERROR/WARNING: communication with the xCAT server seems to have been ended prematurely\n"; - $xCAT::Client::EXITCODE = 1; - } - -sub validateXML { - my $xml = shift; - my @lines = split /\n/, $xml; - my $invalidNewline = 0; - my $contentsColon = 0; - my $contentsLine; - - foreach (@lines) { - if(!$invalidNewline) { - if( ($_ =~ // && $_ !~ /<\/contents>/) || - ($_ =~ // && $_ !~ /<\/desc>/)) { - $invalidNewline = 1; - print "Possible invalid XML using newlines found: \n$xml\n"; - } - } - if($_ =~ /.+:.+<\/contents>/) { - $contentsColon = 1; - $contentsLine = $_; - } - if($_ =~ /.+<\/desc>/) { - $contentsColon = 0; - } - if($contentsColon && $_ =~ /<\/desc>/) { - print "Possible invalid XML found(data contents using colon and blank description): \n$contentsLine\n$_\n"; - $contentsColon = 0; - } - } -} - -################################### -# scan_plugins -# will load all plugin perl modules and build a list of supported -# commands -# -# NOTE: This is copied from xcatd (last merge 11/23/09). -# TODO: Will eventually move to using common source.... -################################### -sub scan_plugins { - my @plugins=glob($plugins_dir."/*.pm"); - foreach (@plugins) { - /.*\/([^\/]*).pm$/; - my $modname = $1; - unless ( eval { require "$_" }) { -# xCAT::MsgUtils->message("S","Error loading module ".$_." ...skipping"); - print "Error loading module $_ ...skipping\n"; - next; - } - no strict 'refs'; - my $cmd_adds=${"xCAT_plugin::".$modname."::"}{handled_commands}->(); - foreach (keys %$cmd_adds) { - my $value = $_; - if (defined($cmd_handlers{$_})) { - push @{$cmd_handlers{$_}},[$modname,$cmd_adds->{$_}]; - } else { - $cmd_handlers{$_} = [ [$modname,$cmd_adds->{$_}] ]; - } - } - } - foreach (@plugins) { - no strict 'refs'; - /.*\/([^\/]*).pm$/; - my $modname = $1; - unless (defined(${"xCAT_plugin::".$modname."::"}{init_plugin})) { - next; - } - ${"xCAT_plugin::".$modname."::"}{init_plugin}->(\&do_request); - } -} - - - - -################################### -# plugin_command -# will invoke the correct plugin -# -# NOTE: This is copied from xcatd (last merge 11/23/09). -# TODO: Will eventually move to using common source.... -################################### -sub plugin_command { - my $req = shift; - my $sock = shift; - my $callback = shift; - my %handler_hash; - my $usesiteglobal = 0; - # We require these only in bypass mode to reduce start up time for the normal case - #use lib "$::XCATROOT/lib/perl"; - #use xCAT::NodeRange; - require lib; - lib->import("$::XCATROOT/lib/perl"); - require xCAT::NodeRange; - require xCAT::Table; - - $Main::resps={}; - my $xmlreq; - if (ref($req) ne 'HASH') { # the request XML, get an array - $xmlreq=$req; # save the original XML - $req = XMLin($xmlreq,SuppressEmpty=>undef,ForceArray=>1) ; - - } - my @nodes; - if ($req->{node}) { - @nodes = @{$req->{node}}; - } elsif ($req->{noderange} and $req->{noderange}->[0]) { - @nodes = xCAT::NodeRange::noderange($req->{noderange}->[0]); - if (xCAT::NodeRange::nodesmissed()) { -# my $rsp = {errorcode=>1,error=>"Invalid nodes in noderange:".join(',',xCAT::NodeRange::nodesmissed)}; -# my $rsp->{serverdone} = {}; - print "Invalid nodes in noderange:".join(',',xCAT::NodeRange::nodesmissed())."\n"; -# if ($sock) { -# print $sock XMLout($rsp,RootName=>'xcatresponse' ,NoAttr=>1); -# } -# return ($rsp); - return 1; - } - unless (@nodes) { - $req->{emptynoderange} = [1]; - } - } - if (@nodes) { $req->{node} = \@nodes; } - my %unhandled_nodes; - foreach (@nodes) { - $unhandled_nodes{$_}=1; - } - my $useunhandled=0; - if (defined($cmd_handlers{$req->{command}->[0]})) { - my $hdlspec; - my @globalhandlers=(); - my $useglobals=1; #If it stays 1, then use globals normally, if 0, use only for 'unhandled_nodes, if -1, don't do at all - foreach (@{$cmd_handlers{$req->{command}->[0]}}) { - $hdlspec =$_->[1]; - my $ownmod = $_->[0]; - if ($hdlspec =~ /^site:/) { #A site entry specifies a plugin - my $sitekey = $hdlspec; - $sitekey =~ s/^site://; - #$sitetab = xCAT::Table->new('site'); - #my $sent = $sitetab->getAttribs({key=>$sitekey},['value']); - #if ($sent and $sent->{value}) { #A site style plugin specification is just like - if ($::XCATSITEVALS{$sitekey}) { #A site style plugin specification is just like - #a static global, it grabs all nodes rather than some - $useglobals = -1; #If they tried to specify anything, don't use the default global handlers at all - unless (@nodes) { - $handler_hash{$::XCATSITEVALS{$sitekey}} = 1; - $usesiteglobal = 1; - } - foreach (@nodes) { #Specified a specific plugin, not a table lookup - $handler_hash{$::XCATSITEVALS{$sitekey}}->{$_} = 1; - } - } - } elsif ($hdlspec =~ /:/) { #Specificed a table lookup path for plugin name - if (@nodes) { # only use table lookup plugin if nodelist exists - # Usage will be handled in common AAAhelp plugin - - $useglobals = 0; #Only contemplate nodes that aren't caught through searching below in the global handler - $useunhandled=1; - my $table; - my $cols; - ($table,$cols) = split(/:/,$hdlspec); - my @colmns=split(/,/,$cols); - my @columns; - my $hdlrtable=xCAT::Table->new($table); - unless ($hdlrtable) { - #TODO: proper error handling - } - my $node; - my $colvals = {}; - foreach my $colu (@colmns) { - if ($colu =~ /=/) { #a value redirect to a pattern/specific name - my $coln; my $colv; - ($coln,$colv) = split(/=/,$colu,2); - $colvals->{$coln} = $colv; - push (@columns,$coln); - } else { - push (@columns,$colu); - } - } - - - unless (@nodes) { #register the plugin in the event of usage - $handler_hash{$ownmod} = 1; - $useglobals = 1; - } - my $hdlrcache; - if ($hdlrtable) { - $hdlrcache = $hdlrtable->getNodesAttribs(\@nodes,\@columns); - } - foreach $node (@nodes) { - unless ($hdlrcache) { next; } - my $attribs = $hdlrcache->{$node}->[0]; #$hdlrtable->getNodeAttribs($node,\@columns); - unless (defined($attribs)) { next; } - foreach (@columns) { - my $col=$_; - if (defined($attribs->{$col})) { - if ($colvals->{$col}) { #A pattern match style request. - if ($attribs->{$col} =~ /$colvals->{$col}/) { - $handler_hash{$ownmod}->{$node} = 1; - delete $unhandled_nodes{$node}; - last; - } - } else { - # call the plugin that matches the table value for that node - if ($attribs->{$col} =~ /$ownmod/) { - $handler_hash{$attribs->{$col}}->{$node} = 1; - delete $unhandled_nodes{$node}; - last; - } - } - } - } - } - $hdlrtable->close; - } # end if (@nodes) - - } else { - push @globalhandlers,$hdlspec; - } - } - if ($useglobals == 1) { #Behavior when globals have not been overriden - my $hdlspec; - foreach $hdlspec (@globalhandlers) { - unless (@nodes) { - $handler_hash{$hdlspec} = 1; - } - foreach (@nodes) { #Specified a specific plugin, not a table lookup - $handler_hash{$hdlspec}->{$_} = 1; - } - } - } elsif ($useglobals == 0) { - unless (@nodes or $usesiteglobal) { #if something like 'makedhcp -n', - foreach (keys %handler_hash) { - if ($handler_hash{$_} == 1) { - delete ($handler_hash{$_}) - } - } - } - foreach $hdlspec (@globalhandlers) { - unless (@nodes or $usesiteglobal) { - $handler_hash{$hdlspec} = 1; - } - foreach (keys %unhandled_nodes) { #Specified a specific plugin, not a table lookup - $handler_hash{$hdlspec}->{$_} = 1; - } - } - } #Otherwise, global handler is implicitly disabled - } else { - print "Error request: $req->{command}->[0] has no known plugin for it.\n"; - return 1; - } - if ($useunhandled) { - my $queuelist; - foreach (@{$cmd_handlers{$req->{command}->[0]}}) { - my $queueitem = $_->[1]; - if (($queueitem =~ /:/) and !($queuelist =~ /($queueitem)/)) { - $queuelist .= "$_->[1];"; - } - } - $queuelist =~ s/;$//; - $queuelist =~ s/:/./g; - foreach (keys %unhandled_nodes) { -# if ($sock) { -# print $sock XMLout({node=>[{name=>[$_],data=>["Unable to identify plugin for this command, check relevant tables: $queuelist"],errorcode=>[1]}]},NoAttr=>1,RootName=>'xcatresponse'); -# } else { - my $tabdesc = $queuelist; - $tabdesc =~ s/=.*$//; - $callback->({node=>[{name=>[$_],error=>['Unable to identify plugin for this command, check relevant tables: '.$tabdesc],errorcode=>[1]}]}); -# } - } - } - -## FOR NOW, DON'T FORK CHILD PROCESS TO MAKE BYPASS SIMPLER AND EASIER TO DEBUG -# $plugin_numchildren=0; -# %plugin_children=(); -# $SIG{CHLD} = \&plugin_reaper; #sub {my $plugpid; while (($plugpid = waitpid(-1, WNOHANG)) > 0) { if ($plugin_children{$plugpid}) { delete $plugin_children{$plugpid}; $plugin_numchildren--; } } }; -# my $check_fds; -# if ($sock) { -# $check_fds = new IO::Select; -# } - foreach (keys %handler_hash) { - my $modname = $_; -# my $shouldbealivepid=$$; - if (-r $plugins_dir."/".$modname.".pm") { - require $plugins_dir."/".$modname.".pm"; -# $plugin_numchildren++; -# my $pfd; #will be referenced for inter-process messaging. -# my $parfd; #not causing a problem that I discern yet, but theoretically -# my $child; -# if ($sock) { #If $sock not passed in, don't fork.. -# socketpair($pfd, $parfd,AF_UNIX,SOCK_STREAM,PF_UNSPEC) or die "socketpair: $!"; -# #pipe($pfd,$cfd); -# $parfd->autoflush(1); -# $pfd->autoflush(1); -# $child = xCAT::Utils->xfork; -# } else { -# $child = 0; -# } -# unless (defined $child) { die "Fork failed"; } -# if ($child == 0) { -# if ($parfd) { #If xCAT is doing multiple requests in same communication PID, things would get unfortunate otherwise -# $parent_fd = $parfd; -# } - my $oldprogname=$$progname; - $$progname=$oldprogname.": $modname instance"; -# if ($sock) { close $pfd; } - unless ($handler_hash{$_} == 1) { - my @nodes = sort {($a =~ /(\d+)/)[0] <=> ($b =~ /(\d+)/)[0] || $a cmp $b } (keys %{$handler_hash{$_}}); - $req->{node}=\@nodes; - } - no strict "refs"; -# eval { #REMOVEEVALFORDEBUG -# if ($dispatch_requests) { - # backup the original req and recover it after the a run - my $org_req = {%$req}; - dispatch_request($req,$callback,$modname); - $req = {%$org_req}; -# } else { -# $SIG{CHLD}='DEFAULT'; -# ${"xCAT_plugin::".$modname."::"}{process_request}->($req,$callback,\&do_request); -# } - $$progname=$oldprogname; -# if ($sock) { -# close($parent_fd); -# xexit(0); -# } -# }; #REMOVEEVALFORDEBUG -# if ($sock or $shouldbealivepid != $$) { #We shouldn't still be alive, try to send as much detail to parent as possible as to why -# my $error= "$modname plugin bug, pid $$, process description: '$$progname'"; -# if ($@) { -# $error .= " with error '$@'"; -# } else { #Sys::Virt and perhaps Net::SNMP sometimes crashes in a way $@ won't catch.. -# $error .= " with missing eval error, probably due to special manipulation of $@ or strange circumstances in an XS library, remove evals in xcatd marked 'REMOVEEVALFORDEBUG and run xcatd -f for more info"; -# } -# if (scalar (@nodes)) { #Don't know which of the nodes, so one error message warning about the possibliity.. -# $error .= " while trying to fulfill request for the following nodes: ".join(",",@nodes); -# } -# xCAT::MsgUtils->message("S","xcatd: $error"); -# $callback->({error=>[$error],errorcode=>[1]}); -# xexit(0); #Die like we should have done -# } elsif ($@) { #We are still alive, should be alive, but yet we have an error. This means we are in the case of 'do_request' or something similar. Forward up the death since our communication channel is intact.. -# die $@; -# } -# } else { -# $plugin_children{$child}=1; -# close $parfd; -# $check_fds->add($pfd); -# } - } else { - my $pm_name = $plugins_dir."/".$modname.".pm"; - foreach my $node (keys %{$handler_hash{$_}}) { - if ($sock) { - print $sock XMLout({node=>[{name=>[$node],data=>["Cannot find the perl module to complete the operation: $pm_name"],errorcode=>[1]}]},NoAttr=>1,RootName=>'xcatresponse'); - } else { - $callback->({node=>[{name=>[$node],data=>["Cannot find the perl module to complete the operation: $pm_name"],errorcode=>[1]}]}); - } - } - } - } - unless ($sock) { return $Main::resps }; -# while (($plugin_numchildren > 0) and ($check_fds->count > 0)) { #this tracks end of useful data from children much more closely -# relay_fds($check_fds,$sock); -# } -# #while (relay_fds($check_fds,$sock)) {} -# my %done; -# $done{serverdone} = {}; -# if ($req->{transid}) { -# $done{transid}=$req->{transid}->[0]; -# } -# if ($sock) { -# my $clientpresence = new IO::Select; #The client may have gone away without confirmation, don't PIPE over this trivial thing -# $clientpresence->add($sock); -# if ($clientpresence->can_write(5)) { -# print $sock XMLout(\%done,RootName => 'xcatresponse',NoAttr=>1); -# } -# } -} - - - - -################################### -# dispatch_request -# dispatch the requested command -# -# NOTE: This is copied from xcatd (last merge 11/23/09). -# All we really need from this subroutine is to call preprocess_request -# and to only run the command for nodes handled by the local server -# Will eventually move to using common source.... -################################### -sub dispatch_request { -# %dispatched_children=(); - require xCAT::Utils; - my $req = shift; - $dispatch_cb = shift; - - my $modname = shift; - my $reqs = []; -# my $child_fdset = new IO::Select; - no strict "refs"; - - #Hierarchy support. Originally, the default scope for noderange commands was - #going to be the servicenode associated unless overriden. - #However, assume for example that you have blades and a blade is the service node - #rpower being executed by the servicenode for one of its subnodes would have to - #reach it's own management module. This has the potential to be non-trivial for some quite possible network configurations. - #Since plugins may commonly experience this, a preprocess_request implementation - #will for now be required for a command to be scaled through service nodes - #If the plugin offers a preprocess method, use it to set the request array - if (defined(${"xCAT_plugin::".$modname."::"}{preprocess_request})) { - $SIG{CHLD}='DEFAULT'; - $reqs = ${"xCAT_plugin::".$modname."::"}{preprocess_request}->($req,$dispatch_cb,\&do_request); - } else { #otherwise, pass it in without hierarchy support - $reqs = [$req]; - } - -# $dispatch_children=0; -# $SIG{CHLD} = \&dispatch_reaper; #sub {my $cpid; while (($cpid =waitpid(-1, WNOHANG)) > 0) { if ($dispatched_children{$cpid}) { delete $dispatched_children{$cpid}; $dispatch_children--; } } }; - my $onlyone=0; - if (defined $reqs and (scalar(@{$reqs}) == 1)) { - $onlyone=1; - } - - foreach (@{$reqs}) { -# my $pfd; -# my $parfd; #use a private variable so it won't trounce itself recursively -# my $child; - delete $_->{noderange}; -#----- added to Client.pm -----# - if ($_->{node}) { - $_->{noderange}->[0]=join(',',@{$_->{node}}); - } -#----- end added to Client.pm -----# - - if (ref $_->{'_xcatdest'} and (ref $_->{'_xcatdest'}) eq 'ARRAY') { - _->{'_xcatdest'} = $_->{'_xcatdest'}->[0]; - } - if ($onlyone and not ($_->{'_xcatdest'} and xCAT::NetworkUtils->thishostisnot($_->{'_xcatdest'}))) { - $SIG{CHLD}='DEFAULT'; - ${"xCAT_plugin::".$modname."::"}{process_request}->($_,$dispatch_cb,\&do_request); - return; - } - -# socketpair($pfd, $parfd,AF_UNIX,SOCK_STREAM,PF_UNSPEC) or die "socketpair: $!"; -# $parfd->autoflush(1); -# $pfd->autoflush(1); -# $child = xCAT::Utils->xfork; -# if ($child) { -# $dispatch_children++; -# $dispatched_children{$child}=1; -# $child_fdset->add($pfd); -# next; -# } -# unless (defined $child) { -# $dispatch_cb->({error=>['Fork failure dispatching request'],errorcode=>[1]}); -# } -# undef $SIG{CHLD}; -# $dispatch_parentfd = $parfd; - my @prexcatdests=(); - my @xcatdests=(); - if (ref($_->{'_xcatdest'}) eq 'ARRAY') { #If array, consider it an 'anycast' operation, broadcast done through dupe - #requests, or an alternative join '&' maybe? - @prexcatdests=@{$_->{'_xcatdest'}}; - } else { - @prexcatdests=($_->{'_xcatdest'}); - } - foreach (@prexcatdests) { - if ($_ and /,/) { - push @xcatdests,split /,/,$_; - } else { - push @xcatdests,$_; - } - } - my $xcatdest; - my $numdests=scalar(@xcatdests); - my $request_satisfied=0; - foreach $xcatdest (@xcatdests) { - my $dlock; - if ($xcatdest and xCAT::NetworkUtils->thishostisnot($xcatdest)) { -#----- added to Client.pm -----# - $dispatch_cb->({warning=>['XCATBYPASS is set, skipping hierarchy call to '.$_->{'_xcatdest'}.'']}); -#----- end added to Client.pm -----# - -# #mkpath("/var/lock/xcat/"); #For now, limit intra-xCAT requests to one at a time, to mitigate DB handle usage -# #open($dlock,">","/var/lock/xcat/dispatchto_$xcatdest"); -# #flock($dlock,LOCK_EX); -# $ENV{XCATHOST} = ($xcatdest =~ /:/ ? $xcatdest : $xcatdest.":3001" ); -# $$progname.=": connection to ".$ENV{XCATHOST}; -# my $errstr; -# eval { -# undef $_->{'_xcatdest'}; -# xCAT::Client::submit_request($_,\&dispatch_callback,$xcatdir."/cert/server-cred.pem",$xcatdir."/cert/server-cred.pem",$xcatdir."/cert/ca.pem"); -# }; -# if ($@) { -# $errstr=$@; -# } -# #unlink("/var/lock/xcat/dispatchto_$xcatdest"); -# #flock($dlock,LOCK_UN); -# if ($errstr) { -# if ($numdests == 1) { -# dispatch_callback({error=>["Unable to dispatch command to ".$ENV{XCATHOST}.", command will not make changes to that server ($errstr)"],errorcode=>[1]}); -# xCAT::MsgUtils->message("S","Error dispatching request to ".$ENV{XCATHOST}.": ".$errstr); -# } else { -# xCAT::MsgUtils->message("S","Error dispatching request to ".$ENV{XCATHOST}.", trying other service nodes: ".$errstr); -# } -# next; -# } else { -# $request_satisfied=1; -# last; -# } - } else { - $$progname.=": locally executing"; - $SIG{CHLD}='DEFAULT'; -# ${"xCAT_plugin::".$modname."::"}{process_request}->($_,\&dispatch_callback,\&do_request); -#----- changed in Client.pm -----# - ${"xCAT_plugin::".$modname."::"}{process_request}->($_,$dispatch_cb,\&do_request); -#----- end changed in Client.pm -----# - last; - } - } -# if ($numdests > 1 and not $request_satisfied) { -# xCAT::MsgUtils->message("S","Error dispatching a request to all possible service nodes for request"); -# dispatch_callback({error=>["Failed to dispatch command to any of the following service nodes: ".join(",",@xcatdests)],errorcode=>[1]}); -# } - -# xexit; - } -#while (($dispatch_children > 0) and ($child_fdset->count > 0)) { relay_dispatch($child_fdset) } -#while (relay_dispatch($child_fdset)) { } #Potentially useless drain. -} - - - -################################### -# do_request -# called from a plugin to execute another xCAT plugin command internally -# -# NOTE: This is copied from xcatd (last merge 11/23/09). -# Will eventually move to using common source.... -################################### -sub do_request { - my $req = shift; - my $second = shift; - my $rsphandler = \&build_response; - my $sock = undef; - if ($second) { - if (ref($second) eq "CODE") { - $rsphandler = $second; - } elsif (ref($second) eq "GLOB") { - $sock = $second; - } - } - - #my $sock = shift; #If no sock, will return a response hash - if ($cmd_handlers{$req->{command}->[0]}) { - return plugin_command($req,$sock,$rsphandler); - } elsif ($req->{command}->[0] eq "noderange" and $req->{noderange}) { - my @nodes = xCAT::NodeRange::noderange($req->{noderange}->[0]); - my %resp; - if (xCAT::NodeRange::nodesmissed()) { - $resp{warning}="Invalid nodes in noderange:".join ',',xCAT::NodeRange::nodesmissed() ."\n"; - } - $resp{serverdone} = {}; - @{$resp{node}}=@nodes; - if ($req->{transid}) { - $resp{transid}=$req->{transid}->[0]; - } - if ($sock) { - print $sock XMLout(\%resp,RootName => 'xcatresponse',NoAttr=>1); - } else { - return (\%resp); - } - } else { - my %resp=(error=>"Unsupported request"); - $resp{serverdone} = {}; - if ($req->{transid}) { - $resp{transid}=$req->{transid}->[0]; - } - if ($sock) { - print $sock XMLout(\%resp,RootName => 'xcatresponse',NoAttr=>1); - } else { - return (\%resp); - } - } -} - - -################################### -# build_response -# This callback handles responses from nested level plugin calls. -# It builds a merged hash of all responses that gets passed back -# to the calling plugin. -# Note: Need to create a "deep clone" of this response to add to the -# return, otherwise next time through the referenced data is overwritten -# -################################### -sub build_response { - my $rsp = shift; - require Storable; - foreach (keys %$rsp) { - my $subresp = Storable::dclone($rsp->{$_}); - push (@{$Main::resps->{$_}}, @{$subresp}); - } -} - - - -} # end of submit_request() - -#################################### -# populates all the site attributes into %::XCATSITEVALS -# This is used with XCATBYPASS=1 -################################### -sub populate_site_hash { - %::XCATSITEVALS=(); - my $sitetab = xCAT::Table->new('site',-create=>0); - unless ($sitetab) { - print ("ERROR: Unable to open basic site table for configuration\n"); - return; - } - my @records = $sitetab->getAllAttribs(qw/key value/); - foreach (@records) { - $::XCATSITEVALS{$_->{key}}=$_->{value}; - } -} - - - -########################################## -# handle_response is a default callback that can be passed into submit_request() -# It is invoked repeatedly by submit_request() to print out the data returned by -# the plugin. -# -# The normal flow is: -# -> client cmd (e.g. nodels, which is just a link to xcatclient) -# -> xcatclient -# -> submit_request() -# -> send xml request to xcatd -# -> xcatd -# -> process_request() of the plugin -# <- plugin callback -# <- xcatd -# <- xcatd sends xml response to client -# <- submit_request() read response -# <- handle_response() prints responses and saves exit codes -# <- xcatclient gets exit code and exits -# -# But in XCATBYPASS mode, the flow is: -# -> client cmd (e.g. nodels, which is just a link to xcatclient) -# -> xcatclient -# -> submit_request() -# -> process_request() of the plugin -# <- handle_response() prints responses and saves exit codes -# <- xcatclient gets exit code and exits -# -# Format of the response hash: -# {data => [ 'data str1', 'data str2', '...' ] } -# -# Results are printed as: -# data str1 -# data str2 -# -# or: -# {data => [ {desc => [ 'desc1' ], -# contents => [ 'contents1' ] }, -# {desc => [ 'desc2 ], -# contents => [ 'contents2' ] } -# : -# ] } -# NOTE: In this format, only the data array can have more than one -# element. All other arrays are assumed to be a single element. -# Results are printed as: -# desc1: contents1 -# desc2: contents2 -# -# or: -# {node => [ {name => ['node1'], -# data => [ {desc => [ 'node1 desc' ], -# contents => [ 'node1 contents' ] } ] }, -# {name => ['node2'], -# data => [ {desc => [ 'node2 desc' ], -# contents => [ 'node2 contents' ] } ] }, -# : -# ] } -# NOTE: Only the node array can have more than one element. -# All other arrays are assumed to be a single element. -# -# This was generated from the corresponding XML: -# -# -# node1 -# -# node1 desc -# node1 contents -# -# -# -# node2 -# -# node2 desc -# node2 contents -# -# -# -# -# Results are printed as: -# node_name: desc: contents -########################################## -sub handle_response { - my $rsp = shift; - if ($ENV{'XCATSHOWXML'}) { - my $xmlrec=XMLout($rsp,RootName=>'xcatresponse',NoAttr=>1,KeyAttr=>[]); - print "$xmlrec\n"; - return; - } -#print "in handle_response\n"; - # Handle errors - if (defined($rsp->{errorcode})) { - if (ref($rsp->{errorcode}) eq 'ARRAY') { - foreach my $ecode (@{$rsp->{errorcode}}) { - $xCAT::Client::EXITCODE |= $ecode; - } - } - else { - $xCAT::Client::EXITCODE |= $rsp->{errorcode}; - } # assume it is a non-reference scalar - } - if ($rsp->{error}) { -#print "printing error\n"; - if (ref($rsp->{error}) eq 'ARRAY') { - foreach my $text (@{$rsp->{error}}) { - if ($rsp->{NoErrorPrefix}) { - print STDERR "$text\n"; - } else { - print STDERR "Error: $text\n"; - } - } - } - else { - if ($rsp->{NoErrorPrefix}) { - print STDERR ($rsp->{error}."\n"); - } else { - print STDERR ("Error: ".$rsp->{error}."\n"); - } - } - } - if ($rsp->{warning}) { -#print "printing warning\n"; - if (ref($rsp->{warning}) eq 'ARRAY') { - foreach my $text (@{$rsp->{warning}}) { - if ($rsp->{NoWarnPrefix}) { - print STDERR "$text\n"; - } else { - print STDERR "Warning: $text\n"; - } - } - } - else { - if ($rsp->{NoWarnPrefix}) { - print STDERR ($rsp->{warning}."\n"); - } else { - print STDERR ("Warning: ".$rsp->{warning}."\n"); - } - } - } - if ($rsp->{info}) { -#print "printing info\n"; - if (ref($rsp->{info}) eq 'ARRAY') { - foreach my $text (@{$rsp->{info}}) { - print "$text\n"; - } - } - else { - print ($rsp->{info}."\n"); - } - } - - if ($rsp->{sinfo}) { - if (ref($rsp->{sinfo}) eq 'ARRAY') { - foreach my $text (@{$rsp->{sinfo}}) { - print "$text\r"; $|++; - } - } - else { - print ($rsp->{sinfo}."\r"); $|++; - } - } - - - - # Handle {node} structure - my $errflg=0; - my $nodes=($rsp->{node}); - unless (ref $nodes eq 'ARRAY') { - $nodes = [$nodes]; - } - if (scalar @{$nodes}) { -#print "printing node\n"; - my $node; - foreach $node (@$nodes) { - my $desc; - if (ref($node->{name}) eq 'ARRAY') { - $desc=$node->{name}->[0]; - } else { - $desc=$node->{name}; - } - if ($node->{errorcode}) { - if (ref($node->{errorcode}) eq 'ARRAY') { - foreach my $ecode (@{$node->{errorcode}}) { - $xCAT::Client::EXITCODE |= $ecode; - } - } - else { - $xCAT::Client::EXITCODE |= $node->{errorcode}; - } # assume it is a non-reference scalar - } - if ($node->{error}) { - $desc.=": Error: ".$node->{error}->[0]; - $errflg=1; - } - if ($node->{warning}) { - $desc.=": Warning: ".$node->{warning}->[0]; - $errflg=1; - } - if ($node->{data}) { - if (ref(\($node->{data})) eq 'SCALAR') { - $desc=$desc.": ".$node->{data}; - } elsif (ref($node->{data}) eq 'HASH') { - if ($node->{data}->{desc}) { - if (ref($node->{data}->{desc}) eq 'ARRAY') { - $desc=$desc.": ".$node->{data}->{desc}->[0]; - } else { - $desc=$desc.": ".$node->{data}->{desc}; - } - } - if ($node->{data}->{contents}) { - if (ref($node->{data}->{contents}) eq 'ARRAY') { - $desc="$desc: ".$node->{data}->{contents}->[0]; - } else { - $desc="$desc: ".$node->{data}->{contents}; - } - } - } elsif (ref(\($node->{data}->[0])) eq 'SCALAR') { - $desc=$desc.": ".$node->{data}->[0]; - } else { - if ($node->{data}->[0]->{desc}) { - $desc=$desc.": ".$node->{data}->[0]->{desc}->[0]; - } - if ($node->{data}->[0]->{contents}) { - $desc="$desc: ".$node->{data}->[0]->{contents}->[0]; - } - } - } - if ($desc) { - if ($errflg == 1) { - print STDERR ("$desc\n"); - } else { - print "$desc\n"; - } - } - } - } - - # Handle {data} structure with no nodes - if ($rsp->{data}) { -#print "printing data\n"; - my $data=($rsp->{data}); - my $data_entry; - foreach $data_entry (@$data) { - my $desc; - if (ref(\($data_entry)) eq 'SCALAR') { - $desc=$data_entry; - } else { - if ($data_entry->{desc}) { - $desc=$data_entry->{desc}->[0]; - } - if ($data_entry->{contents}) { - if ($desc) { - $desc="$desc: ".$data_entry->{contents}->[0]; - } else { - $desc=$data_entry->{contents}->[0]; - } - } - } - if ($desc) { print "$desc\n"; } - } - } -} # end of handle_response - - - - - - diff --git a/xCAT-server/lib/xcat/plugins/imgcapture.pm b/xCAT-server/lib/xcat/plugins/imgcapture.pm index bd4f881de..f0aa71fc9 100644 --- a/xCAT-server/lib/xcat/plugins/imgcapture.pm +++ b/xCAT-server/lib/xcat/plugins/imgcapture.pm @@ -123,7 +123,7 @@ sub process_request { # Handle image capture separately for s390x if ($arch eq 's390x') { eval { require xCAT_plugin::zvm; }; # Load z/VM plugin dynamically - xCAT_plugin::zvm->imageCapture($callback, $node, $os, $arch, $profile, $osimg, $device); + xCAT_plugin::zvm->imageCapture($callback, $node, $os, $arch, $type, $profile, $osimg, $device); return; } diff --git a/xCAT-server/lib/xcat/plugins/imgport.pm b/xCAT-server/lib/xcat/plugins/imgport.pm index 9e3e2af9a..e09706659 100644 --- a/xCAT-server/lib/xcat/plugins/imgport.pm +++ b/xCAT-server/lib/xcat/plugins/imgport.pm @@ -174,8 +174,15 @@ sub xexport { my $dest = shift @ARGV; my $cwd = $request->{cwd}; #getcwd; $cwd = $cwd->[0]; + + if (!defined $remoteHost) { + $callback->( {data => ["Exporting $img_name to $cwd..."]}); + } + else { + $callback->( {data => ["Exporting $img_name to $remoteHost..."]}); + } - $callback->( {data => ["Exporting $img_name to $cwd..."]}); + # check if all files are in place my $attrs = get_image_info($img_name, $callback, $node, @extra); #print Dumper($attrs); @@ -237,11 +244,16 @@ sub get_image_info { $errors++; } - unless($attrs0->{provmethod} =~ /install|netboot|statelite|raw/){ + unless($attrs0->{provmethod} =~ /install|netboot|statelite|raw|sysclone/){ $callback->({error=>["Exporting images with 'provemethod' " . $attrs0->{provmethod} . " is not supported. Hint: install, netboot, statelite, or raw"], errorcode=>[1]}); $errors++; } - + + if (($attrs0->{provmethod} =~ /sysclone/) && ($attrs0->{osarch} !~ /s390x/)) { + $callback->({error=>["Exporting images with 'provemethod' " . $attrs0->{provmethod} . " is not supported for osarch '" . $attrs0->{osarch} ."'"], errorcode=>[1]}); + $errors++; + } + #$attrs->{imagename} = $imagename; if($errors){ @@ -438,7 +450,7 @@ sub get_files{ my @files; my $dir = "$installroot/netboot/$osvers/s390x/$profile"; opendir(DIR, $dir) or $callback->({error=>["Could not open image files in directory $dir"], errorcode=>[1]}); - + while (my $file = readdir(DIR)) { # We only want files in the directory that end with .img next unless (-f "$dir/$file"); @@ -449,7 +461,7 @@ sub get_files{ if (@files) { $attrs->{rawimagefiles}->{files} = [@files]; } - + closedir(DIR); } else { @@ -465,7 +477,7 @@ sub get_files{ $attrs->{linuximage}->{pkglist} = $temp; } } - + @arr = ("$installroot/netboot"); my $rootimgdir=$attrs->{linuximage}->{rootimgdir}; my $ramdisk; @@ -489,27 +501,27 @@ sub get_files{ $rootimg = look_for_file('rootimg.gz', $callback, $attrs, @arr); } unless($ramdisk){ - $callback->({error=>["Couldn't find ramdisk (initrd-stateless.gz) for $imagename"],errorcode=>[1]}); - $errors++; - }else{ - $attrs->{ramdisk} = $ramdisk; - } + $callback->({error=>["Couldn't find ramdisk (initrd-stateless.gz) for $imagename"],errorcode=>[1]}); + $errors++; + }else{ + $attrs->{ramdisk} = $ramdisk; + } unless($kernel){ - $callback->({error=>["Couldn't find kernel (kernel) for $imagename"],errorcode=>[1]}); - $errors++; - }else{ - $attrs->{kernel} = $kernel; - } + $callback->({error=>["Couldn't find kernel (kernel) for $imagename"],errorcode=>[1]}); + $errors++; + }else{ + $attrs->{kernel} = $kernel; + } unless($rootimg){ - $callback->({error=>["Couldn't find rootimg (rootimg.gz) for $imagename"],errorcode=>[1]}); - $errors++; - }else{ - $attrs->{rootimg} = $rootimg; - } - } - } elsif ($provmethod =~ /statelite/) { + $callback->({error=>["Couldn't find rootimg (rootimg.gz) for $imagename"],errorcode=>[1]}); + $errors++; + }else{ + $attrs->{rootimg} = $rootimg; + } + } + } elsif ($provmethod =~ /statelite/) { @arr = ("$installroot/custom/netboot", "$xcatroot/share/xcat/netboot"); #get .pkglist file if (! $attrs->{linuximage}->{pkglist}) { @@ -541,24 +553,24 @@ sub get_files{ } unless($kernel){ - $callback->({error=>["Couldn't find kernel (kernel) for $imagename"],errorcode=>[1]}); - $errors++; - }else{ - $attrs->{kernel} = $kernel; - } + $callback->({error=>["Couldn't find kernel (kernel) for $imagename"],errorcode=>[1]}); + $errors++; + }else{ + $attrs->{kernel} = $kernel; + } unless($ramdisk){ - $callback->({error=>["Couldn't find ramdisk (initrd-statelite.gz) for $imagename"],errorcode=>[1]}); - $errors++; - }else{ - $attrs->{ramdisk} = $ramdisk; - } - } + $callback->({error=>["Couldn't find ramdisk (initrd-statelite.gz) for $imagename"],errorcode=>[1]}); + $errors++; + }else{ + $attrs->{ramdisk} = $ramdisk; + } + } } - if (( $provmethod =~ /raw/ ) and ( $arch =~ /s390x/ )) { + if (( $provmethod =~ /raw|sysclone/ ) and ( $arch =~ /s390x/ )) { my @files; - my $dir = "$installroot/raw/$osvers/s390x/$profile"; + my $dir = "$installroot/$provmethod/$osvers/s390x/$profile"; opendir(DIR, $dir) or $callback->({error=>["Could not open image files in directory $dir"], errorcode=>[1]}); while (my $file = readdir(DIR)) { @@ -634,32 +646,52 @@ sub look_for_file { } -# here's where we make the tarball +#------------------------------------------------------- + +=head3 make_bundle + + Description : Makes the image bundle tar ball. + Arguments : Image name from the command line + Destination command line parameter, i.e. name of the tar ball. For a + remote host this can include the target directory. + Remote host parameter from the command line, if specified + Image attributes from the osimage table + callback + Current working directory + Returns : None + Example : make_bundle( $img_name, $dest, $remoteHost, $attrs, $callback, $cwd ); + +=cut + +#------------------------------------------------------- sub make_bundle { my $imagename = shift; my $dest = shift; my $remoteHost = shift; my $attribs = shift; my $callback = shift; - - # tar ball is made in local working directory. Sometimes doing this in /tmp - # is bad. In the case of my development machine, the / filesystem was nearly full. - # so doing it in cwd is easy and predictable. my $dir = shift; - #my $dir = getcwd; + my $rc; + + # Determine the local working directory. It could be specified in the site table + # or we will default to the current working directory which was passed to this routine. + my @siteEntries = xCAT::TableUtils->get_site_attribute("tmpdir"); + my $workDir = $siteEntries[0]; + if (!$workDir) { + $workDir = $dir; + } # get rid of spaces and put in underlines. $imagename =~ s/\s+/_/g; - # we may find that cwd doesn't work, so we use the request cwd. - my $ttpath = mkdtemp("$dir/imgexport.$$.XXXXXX"); + # Create the directory in which we collect the files prior to tarring them. + my $ttpath = mkdtemp("$workDir/imgexport.$$.XXXXXX"); $callback->({data=>["Creating $ttpath..."]}) if $::VERBOSE; my $tpath = "$ttpath/$imagename"; mkdir("$tpath"); chmod 0755,$tpath; - #for statelite if ($attribs->{osimage}->{provmethod} eq 'statelite') { #copy the rootimgdir over @@ -670,6 +702,10 @@ sub make_bundle { $attribs->{'rootimgtree'} = "$rootimgdir/rootimgtree.gz"; } else { $callback->({error=>["Couldn't locate the root image directory. "],errorcode=>[1]}); + $rc = system("rm -rf $ttpath"); + if ($rc) { + $callback->({error=>["Failed to clean up temp space $ttpath"],errorcode=>[1]}); + } return 0; } @@ -677,6 +713,10 @@ sub make_bundle { my $lftab= xCAT::Table->new("litefile" ,-create=>1); if (!$lftab) { $callback->({error=>["Could not open the litefile table."],errorcode=>[1]}); + $rc = system("rm -rf $ttpath"); + if ($rc) { + $callback->({error=>["Failed to clean up temp space $ttpath"],errorcode=>[1]}); + } return 0; } @@ -777,7 +817,7 @@ sub make_bundle { # Copy any raw image files. Multiple files can exist (used by s390x) if ($attribs->{rawimagefiles}->{files}) { foreach my $fromf (@{$attribs->{rawimagefiles}->{files}}) { - my $rc = system("cp $fromf $tpath"); + $rc = system("cp $fromf $tpath"); if ($rc != 0) { $callback->({error=>["Unable to copy the raw image file $fromf."], errorcode=>[1]}); $rc = system("rm -rf $ttpath"); @@ -806,30 +846,39 @@ sub make_bundle { } } - # If this is an export to a remote host then split the destination into the - # remote directory portion and the name of the export bundle. - my $remoteDest; - if (defined $remoteHost) { - $remoteDest = $dest; - if (defined $dest) { - $dest = (split( '/', $dest))[-1]; - } - } - # now get right below all this stuff and tar it up. chdir($ttpath); $callback->( {data => ["Inside $ttpath."]}); - unless($dest){ - $dest = "$dir/$imagename.tgz"; - } - # if no absolute path specified put it in the cwd - unless($dest =~ /^\//){ - $dest = "$dir/$dest"; + # Determine the name of the bundle that we will create. + my ($bundleName, $destDir); + if (defined $dest) { + ($bundleName, $destDir) = fileparse($dest); + if ($bundleName eq '') { + $bundleName="$imagename.tgz"; + } + } else { + $bundleName="$imagename.tgz"; + } + + + # Determine the full file specification of the image bundle. + my $remoteDest; + my $tempBundle; + if (defined $remoteHost) { + # For a remote host, we need both a local build bundle + # and the final remote bundle file specification. + $tempBundle = mktemp("$workDir/imgexport.$$.XXXXXX"); + chomp($tempBundle); + $dest = $tempBundle; + $remoteDest = "$destDir$bundleName"; + } + else { + # Local imgexports go to the current working directory + $dest = "$dir/$bundleName"; } $callback->( {data => ["Compressing $imagename bundle. Please be patient."]}); - my $rc; if($::VERBOSE){ $callback->({data => ["tar czvf $dest . "]}); $rc = system("tar czvf $dest . "); @@ -854,28 +903,48 @@ sub make_bundle { if (defined $remoteHost) { my $remoteFile = $remoteHost . ':' . $remoteDest; - $callback->({data=>["Moving the image bundle to the remote system"]}); + $callback->({data=>["Moving the image bundle to the remote system location $remoteDest"]}); $rc = system("/usr/bin/scp -B $dest $remoteFile"); if ($rc) { - $callback->({error=>["Unable to copy the image bundle to the remote host"], errorcode=>[1]}); - } - - # Remove the image bundle that was sent to the remote system. - $rc = system("rm $dest"); - if ($rc) { - $callback->({error=>["Failed to clean up image bundle $dest"], errorcode=>[1]}); + $callback->({error=>["Unable to copy the image bundle $bundleName to the remote host"], errorcode=>[1]}); } } } - chdir($dir); + # Remove the temporary image bundle if it is still around (for remote exports). + if (-e $tempBundle) { + $rc = system("rm -f $tempBundle"); + if ($rc) { + $callback->({error=>["Failed to clean up the temporary image bundle $tempBundle"], errorcode=>[1]}); + } + } + + # Remove the directory that we used to collect the files prior to creating the tar ball. + chdir($dir); $rc = system("rm -rf $ttpath"); if ($rc) { $callback->({error=>["Failed to clean up temp space $ttpath"],errorcode=>[1]}); - return; - } + } + + return; } +#------------------------------------------------------- + +=head3 extract_bundle + + Description : Extract the files from the image tar ball. + Arguments : Request + callback + nodes + New profile name to use for the image, if specified. + Remote host parameter from the command line + Returns : None + Example : extract_bundle( $request, $callback, $nodes, $new_profile, $remoteHost ); + +=cut + +#------------------------------------------------------- sub extract_bundle { my $request = shift; #print Dumper($request); @@ -889,31 +958,43 @@ sub extract_bundle { my $data; my $datas; my $error = 0; + my $bundleCopy; my $bundle = shift @ARGV; - # extract the image in temp path in cwd + # Determine the current working directory. my $dir = $request->{cwd}; #getcwd; $dir = $dir->[0]; #print Dumper($dir); - # If we have a remote file then move it to the xCAT MN + # A working directory will hold the temporary image directory. + # It will also hold the local copy of a remote image bundle. + # The directory can be defined in the site table and if not + # defined there then we will default to using the current working + # directory. + my @siteEntries = xCAT::TableUtils->get_site_attribute("tmpdir"); + my $workDir = $siteEntries[0]; + if (!$workDir) { + $workDir = $dir; + } + + # If we have a remote file then transfer it to the xCAT MN first. if (defined $remoteHost) { - # Create unique directory for the bundle and copy the bundle to it + # Create unique copy the remote bundle in the working directory my $remoteFile = "$remoteHost:$bundle"; - $dir = `/bin/mktemp -d /var/tmp/XXXXXX`; - chomp($dir); - $bundle = $dir . '/' . (split( '/', $bundle))[-1]; + $bundleCopy = `/bin/mktemp $workDir/imgimport.$$.XXXXXX`; + chomp($bundleCopy); $callback->({data=>["Obtaining the image bundle from the remote system"]}); - my $rc = system("/usr/bin/scp -v -B $remoteFile $dir"); + my $rc = system("/usr/bin/scp -v -B $remoteFile $bundleCopy"); if ($rc != 0) { - $callback->({error=>["Unable to copy the image bundle from the remote host"], errorcode=>[1]}); - $rc = rmtree $dir; - if (! $rc) { - $callback->({error=>["Failed to clean up directory containing the remote image bundle $bundle"], errorcode=>[1]}); + $callback->({error=>["Unable to copy the image bundle $bundle from the remote host"], errorcode=>[1]}); + $rc = system("rm -rf $bundleCopy"); + if ($rc) { + $callback->({error=>["Failed to remove the local copy of the remote image bundle $bundleCopy"], errorcode=>[1]}); } return; } + $bundle = $bundleCopy; } else { # When we are not doing a remote copy, we need to verify the bundle exists and find its exact location unless(-r $bundle){ @@ -936,7 +1017,7 @@ sub extract_bundle { } } - my $tpath = mkdtemp("$dir/imgimport.$$.XXXXXX"); + my $tpath = mkdtemp("$workDir/imgimport.$$.XXXXXX"); $callback->({data=>["Unbundling image..."]}); my $rc; @@ -949,6 +1030,9 @@ sub extract_bundle { if ($rc) { $callback->({error => ["Failed to extract bundle $bundle"],errorcode=>[1]}); + # Remove the files in the untar directory so that we don't attempt to process + # a partially untarred image bundle. + system("rm -rf $tpath"); } # get all the files in the tpath. These should be all the image names. @@ -956,97 +1040,85 @@ sub extract_bundle { # go through each image directory. Find the XML and put it into the array. If there are any # errors then the whole thing is over and we error and leave. foreach my $imgdir (@files){ - unless(-r "$imgdir/manifest.xml"){ - $callback->({error=>["Failed to find manifest.xml file in image bundle"],errorcode=>[1]}); - if (defined $remoteHost) { - $rc = rmtree $dir; - if ( ! $rc ) { - $callback->({error=>["Failed to clean up directory containing the remote image bundle $bundle"], errorcode=>[1]}); - } - } - return; - } - $xml = new XML::Simple; - # get the data! - # put it in an eval string so that it - $data = eval { $xml->XMLin("$imgdir/manifest.xml") }; - if($@){ - $callback->({error=>["invalid manifest.xml file inside the bundle. Please verify the XML"],errorcode=>[1]}); - #my $foo = $@; - #$foo =~ s/\n//; - #$callback->({error=>[$foo],errorcode=>[1]}); - #foreach($@){ - # last; - #} - # If this was an import from a remote host then remove the directory created for the remote files. - # We do not want to leave files hanging around that were brought from another system. - if (defined $remoteHost) { - $rc = rmtree $dir; - if ( ! $rc ) { - $callback->({error=>["Failed to clean up directory containing the remote image bundle $bundle"], errorcode=>[1]}); - } - } - return; - } - #print Dumper($data); - #push @{$datas}, $data; - - # now we need to import the files... - unless(verify_manifest($data, $callback)){ - $error++; - next; + unless(-r "$imgdir/manifest.xml"){ + $callback->({error=>["Failed to find manifest.xml file in image bundle"],errorcode=>[1]}); + last; + } + + $xml = new XML::Simple; + # get the data! + # put it in an eval string so that it + $data = eval { $xml->XMLin("$imgdir/manifest.xml") }; + if($@){ + $callback->({error=>["invalid manifest.xml file inside the bundle. Please verify the XML"],errorcode=>[1]}); + #my $foo = $@; + #$foo =~ s/\n//; + #$callback->({error=>[$foo],errorcode=>[1]}); + #foreach($@){ + # last; + #} + last; + } + #print Dumper($data); + #push @{$datas}, $data; + + # now we need to import the files... + unless(verify_manifest($data, $callback)){ + $error++; + next; + } + + # check media first + unless(check_media($data, $callback)){ + $error++; + next; + } + + #change profile name if needed + if ($new_profile) { + $data=change_profile($data, $callback, $new_profile, $imgdir); + } + + #import manifest.xml into xCAT database + unless(set_config($data, $callback)){ + $error++; + next; + } + + # now place files in appropriate directories. + unless(make_files($data, $imgdir, $callback)){ + $error++; + next; + } + + # put postscripts in the postsctipts table + if ($nodes) { + unless(set_postscripts($data, $callback, $nodes)){ + $error++; + next; + } + } + + my $osimage = $data->{osimage}->{imagename}; + $callback->({data=>["Successfully imported the image $osimage."]}); } - # check media first - unless(check_media($data, $callback)){ - $error++; - next; - } - - #change profile name if needed - if ($new_profile) { - $data=change_profile($data, $callback, $new_profile, $imgdir); - } - - #import manifest.xml into xCAT database - unless(set_config($data, $callback)){ - $error++; - next; - } - - # now place files in appropriate directories. - unless(make_files($data, $imgdir, $callback)){ - $error++; - next; - } - - # put postscripts in the postsctipts table - if ($nodes) { - unless(set_postscripts($data, $callback, $nodes)){ - $error++; - next; - } - } - - my $osimage = $data->{osimage}->{imagename}; - $callback->({data=>["Successfully imported the image $osimage."]}); - } - - # remove temp file only if there were no problems. - unless($error){ + # Clean up for this routine. + # Remove the temp directory used for the exploded bundle + if ( -e $tpath ) { $rc = system("rm -rf $tpath"); if ($rc) { $callback->({error=>["Failed to clean up temp space $tpath"],errorcode=>[1]}); - return; - } + # Don't return just yet. We want the rest of the cleanup to occur. + } } - + # If this was an import from a remote host then remove the directory created for the remote files. # We do not want to leave files hanging around that were brought from another system. - if ( defined $remoteHost ) { - $rc = rmtree $dir; - if ( ! $rc ) { - $callback->({error=>["Failed to clean up directory containing the remote image bundle $bundle"],errorcode=>[1]}); + if ( -e $bundleCopy ) { + $rc = system("rm -rf $bundleCopy"); + if ($rc) { + $callback->({error=>["Failed to remove the local copy of the remote image bundle $bundleCopy"], errorcode=>[1]}); } } } @@ -1068,7 +1140,11 @@ sub change_profile { $installdir = '/install'; } if ($data->{linuximage}->{rootimgdir}) { - $data->{linuximage}->{rootimgdir}="$installdir/netboot/" . $data->{osimage}->{osvers} . "/" . $data->{osimage}->{osarch} . "/$new_profile"; + if (($data->{osimage}->{osarch} eq "s390x") && ($data->{osimage}->{provmethod} =~ /raw|sysclone/)) { + $data->{linuximage}->{rootimgdir}="$installdir/$data->{osimage}->{provmethod}/" . $data->{osimage}->{osvers} . "/" . $data->{osimage}->{osarch} . "/$new_profile"; + } else { + $data->{linuximage}->{rootimgdir}="$installdir/netboot/" . $data->{osimage}->{osvers} . "/" . $data->{osimage}->{osarch} . "/$new_profile"; + } for my $a ("kernel", "ramdisk", "rootimg", "rootimgtree", "litefile") { if ($data->{$a}) { @@ -1325,8 +1401,12 @@ sub verify_manifest { } $data->{osimage}->{osarch} =~ s/^\s*(\S*)\s*$/$1/; - unless($data->{osimage}->{provmethod} =~ /install|netboot|statelite|raw/){ - $callback->({error=>["Importing images with 'provemethod' " . $data->{osimage}->{provmethod} . " is not supported. Hint: install, netboot, statelite, or raw"],errorcode=>[1]}); + unless($data->{osimage}->{provmethod} =~ /install|netboot|statelite|sysclone|raw/){ + $callback->({error=>["Importing images with 'provmethod' " . $data->{osimage}->{provmethod} . " is not supported. Hint: install, netboot, statelite, sysclone or raw"],errorcode=>[1]}); + $errors++; + } + if (($data->{osimage}->{provmethod} =~ /sysclone/) && ($data->{osimage}->{osarch} !~ /s390x/)) { + $callback->({error=>["Importing images with 'provemethod' " . $data->{osimage}->{provmethod} . " is not supported for osarch '" . $data->{osimage}->{osarch} ."'"], errorcode=>[1]}); $errors++; } $data->{osimage}->{provmethod} =~ s/^\s*(\S*)\s*$/$1/; @@ -1344,18 +1424,28 @@ sub verify_manifest { $callback->({info => ['this is an esx image']}); # do nothing for ESX 1; - } elsif (($data->{osimage}->{provmethod} =~ /netboot/) and ($data->{osimage}->{osarch} !~ /s390x/)) { - unless($data->{ramdisk}){ - $callback->({error=>["The 'ramdisk' field is not defined in manifest.xml."],errorcode=>[1]}); - $errors++; - } - unless($data->{kernel}){ - $callback->({error=>["The 'kernel' field is not defined in manifest.xml."],errorcode=>[1]}); - $errors++; - } - unless($data->{rootimg}){ - $callback->({error=>["The 'rootimg' field is not defined in manifest.xml."],errorcode=>[1]}); - $errors++; + } elsif ($data->{osimage}->{provmethod} =~ /netboot/) { + if ($data->{osimage}->{osarch} =~ /s390x/) { + if (!$data->{rawimagefiles}) { + $callback->({error=>["The 'rawimagefiles' section is not defined in manifest.xml."],errorcode=>[1]}); + $errors++; + } elsif (!$data->{rawimagefiles}->{files}) { + $callback->({error=>["'files' were not specified in the 'rawimagefiles' section of manifest.xml."],errorcode=>[1]}); + $errors++; + } + } else { + unless($data->{ramdisk}){ + $callback->({error=>["The 'ramdisk' field is not defined in manifest.xml."],errorcode=>[1]}); + $errors++; + } + unless($data->{kernel}){ + $callback->({error=>["The 'kernel' field is not defined in manifest.xml."],errorcode=>[1]}); + $errors++; + } + unless($data->{rootimg}){ + $callback->({error=>["The 'rootimg' field is not defined in manifest.xml."],errorcode=>[1]}); + $errors++; + } } }elsif($data->{osimage}->{provmethod} =~ /statelite/){ @@ -1372,6 +1462,16 @@ sub verify_manifest { $errors++; } + } elsif ($data->{osimage}->{provmethod} =~ /sysclone/) { + if ($data->{osimage}->{osarch} =~ /s390x/) { + if (!$data->{rawimagefiles}) { + $callback->({error=>["The 'rawimagefiles' section is not defined in manifest.xml."],errorcode=>[1]}); + $errors++; + } elsif (!$data->{rawimagefiles}->{files}) { + $callback->({error=>["'files' were not specified in the 'rawimagefiles' section of manifest.xml."],errorcode=>[1]}); + $errors++; + } + } } if($errors){ @@ -1565,7 +1665,7 @@ sub make_files { $callback->( {data => ["Updating the litefile table."]}); my $fn=$data->{litefile}; if (!$fn) { - $callback->({error=>["Could not find liefile.csv."],errorcode=>[1]}); + $callback->({error=>["Could not find litefile.csv."],errorcode=>[1]}); return 1; } elsif (! -r $fn) { $callback->({error=>["Could not find $fn."],errorcode=>[1]}); @@ -1592,11 +1692,11 @@ sub make_files { close(FILE); $lftab->commit; - $callback->( {data => ["The litetree and statelite talbes are untouched. You can update them if needed."]}); + $callback->( {data => ["The litetree and statelite tables are untouched. You can update them if needed."]}); } # For s390x copy all image files from the root bundle directory to the repository location - if (($data->{osimage}->{osarch} =~ /s390x/) && (($data->{osimage}->{provmethod} =~ /raw/) || ($data->{osimage}->{provmethod} =~ /netboot/))) { + if (($data->{osimage}->{osarch} =~ /s390x/) && ($data->{osimage}->{provmethod} =~ /raw|netboot|sysclone/)) { my $reposImgDir = "$installroot/$data->{osimage}->{provmethod}/$data->{osimage}->{osvers}/$data->{osimage}->{osarch}/$data->{osimage}->{profile}"; mkpath($reposImgDir); diff --git a/xCAT-server/lib/xcat/plugins/rmimage.pm b/xCAT-server/lib/xcat/plugins/rmimage.pm index a22c50e06..3125cbc4c 100644 --- a/xCAT-server/lib/xcat/plugins/rmimage.pm +++ b/xCAT-server/lib/xcat/plugins/rmimage.pm @@ -105,8 +105,8 @@ sub process_request { if($verbose) { $callback->({info=>["For osimage $imagename: osver = $osver, arch = $arch, profile = $profile, method = $method in osimage table"]}); } - if (($method) && ($method ne "netboot") && ($method ne "statelite") && ($method ne "raw")) { - $callback->({error=>["Invalid method \"$method\", the rmimage command can only be used to remove the netboot, statelite, or raw image files"], errorcode=>[1]}); + if (($method) && ($method ne "netboot") && ($method ne "statelite") && ($method ne "raw") && ($method ne "sysclone")) { + $callback->({error=>["Invalid method \"$method\", the rmimage command can only be used to remove the netboot, statelite, sysclone or raw image files"], errorcode=>[1]}); return; } @@ -136,23 +136,31 @@ sub process_request { $callback->({error=>["Invalid image name $imagename"],errorcode=>[1]}); return; } - if (($method ne "netboot") && ($method ne "statelite") && ($method ne "raw")) { - $callback->({error=>["Invalid method \"$method\", the rmimage command can only be used to remove the netboot, statelite, or raw image files"], errorcode=>[1]}); + if (($method ne "netboot") && ($method ne "statelite") && ($method ne "raw") && ($method ne "sysclone")) { + $callback->({error=>["Invalid method \"$method\", the rmimage command can only be used to remove the netboot, statelite, sysclone or raw image files"], errorcode=>[1]}); return; } } - - if ($method eq "raw") { - $imagedir = "$installroot/$method/$osver/$arch/$profile"; + + if ($arch eq "s390x") { + if (($method eq "raw") || ($method eq "sysclone")) { + $imagedir = "$installroot/$method/$osver/$arch/$profile"; + } else { + $imagedir = "$installroot/netboot/$osver/$arch/$profile"; + } } else { $imagedir = "$installroot/netboot/$osver/$arch/$profile"; } } } else { # imagename is not specified - if ($method eq "raw") { - $imagedir = "$installroot/$method/$osver/$arch/$profile"; + if ($arch eq "s390x") { + if (($method eq "raw") || ($method eq "sysclone")) { + $imagedir = "$installroot/$method/$osver/$arch/$profile"; + } else { + $imagedir = "$installroot/netboot/$osver/$arch/$profile"; + } } else { - $imagedir = "$installroot/netboot/$osver/$arch/$profile"; + $imagedir = "$installroot/netboot/$osver/$arch/$profile"; } } @@ -164,7 +172,14 @@ sub process_request { $callback->({error=>["Image directory $imagedir does not exist"],errorcode=>[1]}); return; } - + + # Doing this extra check now because we now have a method and arch from either the node or the image name. + if (($method eq "sysclone") && ($arch ne "s390x")) { + # Only supporting removing sysclone images for s390x at this time. + $callback->({error=>["rmimage cannot be used to remove sysclone images for \"$arch\" architecture"], errorcode=>[1]}); + return; + } + my @filestoremove = ("$imagedir/rootimg.gz", "$imagedir/kernel", "$imagedir/initrd-stateless.gz", "$imagedir/initrd-statelite.gz"); #some rpms like atftp mount the rootimg/proc to /proc, we need to make sure rootimg/proc is free of junk @@ -196,7 +211,7 @@ sub process_request { } # For s390x, remove the image directory. - if (($arch eq "s390x") && (-d "$imagedir") && (($method eq "raw") || ($method eq "netboot"))) { + if (($arch eq "s390x") && (-d "$imagedir") && (($method eq "raw") || ($method eq "netboot") || ($method eq "sysclone"))) { $callback->({info=>["Removing directory $imagedir"]}); rmtree "$imagedir"; } diff --git a/xCAT-server/share/xcat/scripts/xcatconf4z b/xCAT-server/share/xcat/scripts/xcatconf4z index 605433dfa..83eb026de 100644 --- a/xCAT-server/share/xcat/scripts/xcatconf4z +++ b/xCAT-server/share/xcat/scripts/xcatconf4z @@ -1,5 +1,4 @@ #!/bin/sh -# IBM(c) 2013 EPL license http://www.eclipse.org/legal/epl-v10.html ### BEGIN INIT INFO # Provides: xcatconf4z @@ -181,16 +180,20 @@ function setupIso { # @Output: # None # @Code: - # Create ISO based on transport directory iso="/var/opt/xcat/transport.iso" - /usr/bin/mkisofs -l -o $iso $transportdir - # Create loop back device pointing to ISO9660 image - nextLoopDev=`/sbin/losetup -f` - if [[ -n $nextLoopDev ]]; then - /sbin/losetup $nextLoopDev $iso - else - return + # If there are files in the transport directory then create an ISO system. + if [ "$(ls -A .)" ]; then + /usr/bin/mkisofs -l -o $iso $transportdir + fi + + # If the ISO filesystem exists then create loop back device pointing + # to the ISO9660 image + if [[ -e $iso ]]; then + nextLoopDev=`/sbin/losetup -f` + if [[ -n $nextLoopDev ]]; then + /sbin/losetup $nextLoopDev $iso + fi fi # Execute init script (if one exists) @@ -263,18 +266,20 @@ function setupDisk { return fi - out=`stat -L --printf=%t:%T $xcat_srcFile` + out=`/usr/bin/stat --printf=%n ${xcat_srcFile}` if (( $? != 0 )); then echo "xcatconf4z $funcName (Error) Unable to stat the source file: $xcat_srcFile" return fi - major=${out%:*} - major=$(echo ${major} | sed -e 's/^ *//g') - minor=${out#*:} - minor=$(echo ${minor} | sed -e 's/^ *//g') + configFile='/etc/udev/rules.d/56-zfcp.rules' + tgtNode=$(echo ${xcat_tgtFile} | sed -e 's/^\/dev\///') + wwpn_lun=$(echo ${xcat_srcFile} | sed -e 's/^\/dev.*-zfcp-//') + wwpn=$(echo ${wwpn_lun} | sed -e 's/:0x.*//') + lun=$(echo ${wwpn_lun} | sed -e 's/^0x.*://') - mknod $xcat_tgtFile b 0x$major 0x$minor + echo "KERNEL==\"sd*\", SYSFS{wwpn}==\"${wwpn}\", SYSFS{fcp_lun}==\"${lun}\", SYMLINK+=\"${tgtNode}%n\"" >> ${configFile} + udevadm trigger --sysname-match=sd* ########################################################################## # Handle removing a file system node @@ -289,8 +294,11 @@ function setupDisk { return fi - umount "$xcat_tgtFile" - rm -f "$xcat_tgtFile" + configFile='/etc/udev/rules.d/56-zfcp.rules' + tgtNode=$(echo ${xcat_tgtFile} | sed -e 's/^\/dev\///') + + sed -i -e /SYMLINK+=\"${tgtNode}%n\"/d ${configFile} + udevadm trigger --sysname-match=sd* ########################################################################## # Handle adding a SCSI volume @@ -463,22 +471,23 @@ function setupDisk { # Main Code Section ############################################################################ case "$1" in - start) - if [[ -z "$authorizedSenders" ]]; then - echo "xcatconf4z is disabled. There are no authorized senders of configuration files." - else - echo "xcatconf4z is starting" - transportdir="/var/opt/xcat/transport" - rm -Rf $transportdir - /bin/mkdir -p $transportdir - cd $transportdir - - # Get Linux version - getOsVersion - + start) + echo "xcatconf4z is starting" + transportdir="/var/opt/xcat/transport" + rm -Rf $transportdir + /bin/mkdir -p $transportdir + cd $transportdir + + # Get Linux version + getOsVersion + + if [[ -n "$authorizedSenders" ]]; then pullReader - setupIso - fi + else + echo "xcatconf4z is disabled from accepting configuration reader files." + fi + + setupIso ;; stop|status|restart|reload|force-reload) # Do nothing