From 617de03d136c9ea7f3ff17e78e9367274d6febeb Mon Sep 17 00:00:00 2001 From: xq2005 Date: Mon, 21 Oct 2013 01:08:59 -0700 Subject: [PATCH 01/20] delete 127.0.1.1 from /etc/hosts on ubuntu compute node --- xCAT-server/share/xcat/install/scripts/post.ubuntu | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/xCAT-server/share/xcat/install/scripts/post.ubuntu b/xCAT-server/share/xcat/install/scripts/post.ubuntu index 70583feb4..eb64b7e4b 100644 --- a/xCAT-server/share/xcat/install/scripts/post.ubuntu +++ b/xCAT-server/share/xcat/install/scripts/post.ubuntu @@ -188,6 +188,10 @@ elif [[ -r /boot/grub/grub.cfg ]] ; then update-grub fi sed -i 's/\(deb.*security.*\)/#\1/' /etc/apt/sources.list +#iso does not contains source deb packages +sed -i 's/^\(\s*deb-src.*install.*\)$/#\1/g' /etc/apt/sources.list +#delete the 127.0.1.1 line from /etc/hosts +sed -i '/127.0.1.1/d' /etc/hosts updateflag.awk $MASTER 3002 cd / #rm -Rf /xcatpost From 80ba0a46012991d6d475b99647a48060a3096f8f Mon Sep 17 00:00:00 2001 From: zhaoertao Date: Mon, 21 Oct 2013 02:51:36 -0700 Subject: [PATCH 02/20] fix bug 3774 :getmacs -D -V failed --- perl-xCAT/xCAT/PPCcli.pm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/perl-xCAT/xCAT/PPCcli.pm b/perl-xCAT/xCAT/PPCcli.pm index 3de42e5b8..b76a34c4d 100644 --- a/perl-xCAT/xCAT/PPCcli.pm +++ b/perl-xCAT/xCAT/PPCcli.pm @@ -139,7 +139,7 @@ sub connect { my $timeout = $req->{ppctimeout}; my $verbose = $req->{verbose}; my $ssh; - my $expect_log; + my $expect_log = "/dev/null"; my $errmsg; if ($req->{command} eq 'rflash') { @@ -170,7 +170,7 @@ sub connect { ################################################## if ( $verbose ) { close STDERR; - if ( !open( STDERR, '>', \$expect_log )) { + if ( !open( STDERR, '>', $expect_log )) { return( "Unable to redirect STDERR: $!" ); } } @@ -179,7 +179,7 @@ sub connect { ################################################## if ( $verbose ) { close STDOUT; - if ( !open( STDOUT, '>', \$expect_log )) { + if ( !open( STDOUT, '>', $expect_log )) { return( "Unable to redirect STDOUT: $!" ); } } From 81679ffdb9ea1339b5b2402f2e4bccb6b6a5efe7 Mon Sep 17 00:00:00 2001 From: lissav Date: Mon, 21 Oct 2013 11:28:50 -0400 Subject: [PATCH 03/20] defect 3819 --- xCAT/postscripts/xcatflowrequest | 57 +++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/xCAT/postscripts/xcatflowrequest b/xCAT/postscripts/xcatflowrequest index fc09d59d9..b8dd84ea1 100644 --- a/xCAT/postscripts/xcatflowrequest +++ b/xCAT/postscripts/xcatflowrequest @@ -4,9 +4,41 @@ # ready to process the request # It is called by xcatdsklspost before calling getpostscripts.awk # it is called by remoteshell before calling getcredentials.awk +# For example xcatflowrequest 3001 +# Returns +# 0 = good +# 1 = ping/nmap to ip address of master failed (TBD) +# 2 = xcatd never gave goahead +# + +# Here we will test to see if nmap is available +# if available we will use it to see if the daemon is available +# If not available we will use ping to the ip address +# If nmap or ping fail then +# we will return with exit 1 +# + + # check bash version, if < 4 then cannot use autodetect of next FD bashversion=$BASH_VERSION bashversionnum=`echo $bashversion | cut -d. -f1` + +# cleanup before exiting +cleanup() +{ +sleeper=$(cat /tmp/sleeperpid.$parpid) +sleeper=$(ps -ef|awk "\$3==$sleeper"|awk '{print $2}') +rm /tmp/goahead.$parpid +rm /tmp/sleeperpid.$parpid +rm /tmp/killme.$parpid +if [[ $bashversionnum > 3 ]]; then + exec {REMOTEFD}>&- +else + exec 50>&- +fi +kill -TERM $sleeper +} + if [[ $bashversionnum > 3 ]]; then exec {REMOTEFD}<>/dev/udp/$1/$2 else @@ -19,6 +51,8 @@ parpid=$$ touch /tmp/goahead.$parpid touch /tmp/killme.$parpid exec 2> /dev/null +RETRY=0 +MAX_RETRIES=50 while ! grep 'resourcerequest: ok' /tmp/goahead.$parpid > /dev/null; do ( echo "resourcerequest: xcatd" >&$REMOTEFD @@ -34,16 +68,15 @@ while ! grep 'resourcerequest: ok' /tmp/goahead.$parpid > /dev/null; do echo $! > /tmp/sleeperpid.$parpid exec awk '{print $0 > "/tmp/goahead.'$parpid'";exit}' <&$REMOTEFD exec {LOCALFD}>&- - ) + ) + # limit retries, if we reach the max error out + RETRY=$(($RETRY+1)) + if [ $RETRY -eq $MAX_RETRIES ] + then + cleanup + exit 2 + fi + done -sleeper=$(cat /tmp/sleeperpid.$parpid) -sleeper=$(ps -ef|awk "\$3==$sleeper"|awk '{print $2}') -rm /tmp/goahead.$parpid -rm /tmp/sleeperpid.$parpid -rm /tmp/killme.$parpid -if [[ $bashversionnum > 3 ]]; then - exec {REMOTEFD}>&- -else - exec 50>&- -fi -kill -TERM $sleeper +cleanup +exit 0 From ef75e82fe3ad54bf4919dde53ad95aa8506af0f1 Mon Sep 17 00:00:00 2001 From: Chuck Brazie Date: Mon, 21 Oct 2013 14:01:20 -0400 Subject: [PATCH 04/20] Merge zVM updates into xCAT 2.8.3 --- perl-xCAT/xCAT/Client.pm | 1254 -------------------- xCAT-server/lib/xcat/plugins/imgcapture.pm | 2 +- xCAT-server/lib/xcat/plugins/imgport.pm | 474 +++++--- xCAT-server/lib/xcat/plugins/rmimage.pm | 39 +- xCAT-server/share/xcat/scripts/xcatconf4z | 73 +- 5 files changed, 356 insertions(+), 1486 deletions(-) delete mode 100644 perl-xCAT/xCAT/Client.pm 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 From 66d62f7e65726529bc98562abe56a5805a7bfe83 Mon Sep 17 00:00:00 2001 From: Chuck Brazie Date: Mon, 21 Oct 2013 14:09:31 -0400 Subject: [PATCH 05/20] Adding file back in, not sure why it delted --- perl-xCAT/xCAT/Client.pm | 1254 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 1254 insertions(+) create mode 100644 perl-xCAT/xCAT/Client.pm diff --git a/perl-xCAT/xCAT/Client.pm b/perl-xCAT/xCAT/Client.pm new file mode 100644 index 000000000..e0934796d --- /dev/null +++ b/perl-xCAT/xCAT/Client.pm @@ -0,0 +1,1254 @@ +#!/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 + + + + + + From 42bc6cef0713d2e5a6683bb856e5680b0ce97a28 Mon Sep 17 00:00:00 2001 From: jjhua Date: Tue, 22 Oct 2013 10:07:08 -0400 Subject: [PATCH 06/20] code for OpenStack-Chef-Cookbook/xCAT integration --- xCAT-OpenStack/lib/perl/xCAT_plugin/cloud.pm | 194 +++++++++++++++++++ xCAT-server/lib/perl/xCAT/Postage.pm | 161 ++++++++++++++- 2 files changed, 353 insertions(+), 2 deletions(-) create mode 100644 xCAT-OpenStack/lib/perl/xCAT_plugin/cloud.pm diff --git a/xCAT-OpenStack/lib/perl/xCAT_plugin/cloud.pm b/xCAT-OpenStack/lib/perl/xCAT_plugin/cloud.pm new file mode 100644 index 000000000..826894886 --- /dev/null +++ b/xCAT-OpenStack/lib/perl/xCAT_plugin/cloud.pm @@ -0,0 +1,194 @@ +# IBM(c) 2010 EPL license http://www.eclipse.org/legal/epl-v10.html +package xCAT_plugin::cloud; +BEGIN +{ + $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; +} +use lib "$::XCATROOT/lib/perl"; + +use strict; +use xCAT::Table; +use Getopt::Long; +Getopt::Long::Configure("bundling"); +Getopt::Long::Configure("pass_through"); +#use xCAT::Utils; +#use xCAT::TableUtils; +use xCAT::Template; + + + +sub handled_commands +{ + return {makeclouddata => "cloud",}; +} + +############################################################ +# check_options will process the options for makeclouddata and +# give a usage error for any invalid options +############################################################ +sub check_options +{ + my $req = shift; + my $callback = shift; + my $rc = 0; + + Getopt::Long::Configure("bundling"); + $Getopt::Long::ignorecase = 0; + Getopt::Long::Configure("no_pass_through"); + + # Exit if the packet has been preprocessed + if ($req->{_xcatpreprocessed}->[0] == 1) { return [$req]; } + + # Save the arguements in ARGV for GetOptions + if ($req && $req->{arg}) { @ARGV = @{$req->{arg}}; } + else { @ARGV = (); } + + + # Parse the options for makedhcp + if (!GetOptions( + 'h|help' => \$::opt_h, + )) + { + # If the arguements do not pass GetOptions then issue error message and return + return -1; + } + + # display the usage if -h + if ($::opt_h) + { + return 1; + + } + + my $cloudlist =shift( @ARGV ); + + if( defined($cloudlist) ) { + my @clouds = split(",", $cloudlist); + $req->{clouds} = \@clouds; + } + + return 0; +} + +sub cloudvars { + + my $inf = shift; + my $outf = shift; + my $cloud = shift; + my $callback = shift; + my $outh; + my $inh; + open($inh,"<",$inf); + unless ($inh) { + my $rsp; + $rsp->{errorcode}->[0]=1; + $rsp->{error}->[0]="Unable to open $inf, aborting\n"; + $callback->($rsp); + return; + } + my $inc; + #First load input into memory.. + while (<$inh>) { + $inc.=$_; + } + close($inh); + $inc =~ s/\$CLOUD/$cloud/eg; + $inc =~ s/#TABLE:([^:]+):([^:]+):([^#]+)#/xCAT::Template::tabdb($1,$2,$3)/eg; + + open($outh,">",$outf); + unless($outh) { + my $rsp; + $rsp->{errorcode}->[0]=1; + $rsp->{error}->[0]="Unable to open $inf, aborting\n"; + $callback->($rsp); + return; + } + print $outh $inc; + close($outh); + return 0; +} + + +sub process_request +{ + my $req = shift; + my $callback = shift; + my $rc = 0; + + # define usage statement + my $usage="Usage: \n\tmkcloudata\n\tmakeclouddata \n\tmakeclouddata [-h|--help]"; + + $rc = check_options($req,$callback); + if ($rc == -1) { + my $rsp = {}; + $rsp->{data}->[0] = $usage; + xCAT::MsgUtils->message("E", $rsp, $callback, 1); + return; + } elsif ($rc == 1) { + my $rsp = {}; + $rsp->{data}->[0] = $usage; + xCAT::MsgUtils->message("I", $rsp, $callback, 0); + return; + } + + my $tab = "clouds"; + my $ptab = xCAT::Table->new("$tab"); + + unless ($ptab) { + my $rsp; + $rsp->{errorcode}->[0]=1; + $rsp->{error}->[0]="Unable to open $tab table"; + $callback->($rsp); + return; + } + + + my $t = $req->{clouds}; + my %h; + if( defined(@$t) ) { + %h = map { $_ => 1} @$t; + } + + my @cloudentries = $ptab->getAllAttribs('name', 'template', 'repository'); + + foreach my $cloudentry (@cloudentries) { + + my $cloud = $cloudentry->{name}; + if( %h ) { + # if makeclouddata , and + if( $h{$cloud} != 1) { + next; + } + } + + my $tmplfile = $cloudentry->{template}; + my $repos = $cloudentry->{repository}; + + unless ( -r "$tmplfile") { + my $rsp; + $rsp->{errorcode}->[0]=1; + $rsp->{error}->[0]="The $cloud environment template $tmplfile doesn't exist."; + $callback->($rsp); + next; + } + + unless ( -r "$repos") { + my $rsp; + $rsp->{errorcode}->[0]=1; + $rsp->{error}->[0]="The $cloud repository $repos doesn't exist."; + $callback->($rsp); + next; + } + + my $tmperr = cloudvars( + $tmplfile, + "$repos/environments/$cloud.rb", + $cloud, + $callback + ); + + } + return; +} + +1; diff --git a/xCAT-server/lib/perl/xCAT/Postage.pm b/xCAT-server/lib/perl/xCAT/Postage.pm index a3456a1b6..2d96b9498 100644 --- a/xCAT-server/lib/perl/xCAT/Postage.pm +++ b/xCAT-server/lib/perl/xCAT/Postage.pm @@ -213,6 +213,8 @@ sub makescript { $mn = xCAT::Utils->noderangecontainsMn(@$nodes); + my $cfgflag=0; + my $cloudflag=0; my $inc; my $t_inc; my %table; @@ -239,6 +241,14 @@ sub makescript { } } + if( $line =~ /#CFGMGTINFO_EXPORT#/ ) { + $cfgflag = 1; + } + if ($cfgflag == 1) { + if( $line =~ /#CLOUDINFO_EXPORT#/ ) { + $cloudflag = 1; + } + } } close($inh); @@ -334,7 +344,23 @@ sub makescript { # get all the nodes' setstate my $nodes_setstate_hash = getNodesSetState($nodes); - + + my $cfginfo_hash; + my $cloudinfo_hash; + # + # if #CFGCLIENTLIST_EXPORT# exists, ... + if( $cfgflag == 1 ) { + $cfginfo_hash = getcfginfo(); + # + # if #CLOUDINFO_EXPORT# exists, ... + if( $cloudflag == 1) { + $cloudinfo_hash = getcloudinfo(); + + } + } + + + foreach my $n (@$nodes ) { $node = $n; $inc = $t_inc; @@ -447,7 +473,15 @@ sub makescript { my $enablesshbetweennodes = enableSSHbetweennodes($node, \%::GLOBAL_SN_HASH, $groups_hash); - + my @clients; + my $cfgres; + my $cloudres; + if ( $cfgflag == 1 ) { + $cfgres = getcfgres($cfginfo_hash, $node, \@clients); + if ( $cloudflag == 1 ) { + $cloudres = getcloudres($cloudinfo_hash, \@clients); + } + } #ok, now do everything else.. #$inc =~ s/#XCATVAR:([^#]+)#/envvar($1)/eg; #$inc =~ s/#ENV:([^#]+)#/envvar($1)/eg; @@ -462,6 +496,9 @@ sub makescript { $inc =~ s/#NETWORK_FOR_DISKLESS_EXPORT#/$diskless_net_vars/eg; $inc =~ s/#INCLUDE_POSTSCRIPTS_LIST#/$postscripts/eg; $inc =~ s/#INCLUDE_POSTBOOTSCRIPTS_LIST#/$postbootscripts/eg; + + $inc =~ s/#CFGMGTINFO_EXPORT#/$cfgres/eg; + $inc =~ s/#CLOUDINFO_EXPORT#/$cloudres/eg; $inc =~ s/\$ENABLESSHBETWEENNODES/$enablesshbetweennodes/eg; $inc =~ s/\$NSETSTATE/$nodesetstate/eg; @@ -1699,7 +1736,127 @@ sub getPostbootScripts return $result; } +sub getcfginfo +{ + my %info = (); + my $tab = "cfgmgt"; + my $ptab = xCAT::Table->new($tab); + unless ($ptab) { + xCAT::MsgUtils->message("E", "Unable to open $tab table"); + return undef + } + my @rs = $ptab->getAllAttribs('node','cfgserver','roles'); + + foreach my $r ( @rs ) { + my $node = $r->{'node'}; + my $server = $r->{'cfgserver'}; + my $roles = $r->{'roles'}; + $info{ $server }{clientlist} .= "$node,"; + $info{ $node }{roles} = $roles; + + } + + return \%info; + + +} + +sub getcfgres +{ + my $cfginfo_hash = shift; + my $server = shift; + my $clients = shift; + my $cfgclient_list; + my $cfgres; + if( ! ( exists($cfginfo_hash->{$server}) && exists( $cfginfo_hash->{$server}->{clientlist} ) ) ) { + return $cfgres; + } + + $cfgclient_list = $cfginfo_hash->{$server}->{clientlist}; + chop $cfgclient_list; + $cfgres = "CFGCLIENTLIST='$cfgclient_list'\n"; + $cfgres .= "export CFGCLIENTLIST\n"; + @$clients = split(',', $cfgclient_list); + foreach my $client (@$clients) { + my $roles = $cfginfo_hash->{$client}->{roles}; + #$cfgres .= "hput $client roles $roles\n"; + $cfgres .= "HASH".$client."roles='$roles'\nexport HASH".$client."roles\n"; + } + + return $cfgres; +} + +sub getcloudinfo +{ + my %info = (); + + my $tab = "clouds"; + my $ptab = xCAT::Table->new($tab); + unless ($ptab) { + xCAT::MsgUtils->message("E", "Unable to open $tab table"); + return undef; + } + my @rs = $ptab->getAllAttribs('name','repository'); + + foreach my $r ( @rs ) { + my $cloud = $r->{'name'}; + my $repos = $r->{'repository'}; + $info{ $cloud }{repository} = $repos; + } + + $tab = "cloud"; + $ptab = xCAT::Table->new($tab); + unless ($ptab) { + xCAT::MsgUtils->message("E", "Unable to open $tab table"); + return undef; + } + @rs = $ptab->getAllAttribs('node','cloudname'); + + my $pre; + my $curr; + foreach my $r ( @rs ) { + my $node = $r->{'node'}; + my $cloud = $r->{'cloudname'}; + $info{ $node }{cloud} = $cloud; + } + + return \%info; +} + +sub getcloudres +{ + my $cloudinfo_hash = shift; + my $clients = shift; + my $cloudres; + my $cloudlist; + my $repos; + if( @$clients == 0 ) { + return $cloudres; + } + foreach my $client (@$clients) { + my $cloud; + if( defined($cloudinfo_hash) && defined($cloudinfo_hash->{$client}) ) { + $cloud = $cloudinfo_hash->{$client}->{cloud}; + } + #$cloudres .= "hput $client cloud $cloud\n"; + $cloudres .= "HASH".$client."cloud='$cloud'\nexport HASH".$client."cloud\n"; + $cloudlist .="$cloud,"; + + my $t = $cloudinfo_hash->{$cloud}->{repository}; + if( !defined($repos) ) { + $repos = $t; + } + if( defined($repos) && ( $repos != $t && "$repos/" != $t && $repos != "$t/" ) ) { + xCAT::MsgUtils->message("E", "Two cloud repositories: $repos and $t.\n There should be only one cloud repository one ont chef-server."); + return undef; + } + } + chop $cloudlist; + $cloudres = "REPOSITORY='$repos'\nexport REPOSITORY\nCLOUDLIST='$cloudlist'\nexport CLOUDLIST\n$cloudres"; + return $cloudres; +} + 1; From a77996e9339518bfcbba21b59fd1b548f79e434f Mon Sep 17 00:00:00 2001 From: jjhua Date: Tue, 22 Oct 2013 10:22:39 -0400 Subject: [PATCH 07/20] Postscripts for OpenStack-Chef-Cookbook/xCAT integration --- xCAT/postscripts/config_chef_client | 19 +- xCAT/postscripts/config_chef_server | 28 +++ xCAT/postscripts/config_chef_workstation | 21 ++- xCAT/postscripts/hashlib.sh | 16 ++ xCAT/postscripts/loadchefdata | 212 +++++++++++++++++++++++ xCAT/postscripts/mountinstall | 50 ++++++ 6 files changed, 340 insertions(+), 6 deletions(-) create mode 100755 xCAT/postscripts/hashlib.sh create mode 100755 xCAT/postscripts/loadchefdata create mode 100755 xCAT/postscripts/mountinstall diff --git a/xCAT/postscripts/config_chef_client b/xCAT/postscripts/config_chef_client index ac95062d5..4d06eca7f 100755 --- a/xCAT/postscripts/config_chef_client +++ b/xCAT/postscripts/config_chef_client @@ -30,16 +30,29 @@ if [ -z "$chef_server" ]; then chef_server=$CHEFSERVER fi if [ -z "$chef_server" ]; then - chef_server=$SITEMASTER + chef_server=$MASTER fi fi mkdir -p /etc/chef +mkdir -p /etc/chef-server_tmp + +mount $chef_server:/etc/chef-server /etc/chef-server_tmp +if [ $? -ne 0 ] +then + errmsg="Failed to run 'mount $chef_server:/etc/chef-server /etc/chef-server_tmp' on $node" + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 +fi + # copy the validator.pem to chef client -scp root@$chef_server:/etc/chef-server/chef-validator.pem /etc/chef/validation.pem - +#scp root@$chef_server:/etc/chef-server/chef-validator.pem /etc/chef/validation.pem +cp /etc/chef-server_tmp/chef-validator.pem /etc/chef/validation.pem +umount /etc/chef-server_tmp +rmdir /etc/chef-server_tmp # Add the info to /etc/chef/client.rb echo -e "log_level :auto diff --git a/xCAT/postscripts/config_chef_server b/xCAT/postscripts/config_chef_server index b59938de2..b1ac1ce15 100755 --- a/xCAT/postscripts/config_chef_server +++ b/xCAT/postscripts/config_chef_server @@ -25,4 +25,32 @@ then exit 1 fi +# for ubuntu +if [ -e "/etc/lsb-release" ] +then + apt-get install nfs-kernel-server portmap nfs-common -y + + grep "/etc/chef-server" /etc/exports + if [ $? -ne 0 ] + then + echo -e "\n/etc/chef-server *(rw,no_root_squash,sync,no_subtree_check)\n" >> /etc/exports + fi + sudo /etc/init.d/nfs-kernel-server restart + if [ $? -ne 0 ] + then + errmsg="Failed to run sudo /etc/init.d/nfs-kernel-server restart on $node" + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 + fi + service portmap restart + if [ $? -ne 0 ] + then + errmsg="Failed to run service portmap restart on $node" + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 + fi +fi + exit 0; diff --git a/xCAT/postscripts/config_chef_workstation b/xCAT/postscripts/config_chef_workstation index c17e41cf7..23c104acc 100755 --- a/xCAT/postscripts/config_chef_workstation +++ b/xCAT/postscripts/config_chef_workstation @@ -35,7 +35,7 @@ then fi if [ -z "$chefserver" ] then - chefserver=$SITEMASTER + chefserver=$MASTER fi fi @@ -78,8 +78,23 @@ then validation_key='/etc/chef-server/chef-validator.pem' else # Remote chef-server - scp $chefserver:/etc/chef-server/admin.pem $homedir/.chef 2>&1 1>/dev/null - scp $chefserver:/etc/chef-server/chef-validator.pem $homedir/.chef 2>&1 1>/dev/null + #scp $chefserver:/etc/chef-server/admin.pem $homedir/.chef 2>&1 1>/dev/null + #scp $chefserver:/etc/chef-server/chef-validator.pem $homedir/.chef 2>&1 1>/dev/null + mkdir -p /etc/chef + mkdir -p /etc/chef-server_tmp + + mount $chef_server:/etc/chef-server /etc/chef-server_tmp + if [ $? -ne 0 ] + then + errmsg="Failed to run 'mount $chef_server:/etc/chef-server /etc/chef-server_tmp' on $node" + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 + fi + cp /etc/chef-server_tmp/admin.pem $homedir/.chef 2>&1 1>/dev/null + cp /etc/chef-server_tmp/chef-validator.pem $homedir/.chef 2>&1 1>/dev/null + umount /etc/chef-server_tmp + rmdir /etc/chef-server_tmp if [ ! -e "$homedir/.chef/admin.pem" ] || [ ! -e "$homedir/.chef/chef-validator.pem" ] then errmsg="Could not get the chef keys from chef server $chefserver" diff --git a/xCAT/postscripts/hashlib.sh b/xCAT/postscripts/hashlib.sh new file mode 100755 index 000000000..78fb47c9e --- /dev/null +++ b/xCAT/postscripts/hashlib.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +## defined HASH functions here +hput() { + eval "HASH""$1""$2"='$3' +} + +hget() { + eval echo '${'"HASH$1$2"'}' +} + +hkeys() { + set | grep -o "^HASH${1}[[:alnum:]]*=" | sed -re "s/^HASH${1}(.*)=/\\1/g" +} + + diff --git a/xCAT/postscripts/loadchefdata b/xCAT/postscripts/loadchefdata new file mode 100755 index 000000000..41e525314 --- /dev/null +++ b/xCAT/postscripts/loadchefdata @@ -0,0 +1,212 @@ +#!/bin/sh +# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html + +# This script, ("loadchefdata"), is a sample xCAT post script for +# upload the openstack-cookbooks, roles, enviornment to the +# xCAT chef-server node, and then create the chef-client +# nodes, and then assign the role and environment name to the +# chef-client nodes +# +# Make sure your script is executable and that is is in the +# /install/postscripts directory on the xCAT management node. +# +# You must add the script name to the list of scripts that +# must be run at install time, or use it with updatenode. +# +# To use this script you should make sure it gets run after the +# "mountinstall" script or any other scipts that may need to use +# scripts in the /install directory. +# +# For example, to get it to run after the "mountinstall" script you +# could set the "postbootscripts" attribute of the chef-server node +# definitions as follows: +# +# chdef -t node -o chef-server postbootscripts="mountinstall,loadchefdata" +# + + +# load shell hash lib +source ./hashlib.sh + +#flags +no_args=0 +only_load_cookbook=0 +only_load_role=0 +only_load_clouddata=0 + +if [ $# -eq 0 ] +then + no_args=1 +else + for arg in "$@" + do + if [ "$arg" = "--cookbook" ] + then + only_load_cookbook=1 + elif [ "$arg" = "--role" ] + then + only_load_role=1 + elif [ "$arg" = "--clouddata" ] + then + only_load_clouddata=1 + else + errmsg="no argument $arg in the loadchefdata script" + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 + fi + done +fi + + + +# enter the repository director +# for example: cd /install/chef-cookbooks/grizzy-xcat/ +if [ ! -d "$REPOSITORY" ] +then + errmsg="$REPOSITORY is not a OpenStack Chef cookbooks directory." + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 +fi +cd $REPOSITORY + +if [ $no_args -eq 1 -o $only_load_cookbook -eq 1 ] +then + # upload coobooks + knife cookbook bulk delete '.*' -y > /dev/null 2>&1 + knife cookbook upload -o cookbooks --all + if [ $? != 0 ] + then + errmsg="Failed to run knife cookbook upload -o cookbooks --all on the chefserver $NODE." + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 + fi +fi + +if [ $no_args -eq 1 -o $only_load_role -eq 1 ] +then + # upload roles + knife role bulk delete '.*' -y > /dev/null 2>&1 + knife role from file roles/*.rb + if [ $? != 0 ] + then + errmsg="Failed to run knife role from file roles/*.rb on the chefserver $NODE." + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 + fi + +fi + + +if [ $no_args -eq 1 -o $only_load_clouddata -eq 1 ] +then + + if [ -z $CFGCLIENTLIST ] + then + msg="No cfgclient on the cfgserver $NODE?" + logger -t xcat -p local3.info $msg + echo $errmsg + exit 0 + fi + + #CLOUDLIST='cloud1,cloud1,cloud3' + OIFS=$IFS + IFS=',' + for cloud in $CLOUDLIST + do + echo "loading the enviornment file $cloud.rb for $cloud" + # knife environment delete xcat_per-tenant_routers_with_private_networks -y + # knife environment delete xcat_per-tenant_routers_with_private_networks -y + # load the environment file + # knife environment from file environments/xcat_per-tenant_routers_with_private_networks.rb + if [ ! -e "$REPOSITORY/environments/$cloud.rb" ] + then + errmsg="$REPOSITORY/environments/$cloud.rb doesn't exsit. run mkclouddata at first." + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 + fi + knife environment from file environments/$cloud.rb + if [ $? != 0 ] + then + errmsg="Failed to run knife environment from file environments/$cloud.rb on the chef-server $NODE." + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 + fi + done + #IFS=$OIFS + + #CFGCLIENTLIST='node1,node1,node3' + #OIFS=$IFS + #IFS=',' + for client in $CFGCLIENTLIST + do + echo "Configuring the chef-client node $client on the chef-server $NODE." + c_fullname="$client.$DOMAIN" + knife client delete -y $c_fullname > /dev/null 2>&1 + knife node delete -y $c_fullname > /dev/null 2>&1 + + #create nodes on this chef-server + # knife node create test3 -d + knife node create $c_fullname -d + if [ $? != 0 ] + then + errmsg="Failed to run knife node create $client -d on the chef-server $NODE." + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 + fi + + roles=`hget $client roles` + if [ -z $roles ] + then + errmsg="No roles for $client. Please check the cfgmgt table." + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 + fi + + # assign the role for the chef node + knife node run_list add $c_fullname "role[$roles]" + if [ $? != 0 ] + then + errmsg="Failed to run knife node run_list add $client 'role[$roles]' on the chef-server $NODE." + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 + fi + + # assign the new environment to the chef client node + newenv=`hget $client cloud` + if [ -z $newenv ] + then + errmsg="No cloud for $client. Please check the cloud table." + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 + fi + origenv=`knife node show $c_fullname -E | sed -e 's/[ ]*//g'| awk -F: '{print $2}'` + EDITOR="sed -e s/$origenv/$newenv/ -i" knife node edit $c_fullname + if [ $? != 0 ] + then + errmsg="Failed to run knife node edit $client on the chef-server $NODE." + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 + fi + + + done +fi + +IFS=$OIFS + + +exit 0 + + + diff --git a/xCAT/postscripts/mountinstall b/xCAT/postscripts/mountinstall new file mode 100755 index 000000000..1ac5f7412 --- /dev/null +++ b/xCAT/postscripts/mountinstall @@ -0,0 +1,50 @@ +#!/bin/sh +# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html + +# This script, ("mountinstall"), is a sample xCAT post script for +# mounting /install from managment node to xCAT chef-server +# nodes. +# +# Make sure your script is executable and that is is in the +# /install/postscripts directory on the xCAT management node. +# +# You must add the script name to the list of scripts that +# must be run at install time, or use it with updatenode. +# +# To use this script you should make sure it gets run before the +# "loadchefdata" script or any other scipts that may need to use +# scripts in the /install directory. +# +# For example, to get it to run before the "loadchefdata" script you +# could set the "postbootscripts" attribute of the chef-server node +# definitions as follows: +# +# chdef -t node -o chef-server postbootscripts="mountinstall,loadchefdata" +# + + +if [ -z "$INSTALLDIR" ]; then + INSTALLDIR="/install" +fi + + +mount | grep "$MASTER:$INSTALLDIR" +if [ $? -ne 0 ] +then + exit 0 +fi + + +# mount the files systems +mkdir /install + +mount $MASTER:$INSTALLDIR /install +if [ $? -ne 0 ] +then + errmsg="Failed to run mount $MASTER:$INSTALLDIR /install" + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 +fi + +exit 0 From e852d0b26411cb149f5ec14f2026b7a8a23eec8a Mon Sep 17 00:00:00 2001 From: jjhua Date: Tue, 22 Oct 2013 10:45:41 -0400 Subject: [PATCH 08/20] changes for the command makeclouddata --- xCAT-OpenStack/xCAT-OpenStack.spec | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/xCAT-OpenStack/xCAT-OpenStack.spec b/xCAT-OpenStack/xCAT-OpenStack.spec index 55e492145..363a5935a 100644 --- a/xCAT-OpenStack/xCAT-OpenStack.spec +++ b/xCAT-OpenStack/xCAT-OpenStack.spec @@ -28,11 +28,15 @@ management. %install mkdir -p $RPM_BUILD_ROOT/%{prefix}/lib/perl/xCAT_schema +mkdir -p $RPM_BUILD_ROOT/%{prefix}/lib/perl/xCAT_plugin cp -a lib/perl/xCAT_schema/* $RPM_BUILD_ROOT/%{prefix}/lib/perl/xCAT_schema find $RPM_BUILD_ROOT/%{prefix}/lib/perl/xCAT_schema -type d -exec chmod 755 {} \; find $RPM_BUILD_ROOT/%{prefix}/lib/perl/xCAT_schema -type f -exec chmod 644 {} \; +cp -a lib/perl/xCAT_plugin/* $RPM_BUILD_ROOT/%{prefix}/lib/perl/xCAT_plugin + +ln -sf ../bin/xcatclientnnr $RPM_BUILD_ROOT/%{prefix}/sbin/makeclouddata %clean rm -rf $RPM_BUILD_ROOT From f8daa39253f79633c0c5fdad1ffb4ed456707c11 Mon Sep 17 00:00:00 2001 From: jjhua Date: Tue, 22 Oct 2013 13:25:45 -0400 Subject: [PATCH 09/20] fixed a minor problem --- xCAT/postscripts/mountinstall | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xCAT/postscripts/mountinstall b/xCAT/postscripts/mountinstall index 1ac5f7412..bf8a0fe86 100755 --- a/xCAT/postscripts/mountinstall +++ b/xCAT/postscripts/mountinstall @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -vx # IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html # This script, ("mountinstall"), is a sample xCAT post script for @@ -28,8 +28,8 @@ if [ -z "$INSTALLDIR" ]; then fi -mount | grep "$MASTER:$INSTALLDIR" -if [ $? -ne 0 ] +mount | grep "$MASTER:$INSTALLDIR on /install" +if [ $? -eq 0 ] then exit 0 fi From d464001ca138d51ab8dfa23e906e1946a3dd8a37 Mon Sep 17 00:00:00 2001 From: jjhua Date: Tue, 22 Oct 2013 14:29:56 -0400 Subject: [PATCH 10/20] Add the chef-client to invoke the config_chef_client script --- xCAT/postscripts/chef-client | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100755 xCAT/postscripts/chef-client diff --git a/xCAT/postscripts/chef-client b/xCAT/postscripts/chef-client new file mode 100755 index 000000000..834b78f3f --- /dev/null +++ b/xCAT/postscripts/chef-client @@ -0,0 +1,20 @@ +#!/bin/sh + +#This script will invoke the config_chef_client directly. +#If the chef-server and chef-client are installed successfully at first, +#and then on the chef-server node configure the software for the chef-client nodes. +#We can run +# updatenode chef-client +#To configure the softare on the chef-client node. + +./config_chef_client + +if [ $? -ne 0 ] +then + errmsg="Failed to run the postscript ./config_chef_client on $node" + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 +fi + +exit 0; From bcd72b4040c111b1bcbb6b76bf02e15579306310 Mon Sep 17 00:00:00 2001 From: immarvin Date: Tue, 22 Oct 2013 00:57:14 -0700 Subject: [PATCH 11/20] fix defect #3626 yaboot.pm needs to use pkgdir --- xCAT-server/lib/xcat/plugins/yaboot.pm | 43 +++++++++++++++++--------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/xCAT-server/lib/xcat/plugins/yaboot.pm b/xCAT-server/lib/xcat/plugins/yaboot.pm index fda2ccb33..cc8863de3 100644 --- a/xCAT-server/lib/xcat/plugins/yaboot.pm +++ b/xCAT-server/lib/xcat/plugins/yaboot.pm @@ -194,7 +194,7 @@ sub setstate { close($pcfg); my $inetn = xCAT::NetworkUtils->getipaddr($node); unless ($inetn) { - syslog("local4|err","xCAT unable to resolve IP for $node in yaboot plugin"); + syslog("local1|err","xCAT unable to resolve IP for $node in yaboot plugin"); return; } } else { #TODO: actually, should possibly default to xCAT image? @@ -252,7 +252,7 @@ sub setstate { close($pcfg); my $inetn = xCAT::NetworkUtils->getipaddr($node); unless ($inetn) { - syslog("local4|err","xCAT unable to resolve IP for $node in yaboot plugin"); + syslog("local1|err","xCAT unable to resolve IP for $node in yaboot plugin"); return; } } else { #TODO: actually, should possibly default to xCAT image? @@ -261,7 +261,7 @@ sub setstate { } my $ip = xCAT::NetworkUtils->getipaddr($node); unless ($ip) { - syslog("local4|err","xCAT unable to resolve IP in yaboot plugin"); + syslog("local1|err","xCAT unable to resolve IP in yaboot plugin"); return; } my $mactab = xCAT::Table->new('mac'); @@ -500,8 +500,9 @@ sub process_request { my $nrtab=xCAT::Table->new('noderes',-create=>1); my $nrhash=$nrtab->getNodesAttribs(\@nodes,['servicenode']); my $typetab=xCAT::Table->new('nodetype',-create=>1); - my $typehash=$typetab->getNodesAttribs(\@nodes,['os','provmethod']); + my $typehash=$typetab->getNodesAttribs(\@nodes,['os','provmethod','arch','profile']); my $linuximgtab=xCAT::Table->new('linuximage',-create=>1); + my $osimagetab=xCAT::Table->new('osimage',-create=>1); my $rc; my $errstr; @@ -538,15 +539,22 @@ sub process_request { my @normalnodeset = keys %normalnodes; my @breaknetboot=keys %breaknetbootnodes; #print "yaboot:inittime=$inittime; normalnodeset=@normalnodeset; breaknetboot=@breaknetboot\n"; - my %oshash; + my %osimagenodehash; for my $nn (@normalnodeset){ #record the os version for node - my $ent = $typehash->{$nn}->[0]; - my $os = $ent->{'os'}; - push @{$oshash{$os}}, $nn; + my $ent = $typehash->{$nn}->[0]; + my $osimage=$ent->{'provmethod'}; + if($osimage =~ /^(install|netboot|statelite)$/){ + $osimage=($ent->{'os'}).'-'.($ent->{'arch'}).'-'.($ent->{'provmethod'}).'-'.($ent->{'profile'}); + } + push @{$osimagenodehash{$osimage}}, $nn; } - foreach my $os (keys %oshash) { + + foreach my $osimage (keys %osimagenodehash) { + my $osimgent = $osimagetab->getAttribs({imagename => $osimage },'osvers'); + my $os = $osimgent->{'osvers'}; + my $osv; my $osn; my $osm; @@ -560,6 +568,7 @@ sub process_request { $osn = $2; $osm = 0; } + if (($osv =~ /rh/ and int($osn) < 6) or ($osv =~ /sles/ and int($osn) < 11)) { # check if xcat-yaboot installed @@ -582,16 +591,20 @@ sub process_request { xCAT::MsgUtils->message("E", $rsp, $callback); return; } - my $yabootpath = $tftpdir."/yb/".$os; - mkpath $yabootpath; + my $yabootpath = $tftpdir."/yb/".$os; + mkpath $yabootpath; + + my $linuximgent = $linuximgtab->getAttribs({imagename => $osimage},'pkgdir'); + my @pkgdirlist = split /,/, $linuximgent->{'pkgdir'}; + my $pkgdir = $pkgdirlist[0]; + $pkgdir =~ s/\/+$//; + my $yabootfile; if ($os =~ /sles/) { - my $installdir = $::XCATSITEVALS{'installdir'} ? $::XCATSITEVALS{'installdir'} : "/install"; - $yabootfile = $installdir."/".$os."/ppc64/1/suseboot/yaboot"; + $yabootfile = $pkgdir."/1/suseboot/yaboot"; } elsif ($os =~ /rh/){ - my $installdir = $::XCATSITEVALS{'installdir'} ? $::XCATSITEVALS{'installdir'} : "/install"; - $yabootfile = $installdir."/".$os."/ppc64/ppc/chrp/yaboot"; + $yabootfile = $pkgdir."/ppc/chrp/yaboot"; } unless (-e "$yabootfile") { my $rsp; From 105b54d4cdb9161f12226dfc72d6578f7604d154 Mon Sep 17 00:00:00 2001 From: immarvin Date: Tue, 22 Oct 2013 04:53:02 -0700 Subject: [PATCH 12/20] fix defect #3626 yaboot.pm needs to use pkgdir --- xCAT-server/lib/xcat/plugins/yaboot.pm | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/xCAT-server/lib/xcat/plugins/yaboot.pm b/xCAT-server/lib/xcat/plugins/yaboot.pm index cc8863de3..f3de6d60b 100644 --- a/xCAT-server/lib/xcat/plugins/yaboot.pm +++ b/xCAT-server/lib/xcat/plugins/yaboot.pm @@ -625,7 +625,7 @@ sub process_request { return; } } - } #end of foreach oshash + } #end of foreach osimagenodehash #Don't bother to try dhcp binding changes if sub_req not passed, i.e. service node build time unless (($args[0] eq 'stat') || ($inittime) || ($args[0] eq 'offline')) { @@ -642,8 +642,11 @@ sub process_request { #} if ($do_dhcpsetup) { - if (%oshash) { - foreach my $osentry (keys %oshash) { + if (%osimagenodehash) { + foreach my $osimage (keys %osimagenodehash) { + my $osimgent = $osimagetab->getAttribs({imagename => $osimage },'osvers'); + my $osentry = $osimgent->{'osvers'}; + my $osv; my $osn; my $osm; @@ -662,20 +665,20 @@ sub process_request { my $fpath = "/yb/". $osentry."/yaboot"; if ($request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command $sub_req->({command=>['makedhcp'], - node=>\@{$oshash{$osentry}}, + node=>\@{$osimagenodehash{$osimage}}, arg=>['-l','-s','filename = \"'.$fpath.'\";']},$callback); } else { $sub_req->({command=>['makedhcp'], - node=>\@{$oshash{$osentry}}, + node=>\@{$osimagenodehash{$osimage}}, arg=>['-s','filename = \"'.$fpath.'\";']},$callback); } } else { if ($request->{'_disparatetftp'}->[0]) { #reading hint from preprocess_command, only change local settings if already farmed $sub_req->({command=>['makedhcp'],arg=>['-l'], - node=>\@{$oshash{$osentry}}},$callback); + node=>\@{$osimagenodehash{$osimage}}},$callback); } else { $sub_req->({command=>['makedhcp'], - node=>\@{$oshash{$osentry}}},$callback); + node=>\@{$osimagenodehash{$osimage}}},$callback); } } } From 06e244202b8d06842fdf014dac2a85713481b63c Mon Sep 17 00:00:00 2001 From: immarvin Date: Tue, 22 Oct 2013 05:11:27 -0700 Subject: [PATCH 13/20] correct xcat-yaboot in error message to yaboot-xcat --- xCAT-server/lib/xcat/plugins/yaboot.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xCAT-server/lib/xcat/plugins/yaboot.pm b/xCAT-server/lib/xcat/plugins/yaboot.pm index f3de6d60b..2e71b594d 100644 --- a/xCAT-server/lib/xcat/plugins/yaboot.pm +++ b/xCAT-server/lib/xcat/plugins/yaboot.pm @@ -571,12 +571,12 @@ sub process_request { if (($osv =~ /rh/ and int($osn) < 6) or ($osv =~ /sles/ and int($osn) < 11)) { - # check if xcat-yaboot installed + # check if yaboot-xcat installed my $yf = $tftpdir . "/yaboot"; unless (-e $yf) { my $rsp; push @{$rsp->{data}}, - "stop configuration because xcat-yaboot need to be installed for $os.\n"; + "stop configuration because yaboot-xcat need to be installed for $os.\n"; xCAT::MsgUtils->message("E", $rsp, $callback); return; } From 3243037a918374ae92919410c38122f1adc06e23 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Mon, 21 Oct 2013 10:44:15 -0400 Subject: [PATCH 14/20] For newer versions of esxi for which we have selected a less vague name, ensure we remake it every time. --- xCAT-server/lib/xcat/plugins/esx.pm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xCAT-server/lib/xcat/plugins/esx.pm b/xCAT-server/lib/xcat/plugins/esx.pm index 235264205..1f4af072e 100644 --- a/xCAT-server/lib/xcat/plugins/esx.pm +++ b/xCAT-server/lib/xcat/plugins/esx.pm @@ -4514,12 +4514,12 @@ sub makecustomizedmod { my $modname; if ($osver =~ /esxi4/) { #want more descriptive name,but don't break esxi4 setups. $modname="mod.tgz"; + # if it already exists, do not overwrite it because it may be someone + # else's custom image + if(-f "$dest/$modname"){ return 1; } } else { $modname="xcatmod.tgz"; } - # if it already exists, do not overwrite it because it may be someone - # else's custom image - if(-f "$dest/$modname"){ return 1; } my $passtab = xCAT::Table->new('passwd'); my $tmp; my $password; From 50a853c96eccca20e28422b43a18999dbf338f37 Mon Sep 17 00:00:00 2001 From: daniceexi Date: Wed, 23 Oct 2013 14:00:09 -0400 Subject: [PATCH 15/20] add more kernel modules of scsi for localdisk support --- xCAT-server/share/xcat/netboot/sles/genimage | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xCAT-server/share/xcat/netboot/sles/genimage b/xCAT-server/share/xcat/netboot/sles/genimage index aa3eda6d6..3a11a8d3f 100755 --- a/xCAT-server/share/xcat/netboot/sles/genimage +++ b/xCAT-server/share/xcat/netboot/sles/genimage @@ -804,7 +804,7 @@ if (@new_order) { } # add drivers for local disk support -push @ndrivers, ("ext3.ko", "ext4.ko", "virtio_pci.ko", "virtio_blk.ko", "ata_piix.ko", "libata.ko", "scsi_mod.ko", "ibmvscsi.ko", "ibmvscsic.ko", "megaraid_sas.ko", "pcieport.ko", "sd_mod.ko"); +push @ndrivers, ("ext3.ko", "ext4.ko", "virtio_pci.ko", "virtio_blk.ko", "ata_piix.ko", "libata.ko", "scsi_mod.ko", "scsi_dh.ko", "ahci.ko", "ibmvscsi.ko", "ibmvscsic.ko", "megaraid_sas.ko", "pcieport.ko", "sd_mod.ko"); open($moddeps,"<","$rootimg_dir/lib/modules/$kernelver/modules.dep"); my @moddeps = <$moddeps>; From 4e59b13e0f5c9b28427d2db536d99d4c2ef026c2 Mon Sep 17 00:00:00 2001 From: jjhua Date: Wed, 23 Oct 2013 22:41:15 -0400 Subject: [PATCH 16/20] move out the code to read cloud/clouds table from Postage.pm to Cloud.pm in xCAT-OpenStack. Move out the loadchefdata script. --- xCAT-OpenStack/lib/perl/xCAT/Cloud.pm | 158 +++++++++++++++++++ xCAT-server/lib/perl/xCAT/Postage.pm | 174 +++++++++++---------- xCAT/postscripts/hashlib.sh | 16 -- xCAT/postscripts/loadchefdata | 212 -------------------------- xCAT/postscripts/mountinstall | 2 +- 5 files changed, 249 insertions(+), 313 deletions(-) create mode 100644 xCAT-OpenStack/lib/perl/xCAT/Cloud.pm delete mode 100755 xCAT/postscripts/hashlib.sh delete mode 100755 xCAT/postscripts/loadchefdata diff --git a/xCAT-OpenStack/lib/perl/xCAT/Cloud.pm b/xCAT-OpenStack/lib/perl/xCAT/Cloud.pm new file mode 100644 index 000000000..171b7ad4b --- /dev/null +++ b/xCAT-OpenStack/lib/perl/xCAT/Cloud.pm @@ -0,0 +1,158 @@ +# IBM(c) 2013 EPL license http://www.eclipse.org/legal/epl-v10.html +package xCAT::Cloud; + +BEGIN +{ + $::XCATROOT = + $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} + : -d '/opt/xcat' ? '/opt/xcat' + : '/usr'; +} +use lib "$::XCATROOT/lib/perl"; +use xCAT::Table; +use xCAT::MsgUtils; +use xCAT::NodeRange; +use xCAT::Utils; +use xCAT::TableUtils; +#use Data::Dumper; +use strict; + + + +#----------------------------------------------------------------------------- + +=head3 getcloudinfo + + This function will be invoked by Postage.pm. + get the chef cookbook repository for each cloud from the clouds table, and + then get all the node --> cloud from the cloud table. The two type information + will be stored in the %info + + If success, return the \%info. + + + Arguments: + none + Returns: + \%info + + Error: + none + Example: + + Comments: + none + +=cut + +#----------------------------------------------------------------------------- + + +sub getcloudinfo +{ + my %info = (); + + my $tab = "clouds"; + my $ptab = xCAT::Table->new($tab); + unless ($ptab) { + xCAT::MsgUtils->message("E", "Unable to open $tab table"); + return undef; + } + my @rs = $ptab->getAllAttribs('name','repository'); + + foreach my $r ( @rs ) { + my $cloud = $r->{'name'}; + my $repos = $r->{'repository'}; + $info{ $cloud }{repository} = $repos; + } + + $tab = "cloud"; + $ptab = xCAT::Table->new($tab); + unless ($ptab) { + xCAT::MsgUtils->message("E", "Unable to open $tab table"); + return undef; + } + @rs = $ptab->getAllAttribs('node','cloudname'); + + my $pre; + my $curr; + foreach my $r ( @rs ) { + my $node = $r->{'node'}; + my $cloud = $r->{'cloudname'}; + $info{ $node }{cloud} = $cloud; + } + + return \%info; + + + +} + + +#----------------------------------------------------------------------------- + +=head3 getcloudres + + This function will be invoked by Postage.pm. And it's only for one chef-server. + 1. get the chef cookbook repository for the clouds on one chef-server. + All the clouds's repositoryies on one chef-server should be the same one. + 2. get the cloud list for one chef-server + 3. get the cloud name for each node on the same chef-server + + + Arguments: + $cloudinfo_hash -- This is from the getcloudinfo function. + $clients -- an array which stores different cloud nodes(chef-client) + Returns: + $cloudres -- a string including cloud information + + Error: + none + Example: + + Comments: + none + +=cut + +#----------------------------------------------------------------------------- + + + +sub getcloudres +{ + my $cloudinfo_hash = shift; + my $clients = shift; + my $cloudres; + my $cloudlist; + my $repos; + if( @$clients == 0 ) { + return $cloudres; + } + foreach my $client (@$clients) { + my $cloud; + if( defined($cloudinfo_hash) && defined($cloudinfo_hash->{$client}) ) { + $cloud = $cloudinfo_hash->{$client}->{cloud}; + } + #$cloudres .= "hput $client cloud $cloud\n"; + $cloudres .= "HASH".$client."cloud='$cloud'\nexport HASH".$client."cloud\n"; + if ( $cloudlist !~ $cloud ) { + $cloudlist .="$cloud,"; + } + + my $t = $cloudinfo_hash->{$cloud}->{repository}; + if( !defined($repos) ) { + $repos = $t; + } + if( defined($repos) && ( $repos != $t && "$repos/" != $t && $repos != "$t/" ) ) { + xCAT::MsgUtils->message("E", "Two cloud repositories: $repos and $t.\n There should be only one cloud repository one ont chef-server."); + return undef; + } + } + chop $cloudlist; + $cloudres = "REPOSITORY='$repos'\nexport REPOSITORY\nCLOUDLIST='$cloudlist'\nexport CLOUDLIST\n$cloudres"; + return $cloudres; +} + + +1; diff --git a/xCAT-server/lib/perl/xCAT/Postage.pm b/xCAT-server/lib/perl/xCAT/Postage.pm index 2d96b9498..0ff0066df 100644 --- a/xCAT-server/lib/perl/xCAT/Postage.pm +++ b/xCAT-server/lib/perl/xCAT/Postage.pm @@ -223,6 +223,11 @@ sub makescript { #First load input into memory.. while (<$inh>) { my $line = $_; + + if( $line =~ /#INCLUDE:[^#^\n]+#/ ) { + $line =~ s/#INCLUDE:([^#^\n]+)#/includetmpl($1)/eg; + } + if ($line !~/^##/ ) { $t_inc.=$line; } @@ -241,14 +246,11 @@ sub makescript { } } + if( $line =~ /#CFGMGTINFO_EXPORT#/ ) { $cfgflag = 1; } - if ($cfgflag == 1) { - if( $line =~ /#CLOUDINFO_EXPORT#/ ) { - $cloudflag = 1; - } - } + } close($inh); @@ -347,20 +349,25 @@ sub makescript { my $cfginfo_hash; my $cloudinfo_hash; + $cfginfo_hash = getcfginfo(); # - # if #CFGCLIENTLIST_EXPORT# exists, ... - if( $cfgflag == 1 ) { - $cfginfo_hash = getcfginfo(); - # - # if #CLOUDINFO_EXPORT# exists, ... - if( $cloudflag == 1) { - $cloudinfo_hash = getcloudinfo(); - - } + #check it the cloud module exists or not + #the default doesn't exist. + my $cloud_exists = 0; + my $cloud_module_name="xCAT::Cloud"; + eval("use $cloud_module_name;"); + if (!$@) { + $cloud_exists = 1; + if( $cfgflag == 0) { + my $rsp; + $rsp->{errorcode}->[0]=1; + $rsp->{error}->[0]="xCAT-OpenStack needs the tag #CFGMGTINFO_EXPORT# in $tmpl.\n"; + $callback->($rsp); + return; + } + $cloudinfo_hash = getcloudinfo($cloud_module_name, $cloud_exists); } - - - + foreach my $n (@$nodes ) { $node = $n; $inc = $t_inc; @@ -476,12 +483,11 @@ sub makescript { my @clients; my $cfgres; my $cloudres; - if ( $cfgflag == 1 ) { - $cfgres = getcfgres($cfginfo_hash, $node, \@clients); - if ( $cloudflag == 1 ) { - $cloudres = getcloudres($cloudinfo_hash, \@clients); - } + $cfgres = getcfgres($cfginfo_hash, $node, \@clients); + if ( $cloud_exists == 1 ) { + $cloudres = getcloudres($cloud_module_name, $cloud_exists, $cloudinfo_hash, \@clients); } + #ok, now do everything else.. #$inc =~ s/#XCATVAR:([^#]+)#/envvar($1)/eg; #$inc =~ s/#ENV:([^#]+)#/envvar($1)/eg; @@ -1788,75 +1794,75 @@ sub getcfgres sub getcloudinfo { - my %info = (); - my $tab = "clouds"; - my $ptab = xCAT::Table->new($tab); - unless ($ptab) { - xCAT::MsgUtils->message("E", "Unable to open $tab table"); - return undef; + my $module_name = shift; + my $cloud_exists = shift; + my $result; + + #get cloud info + if ( $cloud_exists ) { + no strict "refs"; + if (defined(${$module_name."::"}{getcloudinfo})) { + $result=${$module_name."::"}{getcloudinfo}(); + } } - my @rs = $ptab->getAllAttribs('name','repository'); + return $result; +} - foreach my $r ( @rs ) { - my $cloud = $r->{'name'}; - my $repos = $r->{'repository'}; - $info{ $cloud }{repository} = $repos; - } - - $tab = "cloud"; - $ptab = xCAT::Table->new($tab); - unless ($ptab) { - xCAT::MsgUtils->message("E", "Unable to open $tab table"); - return undef; - } - @rs = $ptab->getAllAttribs('node','cloudname'); - - my $pre; - my $curr; - foreach my $r ( @rs ) { - my $node = $r->{'node'}; - my $cloud = $r->{'cloudname'}; - $info{ $node }{cloud} = $cloud; - } - - return \%info; - - - -} sub getcloudres { + my $module_name = shift; + my $cloud_exists = shift; my $cloudinfo_hash = shift; - my $clients = shift; - my $cloudres; - my $cloudlist; - my $repos; - if( @$clients == 0 ) { - return $cloudres; - } - foreach my $client (@$clients) { - my $cloud; - if( defined($cloudinfo_hash) && defined($cloudinfo_hash->{$client}) ) { - $cloud = $cloudinfo_hash->{$client}->{cloud}; - } - #$cloudres .= "hput $client cloud $cloud\n"; - $cloudres .= "HASH".$client."cloud='$cloud'\nexport HASH".$client."cloud\n"; - $cloudlist .="$cloud,"; - - my $t = $cloudinfo_hash->{$cloud}->{repository}; - if( !defined($repos) ) { - $repos = $t; - } - if( defined($repos) && ( $repos != $t && "$repos/" != $t && $repos != "$t/" ) ) { - xCAT::MsgUtils->message("E", "Two cloud repositories: $repos and $t.\n There should be only one cloud repository one ont chef-server."); - return undef; - } - } - chop $cloudlist; - $cloudres = "REPOSITORY='$repos'\nexport REPOSITORY\nCLOUDLIST='$cloudlist'\nexport CLOUDLIST\n$cloudres"; - return $cloudres; + my $clients = shift; + my $result; + + #get cloud res + if ( $cloud_exists ) { + no strict "refs"; + if (defined(${$module_name."::"}{getcloudres})) { + $result=${$module_name."::"}{getcloudres}($cloudinfo_hash, $clients); + } + } + return $result; } +## +# +#This function only can be used for #INCLUDE:filepath# in mypostscript.tmpl . +#It doesn't support the #INCLUDE:filepath# in the new $file. So it doesn't +#support the repeated include. +#It will put all the content of the file into @text excetp the empty line +sub includetmpl +{ + my $file = shift; + my @text = (); + + if ( ! -r $file ) { + return ""; + } + + open(INCLUDE, $file) || \return ""; + + while () + { + chomp($_); #remove newline + s/\s+$//; #remove trailing spaces + next if /^\s*$/; #-- skip empty lines + if (/^@(.*)/) + { #for groups that has space in name + my $save = $1; + if ($1 =~ / /) { $_ = "\@" . $save; } + } + push(@text, $_); + } + + close(INCLUDE); + + return join(',', @text); +} + + + 1; diff --git a/xCAT/postscripts/hashlib.sh b/xCAT/postscripts/hashlib.sh deleted file mode 100755 index 78fb47c9e..000000000 --- a/xCAT/postscripts/hashlib.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -## defined HASH functions here -hput() { - eval "HASH""$1""$2"='$3' -} - -hget() { - eval echo '${'"HASH$1$2"'}' -} - -hkeys() { - set | grep -o "^HASH${1}[[:alnum:]]*=" | sed -re "s/^HASH${1}(.*)=/\\1/g" -} - - diff --git a/xCAT/postscripts/loadchefdata b/xCAT/postscripts/loadchefdata deleted file mode 100755 index 41e525314..000000000 --- a/xCAT/postscripts/loadchefdata +++ /dev/null @@ -1,212 +0,0 @@ -#!/bin/sh -# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html - -# This script, ("loadchefdata"), is a sample xCAT post script for -# upload the openstack-cookbooks, roles, enviornment to the -# xCAT chef-server node, and then create the chef-client -# nodes, and then assign the role and environment name to the -# chef-client nodes -# -# Make sure your script is executable and that is is in the -# /install/postscripts directory on the xCAT management node. -# -# You must add the script name to the list of scripts that -# must be run at install time, or use it with updatenode. -# -# To use this script you should make sure it gets run after the -# "mountinstall" script or any other scipts that may need to use -# scripts in the /install directory. -# -# For example, to get it to run after the "mountinstall" script you -# could set the "postbootscripts" attribute of the chef-server node -# definitions as follows: -# -# chdef -t node -o chef-server postbootscripts="mountinstall,loadchefdata" -# - - -# load shell hash lib -source ./hashlib.sh - -#flags -no_args=0 -only_load_cookbook=0 -only_load_role=0 -only_load_clouddata=0 - -if [ $# -eq 0 ] -then - no_args=1 -else - for arg in "$@" - do - if [ "$arg" = "--cookbook" ] - then - only_load_cookbook=1 - elif [ "$arg" = "--role" ] - then - only_load_role=1 - elif [ "$arg" = "--clouddata" ] - then - only_load_clouddata=1 - else - errmsg="no argument $arg in the loadchefdata script" - logger -t xcat -p local4.err $errmsg - echo $errmsg - exit 1 - fi - done -fi - - - -# enter the repository director -# for example: cd /install/chef-cookbooks/grizzy-xcat/ -if [ ! -d "$REPOSITORY" ] -then - errmsg="$REPOSITORY is not a OpenStack Chef cookbooks directory." - logger -t xcat -p local4.err $errmsg - echo $errmsg - exit 1 -fi -cd $REPOSITORY - -if [ $no_args -eq 1 -o $only_load_cookbook -eq 1 ] -then - # upload coobooks - knife cookbook bulk delete '.*' -y > /dev/null 2>&1 - knife cookbook upload -o cookbooks --all - if [ $? != 0 ] - then - errmsg="Failed to run knife cookbook upload -o cookbooks --all on the chefserver $NODE." - logger -t xcat -p local4.err $errmsg - echo $errmsg - exit 1 - fi -fi - -if [ $no_args -eq 1 -o $only_load_role -eq 1 ] -then - # upload roles - knife role bulk delete '.*' -y > /dev/null 2>&1 - knife role from file roles/*.rb - if [ $? != 0 ] - then - errmsg="Failed to run knife role from file roles/*.rb on the chefserver $NODE." - logger -t xcat -p local4.err $errmsg - echo $errmsg - exit 1 - fi - -fi - - -if [ $no_args -eq 1 -o $only_load_clouddata -eq 1 ] -then - - if [ -z $CFGCLIENTLIST ] - then - msg="No cfgclient on the cfgserver $NODE?" - logger -t xcat -p local3.info $msg - echo $errmsg - exit 0 - fi - - #CLOUDLIST='cloud1,cloud1,cloud3' - OIFS=$IFS - IFS=',' - for cloud in $CLOUDLIST - do - echo "loading the enviornment file $cloud.rb for $cloud" - # knife environment delete xcat_per-tenant_routers_with_private_networks -y - # knife environment delete xcat_per-tenant_routers_with_private_networks -y - # load the environment file - # knife environment from file environments/xcat_per-tenant_routers_with_private_networks.rb - if [ ! -e "$REPOSITORY/environments/$cloud.rb" ] - then - errmsg="$REPOSITORY/environments/$cloud.rb doesn't exsit. run mkclouddata at first." - logger -t xcat -p local4.err $errmsg - echo $errmsg - exit 1 - fi - knife environment from file environments/$cloud.rb - if [ $? != 0 ] - then - errmsg="Failed to run knife environment from file environments/$cloud.rb on the chef-server $NODE." - logger -t xcat -p local4.err $errmsg - echo $errmsg - exit 1 - fi - done - #IFS=$OIFS - - #CFGCLIENTLIST='node1,node1,node3' - #OIFS=$IFS - #IFS=',' - for client in $CFGCLIENTLIST - do - echo "Configuring the chef-client node $client on the chef-server $NODE." - c_fullname="$client.$DOMAIN" - knife client delete -y $c_fullname > /dev/null 2>&1 - knife node delete -y $c_fullname > /dev/null 2>&1 - - #create nodes on this chef-server - # knife node create test3 -d - knife node create $c_fullname -d - if [ $? != 0 ] - then - errmsg="Failed to run knife node create $client -d on the chef-server $NODE." - logger -t xcat -p local4.err $errmsg - echo $errmsg - exit 1 - fi - - roles=`hget $client roles` - if [ -z $roles ] - then - errmsg="No roles for $client. Please check the cfgmgt table." - logger -t xcat -p local4.err $errmsg - echo $errmsg - exit 1 - fi - - # assign the role for the chef node - knife node run_list add $c_fullname "role[$roles]" - if [ $? != 0 ] - then - errmsg="Failed to run knife node run_list add $client 'role[$roles]' on the chef-server $NODE." - logger -t xcat -p local4.err $errmsg - echo $errmsg - exit 1 - fi - - # assign the new environment to the chef client node - newenv=`hget $client cloud` - if [ -z $newenv ] - then - errmsg="No cloud for $client. Please check the cloud table." - logger -t xcat -p local4.err $errmsg - echo $errmsg - exit 1 - fi - origenv=`knife node show $c_fullname -E | sed -e 's/[ ]*//g'| awk -F: '{print $2}'` - EDITOR="sed -e s/$origenv/$newenv/ -i" knife node edit $c_fullname - if [ $? != 0 ] - then - errmsg="Failed to run knife node edit $client on the chef-server $NODE." - logger -t xcat -p local4.err $errmsg - echo $errmsg - exit 1 - fi - - - done -fi - -IFS=$OIFS - - -exit 0 - - - diff --git a/xCAT/postscripts/mountinstall b/xCAT/postscripts/mountinstall index bf8a0fe86..62097e469 100755 --- a/xCAT/postscripts/mountinstall +++ b/xCAT/postscripts/mountinstall @@ -19,7 +19,7 @@ # could set the "postbootscripts" attribute of the chef-server node # definitions as follows: # -# chdef -t node -o chef-server postbootscripts="mountinstall,loadchefdata" +# chdef -t node -o chef-server postbootscripts="mountinstall,loadclouddata" # From 7cff2524011e0c8203a8481b74b574bb3d97c4ab Mon Sep 17 00:00:00 2001 From: jjhua Date: Wed, 23 Oct 2013 22:56:17 -0400 Subject: [PATCH 17/20] add the loadclouddata, share/xcat/mypostscript/mypostscript_cloud.tmpl into xCAT-OpenStack --- xCAT-OpenStack/postscripts/loadclouddata | 224 ++++++++++++++++++ xCAT-OpenStack/sbin/makeclouddata | 56 +++++ .../xcat/mypostscript/mypostscript_cloud.tmpl | 1 + xCAT-OpenStack/xCAT-OpenStack.spec | 22 +- .../share/xcat/mypostscript/mypostscript.tmpl | 4 + 5 files changed, 306 insertions(+), 1 deletion(-) create mode 100755 xCAT-OpenStack/postscripts/loadclouddata create mode 100755 xCAT-OpenStack/sbin/makeclouddata create mode 100644 xCAT-OpenStack/share/xcat/mypostscript/mypostscript_cloud.tmpl diff --git a/xCAT-OpenStack/postscripts/loadclouddata b/xCAT-OpenStack/postscripts/loadclouddata new file mode 100755 index 000000000..5e27bd25d --- /dev/null +++ b/xCAT-OpenStack/postscripts/loadclouddata @@ -0,0 +1,224 @@ +#!/bin/sh +# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html + +# This script, ("loadclouddata"), is a sample xCAT post script for +# upload the openstack-cookbooks, roles, enviornment to the +# xCAT chef-server node, and then create the chef-client +# nodes, and then assign the role and environment name to the +# chef-client nodes +# +# Make sure your script is executable and that is is in the +# /install/postscripts directory on the xCAT management node. +# +# You must add the script name to the list of scripts that +# must be run at install time, or use it with updatenode. +# +# To use this script you should make sure it gets run after the +# "mountinstall" script or any other scipts that may need to use +# scripts in the /install directory. +# +# For example, to get it to run after the "mountinstall" script you +# could set the "postbootscripts" attribute of the chef-server node +# definitions as follows: +# +# chdef -t node -o chef-server postbootscripts="mountinstall,loadclouddata" +# + + +## defined HASH functions here +hput() { + eval "HASH""$1""$2"='$3' +} + +hget() { + eval echo '${'"HASH$1$2"'}' +} + +hkeys() { + set | grep -o "^HASH${1}[[:alnum:]]*=" | sed -re "s/^HASH${1}(.*)=/\\1/g" +} + + + +#flags +no_args=0 +only_load_cookbook=0 +only_load_role=0 +only_load_clouddata=0 + +if [ $# -eq 0 ] +then + no_args=1 +else + for arg in "$@" + do + if [ "$arg" = "--cookbook" ] + then + only_load_cookbook=1 + elif [ "$arg" = "--role" ] + then + only_load_role=1 + elif [ "$arg" = "--clouddata" ] + then + only_load_clouddata=1 + else + errmsg="no argument $arg in the loadchefdata script" + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 + fi + done +fi + + + +# enter the repository director +# for example: cd /install/chef-cookbooks/grizzy-xcat/ +if [ ! -d "$REPOSITORY" ] +then + errmsg="$REPOSITORY is not a OpenStack Chef cookbooks directory." + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 +fi +cd $REPOSITORY + +if [ $no_args -eq 1 -o $only_load_cookbook -eq 1 ] +then + # upload coobooks + knife cookbook bulk delete '.*' -y > /dev/null 2>&1 + knife cookbook upload -o cookbooks --all + if [ $? != 0 ] + then + errmsg="Failed to run knife cookbook upload -o cookbooks --all on the chefserver $NODE." + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 + fi +fi + +if [ $no_args -eq 1 -o $only_load_role -eq 1 ] +then + # upload roles + knife role bulk delete '.*' -y > /dev/null 2>&1 + knife role from file roles/*.rb + if [ $? != 0 ] + then + errmsg="Failed to run knife role from file roles/*.rb on the chefserver $NODE." + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 + fi + +fi + + +if [ $no_args -eq 1 -o $only_load_clouddata -eq 1 ] +then + + if [ -z $CFGCLIENTLIST ] + then + msg="No cfgclient on the cfgserver $NODE?" + logger -t xcat -p local3.info $msg + echo $errmsg + exit 0 + fi + + #CLOUDLIST='cloud1,cloud1,cloud3' + OIFS=$IFS + IFS=',' + for cloud in $CLOUDLIST + do + echo "loading the enviornment file $cloud.rb for $cloud" + # knife environment delete xcat_per-tenant_routers_with_private_networks -y + # knife environment delete xcat_per-tenant_routers_with_private_networks -y + # load the environment file + # knife environment from file environments/xcat_per-tenant_routers_with_private_networks.rb + if [ ! -e "$REPOSITORY/environments/$cloud.rb" ] + then + errmsg="$REPOSITORY/environments/$cloud.rb doesn't exsit. run mkclouddata at first." + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 + fi + knife environment from file environments/$cloud.rb + if [ $? != 0 ] + then + errmsg="Failed to run knife environment from file environments/$cloud.rb on the chef-server $NODE." + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 + fi + done + #IFS=$OIFS + + #CFGCLIENTLIST='node1,node1,node3' + #OIFS=$IFS + #IFS=',' + for client in $CFGCLIENTLIST + do + echo "Configuring the chef-client node $client on the chef-server $NODE." + c_fullname="$client.$DOMAIN" + knife client delete -y $c_fullname > /dev/null 2>&1 + knife node delete -y $c_fullname > /dev/null 2>&1 + + #create nodes on this chef-server + # knife node create test3 -d + knife node create $c_fullname -d + if [ $? != 0 ] + then + errmsg="Failed to run knife node create $client -d on the chef-server $NODE." + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 + fi + + roles=`hget $client roles` + if [ -z $roles ] + then + errmsg="No roles for $client. Please check the cfgmgt table." + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 + fi + + # assign the role for the chef node + knife node run_list add $c_fullname "role[$roles]" + if [ $? != 0 ] + then + errmsg="Failed to run knife node run_list add $client 'role[$roles]' on the chef-server $NODE." + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 + fi + + # assign the new environment to the chef client node + newenv=`hget $client cloud` + if [ -z $newenv ] + then + errmsg="No cloud for $client. Please check the cloud table." + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 + fi + origenv=`knife node show $c_fullname -E | sed -e 's/[ ]*//g'| awk -F: '{print $2}'` + EDITOR="sed -e s/$origenv/$newenv/ -i" knife node edit $c_fullname + if [ $? != 0 ] + then + errmsg="Failed to run knife node edit $client on the chef-server $NODE." + logger -t xcat -p local4.err $errmsg + echo $errmsg + exit 1 + fi + + + done +fi + +IFS=$OIFS + + +exit 0 + + + diff --git a/xCAT-OpenStack/sbin/makeclouddata b/xCAT-OpenStack/sbin/makeclouddata new file mode 100755 index 000000000..583d7c549 --- /dev/null +++ b/xCAT-OpenStack/sbin/makeclouddata @@ -0,0 +1,56 @@ +#!/usr/bin/env perl +# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html + +# Used as a standard client cmd that can be used for xcat cmds that do not have +# noderange as an argument. See xcatclient for additional documentation. + +# To put the cloud command only in xCAT-OpenStack, just copy the ../bin/xcatclientnnr +# as makeclouddata command here. we couldn't sym link the command makecloudata +# to this script ../bin/xcatclientnnr in xCAT-OpenStack.spec. + +BEGIN { $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : -d '/opt/xcat' ? '/opt/xcat' : '/usr'; } +use lib "$::XCATROOT/lib/perl"; +use Cwd; +use File::Basename; +use xCAT::Client; +use strict; + +my $bname = basename($0); +my $cmdref; +if ($bname =~ /xcatclientnnr/) { $cmdref->{command}->[0]=shift @ARGV; } # xcatclientnnr was invoked directly and the 1st arg is cmd name that is used to locate the plugin +else { $cmdref->{command}->[0] = $bname; } # the cmd was sym linked to xcatclientnnr +$cmdref->{cwd}->[0] = cwd(); +my $data; +# allows our plugins to get the stdin of the cmd that invoked the plugin +if ( (($^O =~ /^linux/i) && ($ENV{'SHELL'} =~ /\/ksh$/)) || !defined($ENV{'TERM'}) ) +{ + my $rout; + my $rin=""; + vec($rin,fileno(STDIN),1)=1; + my $nfound=select($rout=$rin,"","",1); + if ($nfound) + { + while ( ) { $data.=$_; } + $cmdref->{stdin}->[0]=$data; + } +} +else +{ + if (-p STDIN) { + while ( ) { $data.=$_; } + $cmdref->{stdin}->[0]=$data; + } +} + + +push (@{$cmdref->{arg}}, @ARGV); +foreach (keys %ENV) { + if (/^XCAT_/) { + $cmdref->{environment}->{$_} = $ENV{$_}; + } +} + +xCAT::Client::submit_request($cmdref,\&xCAT::Client::handle_response); +exit $xCAT::Client::EXITCODE; + + diff --git a/xCAT-OpenStack/share/xcat/mypostscript/mypostscript_cloud.tmpl b/xCAT-OpenStack/share/xcat/mypostscript/mypostscript_cloud.tmpl new file mode 100644 index 000000000..1a1554069 --- /dev/null +++ b/xCAT-OpenStack/share/xcat/mypostscript/mypostscript_cloud.tmpl @@ -0,0 +1 @@ +#CLOUDINFO_EXPORT# diff --git a/xCAT-OpenStack/xCAT-OpenStack.spec b/xCAT-OpenStack/xCAT-OpenStack.spec index 363a5935a..ce73bb671 100644 --- a/xCAT-OpenStack/xCAT-OpenStack.spec +++ b/xCAT-OpenStack/xCAT-OpenStack.spec @@ -29,20 +29,40 @@ management. %install mkdir -p $RPM_BUILD_ROOT/%{prefix}/lib/perl/xCAT_schema mkdir -p $RPM_BUILD_ROOT/%{prefix}/lib/perl/xCAT_plugin +mkdir -p $RPM_BUILD_ROOT/%{prefix}/lib/perl/xCAT +mkdir -p $RPM_BUILD_ROOT/install/postscripts +mkdir -p $RPM_BUILD_ROOT/%{prefix}/share/xcat/mypostscript +mkdir -p $RPM_BUILD_ROOT/%{prefix}/sbin cp -a lib/perl/xCAT_schema/* $RPM_BUILD_ROOT/%{prefix}/lib/perl/xCAT_schema find $RPM_BUILD_ROOT/%{prefix}/lib/perl/xCAT_schema -type d -exec chmod 755 {} \; find $RPM_BUILD_ROOT/%{prefix}/lib/perl/xCAT_schema -type f -exec chmod 644 {} \; cp -a lib/perl/xCAT_plugin/* $RPM_BUILD_ROOT/%{prefix}/lib/perl/xCAT_plugin +chmod 644 $RPM_BUILD_ROOT/%{prefix}/lib/perl/xCAT_plugin/* -ln -sf ../bin/xcatclientnnr $RPM_BUILD_ROOT/%{prefix}/sbin/makeclouddata +cp -a lib/perl/xCAT/* $RPM_BUILD_ROOT/%{prefix}/lib/perl/xCAT +chmod 644 $RPM_BUILD_ROOT/%{prefix}/lib/perl/xCAT/* + +cp sbin/* $RPM_BUILD_ROOT/%{prefix}/sbin +chmod 755 $RPM_BUILD_ROOT/%{prefix}/sbin/* + + +#ln -sf ../bin/xcatclientnnr $RPM_BUILD_ROOT/%{prefix}/sbin/makeclouddata + +#cd - +cp -a postscripts/* $RPM_BUILD_ROOT/install/postscripts +chmod 755 $RPM_BUILD_ROOT/install/postscripts/* + +cp -a share/xcat/mypostscript/* $RPM_BUILD_ROOT/%{prefix}/share/xcat/mypostscript +chmod 644 $RPM_BUILD_ROOT/%{prefix}/share/xcat/mypostscript/* %clean rm -rf $RPM_BUILD_ROOT %files %{prefix} +/install/postscripts %defattr(-,root,root) diff --git a/xCAT-server/share/xcat/mypostscript/mypostscript.tmpl b/xCAT-server/share/xcat/mypostscript/mypostscript.tmpl index 05e07433c..1dd311b95 100755 --- a/xCAT-server/share/xcat/mypostscript/mypostscript.tmpl +++ b/xCAT-server/share/xcat/mypostscript/mypostscript.tmpl @@ -121,6 +121,10 @@ export CFGMGR CFGSERVER=#TABLE:cfgmgt:$NODE:cfgserver# export CFGSERVER +#CFGMGTINFO_EXPORT# + +#INCLUDE:/opt/xcat/share/xcat/mypostscript/mypostscript_cloud.tmpl# + ## ##The line postscripts-start-here must not be deleted. From 67f5b9c8084e71b3473f6a9300d01c3d86b4eeae Mon Sep 17 00:00:00 2001 From: daniceexi Date: Wed, 23 Oct 2013 15:01:40 -0400 Subject: [PATCH 18/20] change the position to run localdisk script that put it before killing udev. For stateless only. --- xCAT-server/share/xcat/netboot/sles/genimage | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xCAT-server/share/xcat/netboot/sles/genimage b/xCAT-server/share/xcat/netboot/sles/genimage index 3a11a8d3f..22fcc24d4 100755 --- a/xCAT-server/share/xcat/netboot/sles/genimage +++ b/xCAT-server/share/xcat/netboot/sles/genimage @@ -1374,6 +1374,7 @@ EOMS print $inifile " exit\n"; print $inifile "fi\n"; + print $inifile "\$NEWROOT/etc/init.d/localdisk\n"; # to run the localdisk # udevd needed by s390x for networking # but for other type of machine, udevd will affect the start of devices which detected # after the chroot, so kill it before the switching root @@ -1382,7 +1383,6 @@ EOMS } print $inifile "cd /\n"; - print $inifile "\$NEWROOT/etc/init.d/localdisk\n"; # to run the localdisk print $inifile "mkdir \$NEWROOT/var/lib/dhcpcd/\n"; #neccessary for SLES11, not sure for SLES10 print $inifile "cp /var/lib/dhcpcd/* \$NEWROOT/var/lib/dhcpcd/\n"; print $inifile "cp /etc/resolv.conf \$NEWROOT/etc/\n"; From 857af4d4983a9942d5fb397443ba74ca5a0eeab0 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Wed, 23 Oct 2013 11:15:04 -0400 Subject: [PATCH 19/20] Send a positive acknowledgement of flow request --- xCAT-server/sbin/xcatd | 1 + 1 file changed, 1 insertion(+) diff --git a/xCAT-server/sbin/xcatd b/xCAT-server/sbin/xcatd index 85d05da73..ec8f2b3f2 100755 --- a/xCAT-server/sbin/xcatd +++ b/xCAT-server/sbin/xcatd @@ -694,6 +694,7 @@ sleep 0.05; store_fd({data=>$data,sockaddr=>$saddr},$discoctl); } else { # for *now*, we'll do a tiny YAML subset if ($data =~ /^resourcerequest: xcatd$/) { + $socket->send("ackresourcerequest\n",0,$packets{$pkey}->[0]); $tcclients->{$pkey}={ sockaddr=>$packets{$pkey}->[0], timestamp=>time() } } } # JSON maybe one day if important From 3bf30fcc3851ea60e2242a39428e9405b45f8ce3 Mon Sep 17 00:00:00 2001 From: lissav Date: Wed, 23 Oct 2013 13:50:05 -0400 Subject: [PATCH 20/20] defect 3851- handle multiple MN in DB --- perl-xCAT/xCAT/DSHCLI.pm | 16 +++++++++---- perl-xCAT/xCAT/ServiceNodeUtils.pm | 13 ++++++----- xCAT-server/lib/perl/xCAT/Postage.pm | 4 ++-- xCAT-server/lib/xcat/plugins/updatenode.pm | 7 +++--- xCAT-server/sbin/xcatconfig | 26 +++++++++++++--------- 5 files changed, 40 insertions(+), 26 deletions(-) diff --git a/perl-xCAT/xCAT/DSHCLI.pm b/perl-xCAT/xCAT/DSHCLI.pm index ecdb2b4c3..73d1a9232 100644 --- a/perl-xCAT/xCAT/DSHCLI.pm +++ b/perl-xCAT/xCAT/DSHCLI.pm @@ -3237,7 +3237,14 @@ sub bld_resolve_nodes_hash # find out if we have an MN in the list, local cp and sh will be used # not remote shell - my $mname = xCAT::Utils->noderangecontainsMn(@target_list); + # find out the names for the Management Node + my @MNnodeinfo = xCAT::NetworkUtils->determinehostname; + my $mname = pop @MNnodeinfo; # hostname + #my $rsp = {}; + #$rsp->{info}->[0] = + # "Management node name is $mname."; + # xCAT::MsgUtils->message("I", $rsp, $::CALLBACK); + foreach my $target (@target_list) { @@ -4079,11 +4086,12 @@ sub parse_and_run_dsh # check if any node in the noderange is the Management Node and exit # with error, if the Management Node is in the Database and in the # noderange - my $mname = xCAT::Utils->noderangecontainsMn(@nodelist); - if ($mname) { # MN in the nodelist + my @mname = xCAT::Utils->noderangecontainsMn(@nodelist); + if (@mname) { # MN in the nodelist + my $nodes=join(',', @mname); my $rsp = {}; $rsp->{error}->[0] = - "You must not run -K option against the Management Node:$mname."; + "You must not run -K option against the Management Node:$nodes."; xCAT::MsgUtils->message("E", $rsp, $::CALLBACK, 1); return; } diff --git a/perl-xCAT/xCAT/ServiceNodeUtils.pm b/perl-xCAT/xCAT/ServiceNodeUtils.pm index 5bcf6508b..28bf81a98 100644 --- a/perl-xCAT/xCAT/ServiceNodeUtils.pm +++ b/perl-xCAT/xCAT/ServiceNodeUtils.pm @@ -242,12 +242,13 @@ sub getAllSN # if did not input "ALL" and there is a MN, remove it my @newservicenodes; if ((!defined($options)) || ($options ne "ALL")) { - my $mname = xCAT::Utils->noderangecontainsMn(@servicenodes); - if ($mname) { # if there is a MN - foreach my $nodes (@servicenodes) { - if ($mname ne ($nodes)){ - push @newservicenodes, $nodes; - } + my @mname = xCAT::Utils->noderangecontainsMn(@servicenodes); + if (@mname) { # if there is a MN + foreach my $node (@servicenodes) { + # check to see if node in MN list + if (!(grep(/^$node$/, @mname))) { # if node not in the MN array + push @newservicenodes, $node; + } } $servicenodetab->close; return @newservicenodes; # return without the MN in the array diff --git a/xCAT-server/lib/perl/xCAT/Postage.pm b/xCAT-server/lib/perl/xCAT/Postage.pm index 0ff0066df..250c28eb8 100644 --- a/xCAT-server/lib/perl/xCAT/Postage.pm +++ b/xCAT-server/lib/perl/xCAT/Postage.pm @@ -211,7 +211,7 @@ sub makescript { return; } - $mn = xCAT::Utils->noderangecontainsMn(@$nodes); + @::mn = xCAT::Utils->noderangecontainsMn(@$nodes); my $cfgflag=0; my $cloudflag=0; @@ -652,7 +652,7 @@ sub getNodeType my $node = shift; my $result; - if ( $node =~ /^$mn$/) { + if (grep(/^$node$/, @::mn)) { # is it in the Management Node array $result="MN"; return $result; } diff --git a/xCAT-server/lib/xcat/plugins/updatenode.pm b/xCAT-server/lib/xcat/plugins/updatenode.pm index 3162d71fa..6adc76019 100644 --- a/xCAT-server/lib/xcat/plugins/updatenode.pm +++ b/xCAT-server/lib/xcat/plugins/updatenode.pm @@ -396,12 +396,13 @@ sub preprocess_updatenode # check to see if the Management Node is in the noderange and # if it is abort - my $mname = xCAT::Utils->noderangecontainsMn(@$nodes); - if ($mname) + my @mname = xCAT::Utils->noderangecontainsMn(@$nodes); + if (@mname) { # MN in the nodelist + my $nodes=join(',', @mname); my $rsp = {}; $rsp->{error}->[0] = - "You must not run -k option against the Management Node:$mname."; + "You must not run -k option against a management node: $nodes."; xCAT::MsgUtils->message("E", $rsp, $callback, 1); return; } diff --git a/xCAT-server/sbin/xcatconfig b/xCAT-server/sbin/xcatconfig index 5d0aa1191..f9d0b428a 100755 --- a/xCAT-server/sbin/xcatconfig +++ b/xCAT-server/sbin/xcatconfig @@ -2124,23 +2124,27 @@ sub setupMNinDB my $defined = 0; my $cmds="XCATBYPASS=Y $::XCATROOT/sbin/tabdump nodelist | grep __mgmtnode"; - my $output = xCAT::Utils->runcmd("$cmds", -1); + my @output = xCAT::Utils->runcmd("$cmds", -1); + if ($::RUNCMD_RC == 0) # found a management node defined { my $chtabcmds; - my @mn = split(",", $output); + my @mn = split(",", $output[0]); $mn[0] =~ s/"//g; # remove the quotes if ($mn[0] ne $mnname) { # does not match current host name,delete it - $chtabcmds = "$::XCATROOT/sbin/chtab -d node=$mn[0] nodelist;"; - my $outref = xCAT::Utils->runcmd("$chtabcmds", 0); - if ($::RUNCMD_RC != 0) - { - xCAT::MsgUtils->message('E', "Could not run $chtabcmds."); - return; - } + my $size=@output; # if more than one management node defined, do not remove any + if ($size == 1) { + $chtabcmds = "$::XCATROOT/sbin/chtab -d node=$mn[0] nodelist;"; + my $outref = xCAT::Utils->runcmd("$chtabcmds", 0); + if ($::RUNCMD_RC != 0) + { + xCAT::MsgUtils->message('E', "Could not run $chtabcmds."); + return; + } + } } else { # it is defined and good - xCAT::MsgUtils->message('I', "$mnname already defined in the nodelist table."); - $defined=1; + xCAT::MsgUtils->message('I', "$mnname already defined in the nodelist table."); + $defined=1; } } # now add with the new name , if not already there