# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html #------------------------------------------------------- =head1 xCAT plugin package to handle rinstall and winstall Supported command: rinstall - runs nodeset, rsetboot,rpower commands winstall - also opens the console =cut #------------------------------------------------------- package xCAT_plugin::rinstall; use strict; require xCAT::Utils; require xCAT::MsgUtils; use xCAT::NodeRange; use xCAT::Table; use Data::Dumper; use Getopt::Long; #------------------------------------------------------- =head3 handled_commands Return list of commands handled by this plugin =cut #------------------------------------------------------- sub handled_commands { return { rinstall => "rinstall", winstall => "rinstall", }; } #------------------------------------------------------- =head3 Process the command =cut #------------------------------------------------------- sub process_request { my $request = shift; my $callback = shift; my $subreq = shift; rinstall($request, $callback, $subreq); } #------------------------------------------------------- =head3 rinstall Wrapper around nodeset, rsetboot, rpower for the admin convenience =cut #------------------------------------------------------- sub rinstall { my ($req, $callback, $subreq) = @_; $::CALLBACK=$callback; my $OSVER; my $PROFILE; my $ARCH; my $CONSOLE; my $OSIMAGE; my $HELP; my $VERSION; my $command = $req->{command}->[0]; # could be rinstall on winstall my $args; if (defined($req->{arg}) ) { # there are arguments $args=$req->{arg}; # argument @ARGV = @{$args}; } my $nodes; my @nodes; if (defined ($req->{node})) { # there are nodes $nodes = $req->{node}; @nodes=@$nodes; } # no arguments, no nodes then input wrong if ((scalar(@nodes) == 0) && (scalar(@ARGV) == 0)){ &usage($command,$callback); return 1; } #print Dumper($req); Getopt::Long::Configure("bundling"); unless ( GetOptions( 'o|osver=s' => \$OSVER, 'p|profile=s' => \$PROFILE, 'a|arch=s' => \$ARCH, 'O|osimage=s' => \$OSIMAGE, 'h|help' => \$HELP, 'v|version' => \$VERSION, 'c|console' => \$CONSOLE ) ) { &usage($command,$callback); return 1; } if ($HELP) { &usage($command,$callback); return 0; } if ($VERSION) { my $version = xCAT::Utils->Version(); my $rsp = {}; $rsp->{data}->[0] = "$version"; xCAT::MsgUtils->message("I", $rsp, $callback); return (0); } if (scalar @$nodes eq 0) { my $rsp = {}; $rsp->{error}->[0] ="noderange not supplied"; xCAT::MsgUtils->message("E", $rsp, $callback); return 1; } my $rc = 0; my %pnhash; if ($OSIMAGE) { # -O|--osimage is specified, ignore any -a,-p,-o options, # call "nodeset ... osimage= ..." to set the boot state of the noderange to the specified osimage, # "nodeset" will handle the updating of node attributes such as os,arch,profile,provmethod # verify input &checkoption("[-O|--osimage] $OSIMAGE",$OSVER,$PROFILE,$ARCH,$callback); # run nodeset $noderange osimage=$OSIMAGE my @osimageargs; push @osimageargs,"osimage=$OSIMAGE" ; my $res = xCAT::Utils->runxcmd( { command => ["nodeset"], node => \@nodes, arg => \@osimageargs }, $subreq, -1, 1); my $rsp = {}; if ($::RUNCMD_RC ==0 ) { foreach my $line (@$res) { $rsp->{data} ->[0] = $line; xCAT::MsgUtils->message("I", $rsp, $callback); } } else { foreach my $line (@$res) { $rsp->{error} ->[0] = $line; xCAT::MsgUtils->message("E", $rsp, $callback); } return 1; } } else { # no osimage specified, update the node attributes specified by -a,-p,-o options thru "nodech", # then set the boot state of each node based on the nodetype.provmethod: # 1) if nodetype.provmethod = , ignore any -p,-o,-a option, # then call "nodeset ... osimage" # 2) if nodetype.provmethod = [install/netboot/statelite], # update the node attributes specified by -a,-p,-o options thru "nodech", # call "nodeset ... [install/netboot/statelite]" # 3) if nodetype.provmethod is not set, use 'install' as the default value # group the nodes according to the nodetype.provmethod foreach (@$nodes) { my $tab = xCAT::Table->new("nodetype"); my $nthash = $tab->getNodeAttribs($_, ['provmethod']); $tab->close(); if (defined($nthash) and defined($nthash->{'provmethod'})) { push(@{$pnhash{$nthash->{'provmethod'}}}, $_); } else { #if nodetype.provmethod is not specified, push(@{$pnhash{'install'}}, $_); } } # Now for each group based on provmethod foreach my $key (keys %pnhash) { $::RUNCMD_RC =0; my $nodes = join(',', @{$pnhash{$key}}); if ($key =~ /^(install|netboot|statelite)$/) { # nodetype.provmethod = [install|netboot|statelite] my @nodechline; if ($OSVER) { push @nodechline, "nodetype.os=$OSVER"; } if ($PROFILE) { push @nodechline, "nodetype.profile=$PROFILE"; } if ($ARCH) { push @nodechline, "nodetype.arch=$ARCH"; } if (@nodechline) { # run nodech $nodes $nodechline my $res = xCAT::Utils->runxcmd( { command => ["nodech"], node => \@nodes, arg => \@nodechline }, $subreq, -1, 1); my $rsp = {}; $rc=$::RUNCMD_RC; if ($rc == 0 ) { foreach my $line (@$res) { $rsp->{data} ->[0] = $line; xCAT::MsgUtils->message("I", $rsp, $callback); } } else { # error $rsp->{error} ->[0] = "nodech error"; xCAT::MsgUtils->message("E", $rsp, $callback); foreach my $line (@$res) { $rsp->{error} ->[0] = $line; xCAT::MsgUtils->message("E", $rsp, $callback); } } } # end nodechline if ($rc == 0) # if no error from nodech then run nodeset { # run nodeset $nodes $key ( where key is install/netboot/statelite) my @nodesetarg; push @nodesetarg, "$key"; my $res = xCAT::Utils->runxcmd( { command => ["nodeset"], node => \@nodes, arg => \@nodesetarg }, $subreq, -1, 1); my $rsp = {}; $rc=$::RUNCMD_RC; if ($rc ==0 ) { foreach my $line (@$res) { $rsp->{data} ->[0] = $line; xCAT::MsgUtils->message("I", $rsp, $callback); } } else { # error foreach my $line (@$res) { $rsp->{error} ->[0] = $line; xCAT::MsgUtils->message("E", $rsp, $callback); } } } } else # if not install/netboot/statelite { # nodetype.provmethod = &checkoption("nodetype.provmethod=$key",$OSVER,$PROFILE,$ARCH,$callback); # run nodeset $nodes osimage my @nodesetarg; push @nodesetarg, "osimage"; my $res = xCAT::Utils->runxcmd( { command => ["nodeset"], node => \@nodes, arg => \@nodesetarg }, $subreq, -1, 1); my $rsp = {}; $rc=$::RUNCMD_RC; if ($rc ==0 ) { foreach my $line (@$res) { $rsp->{data} ->[0] = $line; xCAT::MsgUtils->message("I", $rsp, $callback); } } else { # error foreach my $line (@$res) { $rsp->{error} ->[0] = $line; xCAT::MsgUtils->message("E", $rsp, $callback); } } } } } # end nodech/nodeset for each group if ($rc != 0) # we got an error with the nodeset { my $rsp = {}; $rsp->{error}->[0] = "nodeset failure will not continue "; xCAT::MsgUtils->message("E", $rsp, $callback); return 1; } # call "rsetboot" to set the boot order of the nodehm.mgt=ipmi nodes,for others, # assume user has set the correct boot order before "rinstall" # run rsetboot $noderange net my @rsetbootarg; push @rsetbootarg, "net"; my $res = xCAT::Utils->runxcmd( { command => ["rsetboot"], node => \@nodes, arg => \@rsetbootarg }, $subreq, -1, 1); # fix output it is a hash and you must get error out of the hash. my $rsp = {}; $rc=$::RUNCMD_RC; if ($rc ==0 ) { foreach my $line (@$res) { $rsp->{data} ->[0] = $line; xCAT::MsgUtils->message("I", $rsp, $callback); } } else { # error foreach my $line (@$res) { $rsp->{error} ->[0] = $line; xCAT::MsgUtils->message("E", $rsp, $callback); } } if ($rc != 0) # we got an error with the rsetboot { my $rsp = {}; $rsp->{error}->[0] = "rsetboot failure will not continue "; xCAT::MsgUtils->message("E", $rsp, $callback); return 1; } # call "rpower" to start the node provision process #run rpower $noderange boot my @rpowerarg; push @rpowerarg, "boot"; my $res = xCAT::Utils->runxcmd( { command => ["rpower"], node => \@nodes, arg => \@rpowerarg }, $subreq, -1, 1); my $rsp = {}; $rc=$::RUNCMD_RC; if ($rc ==0 ) { foreach my $line (@$res) { $rsp->{data} ->[0] = $line; xCAT::MsgUtils->message("I", $rsp, $callback); } } else { # error foreach my $line (@$res) { $rsp->{error} ->[0] = $line; xCAT::MsgUtils->message("E", $rsp, $callback); } } # Check if they asked to bring up a console ( -c) from rinstall always for winstall $req->{startconsole}->[0] =0; if ($command =~ /rinstall/) { # for rinstall, the -c|--console option can provide the remote console for only 1 node if ($CONSOLE) { if (scalar @$nodes ne 1) { my $rsp = {}; $rsp->{error}->[0] = "rinstall -c only accepts one node in the noderange. See winstall for support for support of consoles on multiple nodes."; xCAT::MsgUtils->message("E", $rsp, $callback); return 1; } else { # tell rinstall client ok to start rcons $req->{startconsole}->[0] =1; } } } elsif ($command =~ /winstall/) { # winstall can start a wcons command to multiple nodes for monitoring the provision cycle $req->{startconsole}->[0] =1; } return 0; } #------------------------------------------------------- =head3 Usage =cut #------------------------------------------------------- sub usage { my $command = shift; my $callback = shift; my $rsp = {}; $rsp->{data}->[0] = "$command usage:"; if ($command =~ /rinstall/) { $rsp->{data}->[1] = " [-o|--osver] [-p|--profile] [-a|--arch] [-c|--console] "; } else { # winstall $rsp->{data}->[1] = " [-o|--osver] [-p|--profile] [-a|--arch] "; } if ($command =~ /rinstall/) { $rsp->{data}->[2] = " [-O|--osimage] [-c|--console] "; } else { # wininstall $rsp->{data}->[2] = " [-O|--osimage] "; } $rsp->{data}->[3] = " [-h|--help]"; $rsp->{data}->[4] = " [-v|--version]"; xCAT::MsgUtils->message("I", $rsp, $callback); } # check and complain about the invalid combination of the options, # ignore -o,-p and -a options and prompt a warning message when provmethod=osimagename sub checkoption{ my $optstring=shift; my $OSVER=shift; my $PROFILE=shift; my $ARCH=shift; my $callback=shift; my $rsp = {}; if($OSVER) { $rsp->{data}->[0] = "-o option not valid with $optstring. It is ignored."; xCAT::MsgUtils->message("I", $rsp, $callback); } if($PROFILE) { $rsp->{data}->[0] = "-p option not valid with $optstring. It is ignored."; xCAT::MsgUtils->message("I", $rsp, $callback); } if($ARCH) { $rsp->{data}->[0] = "-a option not valid with $optstring. It is ignored."; xCAT::MsgUtils->message("I", $rsp, $callback); } } 1;