Code drop for Xeon Phi (mic) support. The plugin to handle the rpower, rinv, nodeset, rcons commands for mic
git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@16838 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
This commit is contained in:
		
							
								
								
									
										818
									
								
								xCAT-server/lib/xcat/plugins/mic.pm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										818
									
								
								xCAT-server/lib/xcat/plugins/mic.pm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,818 @@ | ||||
| #!/usr/bin/env perl | ||||
| ## IBM(c) 20013 EPL license http://www.eclipse.org/legal/epl-v10.html | ||||
| # | ||||
| # This plugin is used to handle the command requests for Xeon Phi (mic) support | ||||
| # | ||||
|  | ||||
| package xCAT_plugin::mic; | ||||
| BEGIN | ||||
| { | ||||
|     $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; | ||||
| } | ||||
|  | ||||
| use strict; | ||||
| use Getopt::Long; | ||||
| use File::Path; | ||||
| use File::Basename; | ||||
|  | ||||
| use xCAT::Utils; | ||||
| use xCAT::MsgUtils; | ||||
| use xCAT::TableUtils; | ||||
| use xCAT::Table; | ||||
|  | ||||
| sub handled_commands { | ||||
|     return { | ||||
|         rpower => 'nodehm:mgt', | ||||
|         nodeset => "nodehm:mgt", # generate the osimage for mic on the host | ||||
|         rflash => 'nodehm:mgt',     # update the firmware of mics | ||||
|         rinv => 'nodehm:mgt', | ||||
|         rvitals => 'nodehm:mgt', | ||||
|         copytar => 'mic', | ||||
|         getcons => 'nodehm:mgt',         | ||||
|     } | ||||
| } | ||||
|  | ||||
| my $CALLBACK;  # used to hanel the output from xdsh | ||||
|  | ||||
| # since the mic is attached to the host node and management of mic needs to be  | ||||
| # done via host node, the host will be used as the target to get the service node | ||||
| sub preprocess_request {  | ||||
|     my $request = shift; | ||||
|     my $callback = shift; | ||||
|     | ||||
|     if ($request->{command}->[0] eq 'copytar') | ||||
|     { | ||||
|         # don't handle copytar (copycds) | ||||
|         return [$request]; | ||||
|     }  | ||||
|     # if already preprocessed, go straight to request | ||||
|     if ((defined($request->{_xcatpreprocessed}->[0])) | ||||
|         && ($request->{_xcatpreprocessed}->[0] == 1)) { | ||||
|         return [$request]; | ||||
|     } | ||||
|  | ||||
|     my $nodes = $request->{node}; | ||||
|     my $command = $request->{command}->[0]; | ||||
|     my $extraargs = $request->{arg}; | ||||
|  | ||||
|     if ($extraargs) { | ||||
|         @ARGV=@{$extraargs}; | ||||
|         my ($verbose, $help, $ver); | ||||
|         GetOptions("V" => \$verbose, 'h|help' => \$help, 'v|version' => \$ver);  | ||||
|         if ($help) { | ||||
|             my $usage_string = xCAT::Usage->getUsage($command); | ||||
|             my $rsp; | ||||
|             push @{$rsp->{data}}, $usage_string; | ||||
|             xCAT::MsgUtils->message("I", $rsp, $callback); | ||||
|             return (); | ||||
|         } | ||||
|         if ($ver) { | ||||
|             my $ver_string = xCAT::Usage->getVersion($command); | ||||
|             my $rsp; | ||||
|             push @{$rsp->{data}}, $ver_string; | ||||
|             xCAT::MsgUtils->message("I", $rsp, $callback); | ||||
|             return (); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     # Get the host for the mic nodes | ||||
|     my %hosts; | ||||
|     my $mictab = xCAT::Table->new("mic"); | ||||
|     unless ($mictab) { | ||||
|         xCAT::MsgUtils->message("E", {error=>["Cannot open the mic table."], errorcode=>["1"]}, $callback); | ||||
|         return; | ||||
|     } | ||||
|     my $mictabhash = $mictab->getNodesAttribs($nodes,['host']); | ||||
|     foreach my $node (@$nodes) { | ||||
|         if (!defined ($mictabhash->{$node}->[0]->{'host'})) { | ||||
|             xCAT::MsgUtils->message("E", {error=>["The michost attribute was not set for $node"], errorcode=>["1"]}, $callback); | ||||
|             return; | ||||
|         } | ||||
|         push @{$hosts{$mictabhash->{$node}->[0]->{'host'}}}, $node; | ||||
|     } | ||||
|  | ||||
|     my @requests; | ||||
|     # get the service nodes of hosts instread of mic nodes | ||||
|     my @hosts=keys(%hosts); | ||||
|     my $sn = xCAT::ServiceNodeUtils->get_ServiceNode(\@hosts, 'xcat', "MN"); | ||||
|     foreach my $snkey (keys %$sn){ | ||||
|         my $reqcopy = {%$request}; | ||||
|         my @nodes4sn; | ||||
|         foreach (@{$sn->{$snkey}}) { | ||||
|             push @nodes4sn, @{$hosts{$_}}; | ||||
|         } | ||||
|         $reqcopy->{node} = \@nodes4sn;   # the node attribute will have the real mic nodes | ||||
|         unless ($snkey eq '!xcatlocal!') { | ||||
|             $reqcopy->{'_xcatdest'} = $snkey; | ||||
|         } | ||||
|         $reqcopy->{_xcatpreprocessed}->[0] = 1; | ||||
|         push @requests, $reqcopy; | ||||
|     } | ||||
|     return \@requests; | ||||
| } | ||||
|  | ||||
| sub process_request { | ||||
|     my $request = shift; | ||||
|     my $callback = shift; | ||||
|     my $subreq = shift; | ||||
|  | ||||
|     my $nodes = $request->{node}; | ||||
|     my $command = $request->{command}->[0]; | ||||
|     my $args = $request->{arg}; | ||||
|  | ||||
|     # get the mapping between host and mic | ||||
|     my %hosts; | ||||
|     my $mictab = xCAT::Table->new("mic"); | ||||
|     unless ($mictab) { | ||||
|         xCAT::MsgUtils->message("E", {error=>["Cannot open the mic table."], errorcode=>["1"]}, $callback); | ||||
|         return; | ||||
|     } | ||||
|     my $mictabhash = $mictab->getNodesAttribs($nodes,['host', 'id']); | ||||
|     foreach my $node (@$nodes) { | ||||
|         $hosts{$mictabhash->{$node}->[0]->{'host'}}{$mictabhash->{$node}->[0]->{'id'}} = $node;    # $hosts{host}{micid} = micname | ||||
|         $hosts{$mictabhash->{$node}->[0]->{'host'}}{'ids'} .= " $mictabhash->{$node}->[0]->{'id'}";  # $hosts{host}{ids} = " id0 id1 id2 ..." | ||||
|     } | ||||
|  | ||||
|     if ($command eq "rvitals"){ | ||||
|         rinv($request, $callback, $subreq, \%hosts); | ||||
|     } elsif ($command eq "rmicctrl") { | ||||
|         rmicctrl($callback, $args); | ||||
|     } elsif ($command eq "rinv") { | ||||
|         rinv($request, $callback, $subreq, \%hosts); | ||||
|     } elsif ($command eq "rpower") { | ||||
|         rpower($request, $callback, $subreq, \%hosts); | ||||
|     } elsif ($command eq "copytar") { | ||||
|         copytar($request, $callback); | ||||
|     } elsif ($command eq "getcons") { | ||||
|         getcons($request, $callback); | ||||
|     } elsif ($command eq "rflash") { | ||||
|         rflash($request, $callback, $subreq, \%hosts); | ||||
|     } elsif ($command eq "nodeset") { | ||||
|         nodeset($request, $callback, $subreq, \%hosts); | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| # handle the rpower command for the mic node | ||||
| sub rpower { | ||||
|     my $request = shift; | ||||
|     my $callback = shift; | ||||
|     my $subreq = shift; | ||||
|     my $host2mic = shift; | ||||
|  | ||||
|     my $usage_string = "rpower noderange [stat|state|on|off|reset|boot]"; | ||||
|  | ||||
|     my $args = $request->{arg}; | ||||
|     my ($wait, $timeout, $action); | ||||
|     if ($args) { | ||||
|         @ARGV=@{$args}; | ||||
|         GetOptions('w' => \$wait, | ||||
|                    't=s' => \$timeout); | ||||
|         foreach (@ARGV) { | ||||
|             if (/^stat/) { | ||||
|                 $action = "--status"; | ||||
|             } elsif (/^on$/) { | ||||
|                 $action = "--boot"; | ||||
|             } elsif (/^off$/) { | ||||
|                 $action = "--shutdown"; | ||||
|             } elsif (/^reset$/) { | ||||
|                 $action = "--reset"; | ||||
|             } elsif (/^boot$/) { | ||||
|                 $action = "--reboot"; | ||||
|             } else { | ||||
|                 my $rsp; | ||||
|                 push @{$rsp->{data}}, $usage_string; | ||||
|                 xCAT::MsgUtils->message("E", $rsp, $callback); | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|     } else { | ||||
|         my $rsp; | ||||
|         push @{$rsp->{data}}, $usage_string; | ||||
|         xCAT::MsgUtils->message("E", $rsp, $callback); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     # get all the hosts | ||||
|     # use the id list as the key to classify the host, since the handle the host against | ||||
|     # same mic list will be run in a batch | ||||
|     my %hostclass;   | ||||
|     foreach (keys %$host2mic) { | ||||
|         push @{$hostclass{$host2mic->{$_}{'ids'}}}, $_; | ||||
|     } | ||||
|  | ||||
|     foreach (keys %hostclass) { | ||||
|         my $idlist = $_; | ||||
|         my @hosts = @{$hostclass{$idlist}}; | ||||
|         my $miclist = $idlist;  # currently ,it's " 0 1 2 .." | ||||
|         $miclist =~ s/(\d+)/mic$1/g;  # then, it should be "mic0 mic1 mic2 ..." | ||||
|  | ||||
|         my @cmd = ("/usr/sbin/micctrl", $action, $miclist); | ||||
|         if ($wait) { | ||||
|             if ($timeout) { | ||||
|                 push @cmd, (" --wait", "--timeout=$timeout"); | ||||
|             } else { | ||||
|                 push @cmd, " --wait"; | ||||
|             } | ||||
|         } | ||||
|      | ||||
|         my $output = xCAT::Utils->runxcmd({ command => ['xdsh'], | ||||
|                                            node => \@hosts, | ||||
|                                            arg => \@cmd }, $subreq, 0, 1); | ||||
|      | ||||
|         # parse the output | ||||
|         # replace the mic name from the host like mic0:xxx, mic1:xxx to the real mic name | ||||
|         # which defined in xCAT | ||||
|         foreach (@$output) { | ||||
|             foreach my $line (split /\n/, $_) { | ||||
|                 if ($line =~ /([^:]*):\s*([^:]*):(.*)/) { | ||||
|                     my $host = $1; | ||||
|                     my $mic = $2; | ||||
|                     my $msg = $3; | ||||
|                     chomp ($host); | ||||
|                     chomp ($mic); | ||||
|                     chomp ($msg); | ||||
|                     if ($mic =~ /^mic\d+/) { | ||||
|                         my $micid = $mic; | ||||
|                         $micid =~ s/[^\d]*//g; | ||||
|                         my $micname = $host2mic->{$host}{$micid}; | ||||
|                         xCAT::MsgUtils->message("I", {data=>["$micname: $msg"]}, $callback); | ||||
|                     } else { | ||||
|                         xCAT::MsgUtils->message("E", {data=>[$line]}, $callback); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } # end of foreach host class with same mic list | ||||
| } | ||||
|  | ||||
| # display the inventory information for mic | ||||
| # this subroutine will handle the both rinv and rvitals commands | ||||
| sub rinv { | ||||
|     my $request = shift; | ||||
|     my $callback = shift; | ||||
|     my $subreq = shift; | ||||
|     my $host2mic = shift; | ||||
|  | ||||
|     my $command = $request->{command}->[0]; | ||||
|     my $usage_string; | ||||
|     my %validargs; | ||||
|  | ||||
|     # set the valid argurments and correspoding groups which can be recognized by  | ||||
|     # micinfo command | ||||
|     if ($command eq "rinv") { | ||||
|         $usage_string = "rinv noderange {system|ver|board|core|gddr|all}"; | ||||
|         %validargs = ("system" => "System", "ver" => "Version", "board" => "Board",  | ||||
|                       "core" => "Core", "gddr" => "GDDR", "all" => "all"); | ||||
|     } elsif ($command eq "rvitals") { | ||||
|         $usage_string = "rvitals noderange {thermal|all}"; | ||||
|         %validargs = ("thermal" => "Thermal", "all" => "all"); | ||||
|     } | ||||
|  | ||||
|     my @args; | ||||
|     if (defined ($request->{arg})) { | ||||
|         @args = @{$request->{arg}}; | ||||
|         unless (@args) { | ||||
|             push @args, "all"; | ||||
|         } | ||||
|     } else { | ||||
|         push @args, "all"; | ||||
|     } | ||||
|     my @groups; # the groups name which could be displayed by micinfo  | ||||
|     foreach my $arg (@args) { | ||||
|         if ($validargs{$arg}) { | ||||
|             if ($arg eq "all") { | ||||
|                 if ($command eq "rinv") { | ||||
|                     push @groups, ("System", "Version", "Board", "Core", "GDDR"); | ||||
|                 } elsif ($command eq "rvitals") { | ||||
|                     push @groups, ("Thermal"); | ||||
|                 } | ||||
|             } else { | ||||
|                 push @groups, $validargs{$arg}; | ||||
|             } | ||||
|         } else { | ||||
|             my $rsp; | ||||
|             push @{$rsp->{data}}, $usage_string; | ||||
|             xCAT::MsgUtils->message("E", $rsp, $callback); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     my %groupflag; | ||||
|     foreach (@groups) { | ||||
|         $groupflag{$_} = 1; | ||||
|     } | ||||
|  | ||||
|     # run micinfo on the host to get all the mic information first | ||||
|     my @hosts = (keys  %$host2mic); | ||||
|     my $output = xCAT::Utils->runxcmd({ command => ['xdsh'], | ||||
|                                            node => \@hosts, | ||||
|                                            arg => ["/opt/intel/mic/bin/micinfo"]}, $subreq, 0, 1); | ||||
|  | ||||
|     # classify all the output with the host name | ||||
|     my %outofhost; | ||||
|     foreach (@$output) { | ||||
|         if (/\@\@\@/) { next; } # remove the part of ssh connection warning | ||||
|         foreach my $line (split /\n/, $_) { | ||||
|             $line =~ s/(\s)+/ /g; | ||||
|             if ($line =~ /([^:]*):(.*)/) { | ||||
|                 push @{$outofhost{$1}}, $2; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     foreach my $host (keys %outofhost) { | ||||
|         my $micid; | ||||
|         my $micname; # which is the node name of the mic | ||||
|         my $curgroup; | ||||
|         my @sysinfo; | ||||
|         my $rsp; | ||||
|         foreach (@{$outofhost{$host}}) { | ||||
|             if (/^\s*Device No:\s*(\d+)/) { | ||||
|                 # get the mic name | ||||
|                 $micid = $1; | ||||
|                 $micname = $host2mic->{$host}->{$micid}; | ||||
|  | ||||
|                 # display the System infor first | ||||
|                 foreach (@sysinfo) { | ||||
|                     if ($groupflag{'System'} == 1 && $micname) { | ||||
|                         push @{$rsp->{data}}, "$micname: $_"; | ||||
|                     } | ||||
|                 } | ||||
|             } elsif (/^\s*System Info$/) { | ||||
|                 $curgroup = "System"; | ||||
|             } elsif (/^\s*Version$/) { | ||||
|                 $curgroup = "Version"; | ||||
|             } elsif (/^\s*Board$/) { | ||||
|                 $curgroup = "Board"; | ||||
|             } elsif (/^\s*Cores$/) { | ||||
|                 $curgroup = "Core"; | ||||
|             } elsif (/^\s*Thermal$/) { | ||||
|                 $curgroup = "Thermal"; | ||||
|             }  elsif (/^\s*GDDR$/) { | ||||
|                 $curgroup = "GDDR"; | ||||
|             } else { | ||||
|                 my $msg = $_; | ||||
|                 if ($msg =~ /^\s*$/) { next;} | ||||
|                 $msg =~ s/^\s*//; | ||||
|                 if ($curgroup eq "System") { | ||||
|                     push @sysinfo, $msg; | ||||
|                 } elsif ($groupflag{$curgroup} == 1 && $micname) { | ||||
|                     push @{$rsp->{data}}, "$micname: $msg"; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         xCAT::MsgUtils->message("I", $rsp, $callback); | ||||
|     } | ||||
| } | ||||
|  | ||||
| # do the copy of metarials (root file system, flash image, kernel) for mic support from mpss tar  | ||||
| sub copytar { | ||||
|     my $request = shift; | ||||
|     my $callback = shift; | ||||
|  | ||||
|     my $args = $request->{arg}; | ||||
|     my ($osname, $file); | ||||
|     if ($args) { | ||||
|         @ARGV=@{$args}; | ||||
|         GetOptions('n=s' => \$osname, | ||||
|                    'f=s' => \$file); | ||||
|     } | ||||
|  | ||||
|     my $installroot = "/install"; | ||||
|     my @entries =  xCAT::TableUtils->get_site_attribute("installdir"); | ||||
|     my $t_entry = $entries[0]; | ||||
|     if ( defined($t_entry) ) { | ||||
|         $installroot = $t_entry; | ||||
|     } | ||||
|      | ||||
|     my $tmpdir = "/tmp/mictmp"; | ||||
|     my $destdir = "$installroot/$osname"; | ||||
|     rmtree ($tmpdir); | ||||
|     mkpath ($tmpdir); | ||||
|     mkpath ($destdir); | ||||
|  | ||||
|     # extract the files from the mpss tar file | ||||
|     my $cmd = "tar xvf $file -C $tmpdir"; | ||||
|     my @output = xCAT::Utils->runcmd($cmd, -1); | ||||
|     if ($::RUNCMD_RC != 0) { | ||||
|         xCAT::MsgUtils->message("E", "Error when run [$cmd], @output"); | ||||
|         return 1; | ||||
|     } | ||||
|  | ||||
|     # get the rpm packages intel-mic-gpl and intel-mic-flash which include the files for root file system, flash ... | ||||
|     my @micgpl = <$tmpdir/*/intel-mic-gpl*>; | ||||
|     my @micflash = <$tmpdir/*/intel-mic-flash*>; | ||||
|     unless (-r $micgpl[0] && -r $micflash[0]) { | ||||
|         xCAT::MsgUtils->message("E", "Error: Cannot get the rpm files intel-mic-gpl or intel-mic-flash from the tar file."); | ||||
|         return 1; | ||||
|     } | ||||
|  | ||||
|     # extract the files from rpm packages | ||||
|     $cmd = "cd $destdir; rpm2cpio $micgpl[0] | cpio -idum; rpm2cpio $micflash[0] | cpio -idum"; | ||||
|     @output = xCAT::Utils->runcmd($cmd, -1); | ||||
|     if ($::RUNCMD_RC != 0) { | ||||
|         xCAT::MsgUtils->message("E", "Error when run [$cmd], @output"); | ||||
|         return 1; | ||||
|     } | ||||
|  | ||||
|     # generate the image objects | ||||
|     my $oitab = xCAT::Table->new('osimage'); | ||||
|     unless ($oitab) { | ||||
|         xCAT::MsgUtils->message("E", "Error: Cannot open table osimage."); | ||||
|         return 1; | ||||
|     } | ||||
|  | ||||
|     my %values; | ||||
|     $values{'imagetype'} = "linux"; | ||||
|     $values{'provmethod'} = "netboot"; | ||||
|     $values{'rootfstype'} = "ramdisk"; | ||||
|     $values{'description'} = "Linux for Intel mic"; | ||||
|     $values{'osname'} = "Linux"; | ||||
|     $values{'osvers'} = "mic"; | ||||
|     $values{'osarch'} = "x86_64"; | ||||
|     $values{'profile'} = "compute"; | ||||
|  | ||||
|     my $imagename = "$osname-netboot-compute"; | ||||
|     $oitab->setAttribs({'imagename' => $imagename}, \%values); | ||||
|  | ||||
|     my $litab = xCAT::Table->new('linuximage'); | ||||
|     unless ($litab) { | ||||
|         xCAT::MsgUtils->message("E", "Error: Cannot open table linuximage."); | ||||
|         return 1; | ||||
|     } | ||||
|      | ||||
|     # set a default package list | ||||
|     my $pkglist = "$::XCATROOT/share/xcat/netboot/mic/compute.pkglist"; | ||||
|     $litab->setAttribs({'imagename' => $imagename}, {'pkgdir' => $destdir, 'pkglist' => $pkglist}); | ||||
|  | ||||
|     xCAT::MsgUtils->message("I", "The image $imagename has been created."); | ||||
|     rmtree ($tmpdir); | ||||
| } | ||||
|  | ||||
| # get the console configuration for rcons:  | ||||
| # see /opt/xcat/share/xcat/cons/mic | ||||
| sub getcons { | ||||
|     my $request = shift; | ||||
|     my $callback = shift; | ||||
|  | ||||
|     my $node = $request->{node}->[0]; | ||||
|     my $mictab = xCAT::Table->new("mic"); | ||||
|     unless ($mictab) { | ||||
|         xCAT::MsgUtils->message("E", {error=>["Cannot open the mic table."], errorcode=>["1"]}, $callback); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     # get the console parameters | ||||
|     my $sconsparms = {node=>[{name=>[$node]}]}; | ||||
|     my $mictabhash = $mictab->getNodeAttribs($node,['host', 'id']); | ||||
|     if (defined ($mictabhash->{'host'})) { | ||||
|         $sconsparms->{node}->[0]->{sshhost} = [$mictabhash->{'host'}]; | ||||
|     } | ||||
|     if (defined ($mictabhash->{'id'})) { | ||||
|         $sconsparms->{node}->[0]->{psuedotty} = ["/dev/ttyMIC".$mictabhash->{'id'}]; | ||||
|     } | ||||
|     $sconsparms->{node}->[0]->{baudrate}=["115200"]; | ||||
|  | ||||
|     $callback->($sconsparms); | ||||
| } | ||||
|  | ||||
| # do the flash of firmware for mic | ||||
| sub rflash { | ||||
|     my $request = shift; | ||||
|     my $callback = shift; | ||||
|     my $subreq = shift; | ||||
|     my $host2mic = shift; | ||||
|  | ||||
|     my $usage_string = "rflash noderange"; | ||||
|  | ||||
|     my $nodes = $request->{'node'}; | ||||
|      | ||||
|     # get the provision method for all the nodes | ||||
|     my $nttab = xCAT::Table->new("nodetype"); | ||||
|     unless ($nttab) { | ||||
|         xCAT::MsgUtils->message("E", {error=>["Cannot open the nodetype table."], errorcode=>["1"]}, $callback); | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|     my $nthash = $nttab->getNodesAttribs($nodes,['provmethod']); | ||||
|     foreach my $node (@$nodes) { | ||||
|         unless (defined ($nthash->{$node}->[0]->{'provmethod'})) { | ||||
|             xCAT::MsgUtils->message("E", {error=>["The provmethod for the node $node should be set before the rflash."], errorcode=>["1"]}, $callback); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     # get pkgdir for the osimage | ||||
|     my $litab = xCAT::Table->new("linuximage"); | ||||
|     unless ($litab) { | ||||
|         xCAT::MsgUtils->message("E", {error=>["Cannot open the linuximage table."], errorcode=>["1"]}, $callback); | ||||
|         return; | ||||
|     } | ||||
|     my @osimages = $litab->getAllAttribs("imagename", "pkgdir"); | ||||
|     my %osimage; | ||||
|     foreach (@osimages) { | ||||
|         $osimage{$_->{'imagename'}} = $_->{'pkgdir'}; | ||||
|     } | ||||
|  | ||||
|     # get the tftp dir and create the path for the mic configuration files | ||||
|     my $tftpdir = "/tftpboot"; | ||||
|     my @entries =  xCAT::TableUtils->get_site_attribute("$tftpdir"); | ||||
|     my $t_entry = $entries[0]; | ||||
|     if ( defined($t_entry) ) { | ||||
|         $tftpdir = $t_entry; | ||||
|     } | ||||
|     mkpath ("$tftpdir/xcat/miccfg/"); | ||||
|  | ||||
|     # generate the rflash configuration files for each host | ||||
|     # the configureation file should have the following format | ||||
|     #miclist=mic0 | ||||
|     #0:name=host1-mic0 | ||||
|     #imgpath=/install/mpss3.new | ||||
|     my @hosts = (keys %$host2mic); | ||||
|     foreach my $host (@hosts) { | ||||
|         my @cfgfile; | ||||
|         push @cfgfile, "#XCAT MIC FLASH CONFIGURATION FILE#"; | ||||
|         my $miclist = $host2mic->{$host}{'ids'}; | ||||
|         my @micids = split (/ /, $miclist); | ||||
|         $miclist =~ s/(\d+)/mic$1/g; | ||||
|         $miclist =~ s/ /,/g; | ||||
|         $miclist =~ s/^,//; | ||||
|          | ||||
|         push @cfgfile, "miclist=$miclist"; | ||||
|  | ||||
|         my $osimg; | ||||
|         foreach my $micid (@micids) { | ||||
|             if ($micid eq '') { next;} | ||||
|             my $micname = $host2mic->{$host}{$micid}; | ||||
|             # get the pkgdir of the osimage which set to the mic node. | ||||
|             # and make sure the osimage which set to the mic shold be same for all the mics on one host | ||||
|             if ($osimg) { | ||||
|                 if ($osimg ne $nthash->{$micname}->[0]->{'provmethod'}) { | ||||
|                     xCAT::MsgUtils->message("E", {error=>["The provmethod for the nodes in the same host should be same."], errorcode=>["1"]}, $callback); | ||||
|                     return; | ||||
|                 } | ||||
|             } else { | ||||
|                 $osimg = $nthash->{$micname}->[0]->{'provmethod'}; | ||||
|             } | ||||
|             push @cfgfile, "$micid:name=$micname"; | ||||
|         } | ||||
|         push @cfgfile, "imgpath=$osimage{$osimg}"; | ||||
|          | ||||
|         if (open (CFG, ">$tftpdir/xcat/miccfg/micflash.$host")) { | ||||
|             foreach (@cfgfile) { | ||||
|                 print CFG $_."\n"; | ||||
|             } | ||||
|             close (CFG); | ||||
|         } else { | ||||
|             xCAT::MsgUtils->message("E", {error=>["Cannot open the file $tftpdir/xcat/miccfg/micflash.$host to write."], errorcode=>["1"]}, $callback); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     # run the cmd on the host to flash the mic | ||||
|     my @args = ("-s", "-v", "-e"); | ||||
|     push @args, "$::XCATROOT/sbin/flashmic"; | ||||
|     my $master = $request->{'_xcatdest'}; | ||||
|     push @args, ("-m", "$master"); | ||||
|     push @args, ("-p", "$tftpdir/xcat/miccfg"); | ||||
|  | ||||
|     $CALLBACK = $callback; | ||||
|     $subreq->({ command => ['xdsh'], | ||||
|                       node => \@hosts, | ||||
|                       arg => \@args }, \&michost_cb); | ||||
| } | ||||
|  | ||||
| # run the nodeset to genimage the osimage for each mic | ||||
| # it gets on host first and mount the root file system from MN:/install/mpssxxx | ||||
| # to host, and then configure and generate the mic specific osimage for each mic. | ||||
| # | ||||
| # If running 'odeset noderange osimage=imagename', the imagename will be used to generate | ||||
| # image for mic and imagename will be set to the provmethod attr for the mic. If no 'osimage=xx'  | ||||
| # is specified, the osimage will be get from provmethod attr. | ||||
| sub nodeset { | ||||
|     my $request = shift; | ||||
|     my $callback = shift; | ||||
|     my $subreq = shift; | ||||
|     my $host2mic = shift; | ||||
|  | ||||
|     my $usage_string = "nodeset noderange [osimage=imagename]"; | ||||
|  | ||||
|     my $nodes = $request->{'node'}; | ||||
|     my $args = $request->{arg}; | ||||
|     my $setosimg; | ||||
|     foreach (@$args) { | ||||
|         if (/osimage=(.*)/) { | ||||
|             $setosimg = $1; | ||||
|         } else { | ||||
|             xCAT::MsgUtils->message("E", {error=>[$usage_string], errorcode=>["1"]}, $callback); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     # get the provision method for all the nodes | ||||
|     my $nttab = xCAT::Table->new("nodetype"); | ||||
|     unless ($nttab) { | ||||
|         xCAT::MsgUtils->message("E", {error=>["Cannot open the nodetype table."], errorcode=>["1"]}, $callback); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     # if the osimage=xxx has been specified, then set it to the provmethod attr for the mic. | ||||
|     if ($setosimg) { | ||||
|         my %setpmethod; | ||||
|         foreach (@$nodes) { | ||||
|             $setpmethod{$_}{'provmethod'} = $setosimg; | ||||
|         } | ||||
|         $nttab->setNodesAttribs(\%setpmethod); | ||||
|     } | ||||
|      | ||||
|     my $nthash = $nttab->getNodesAttribs($nodes,['provmethod']); | ||||
|     foreach my $node (@$nodes) { | ||||
|         unless (defined ($nthash->{$node}->[0]->{'provmethod'})) { | ||||
|             xCAT::MsgUtils->message("E", {error=>["The provmethod for the node $node must be set before the nodeset."], errorcode=>["1"]}, $callback); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     # get the virtual bridge, onboot, vlog information for the mic nodes | ||||
|     my $mictab = xCAT::Table->new("mic"); | ||||
|     unless ($mictab) { | ||||
|         xCAT::MsgUtils->message("E", {error=>["Cannot open the mic table."], errorcode=>["1"]}, $callback); | ||||
|         return; | ||||
|     } | ||||
|     my $michash = $mictab->getNodesAttribs($nodes, ['bridge', 'onboot', 'vlog']); | ||||
|  | ||||
|     # get ip for the mic nodes from hosts table | ||||
|     my $hosttab = xCAT::Table->new("hosts"); | ||||
|     unless ($hosttab) { | ||||
|         xCAT::MsgUtils->message("E", {error=>["Cannot open the host table."], errorcode=>["1"]}, $callback); | ||||
|         return; | ||||
|     } | ||||
|     my $hosthash = $hosttab->getNodesAttribs($nodes, ['ip']); | ||||
|  | ||||
|     # get pkgdir from the osimage | ||||
|     my $litab = xCAT::Table->new("linuximage"); | ||||
|     unless ($litab) { | ||||
|         xCAT::MsgUtils->message("E", {error=>["Cannot open the linuximage table."], errorcode=>["1"]}, $callback); | ||||
|         return; | ||||
|     } | ||||
|     my @osimages = $litab->getAllAttribs("imagename", "pkgdir"); | ||||
|     my %osimage; | ||||
|     foreach (@osimages) { | ||||
|         $osimage{$_->{'imagename'}} = $_->{'pkgdir'}; | ||||
|     } | ||||
|  | ||||
|     # get the tftp dir and create the path for mic configuration | ||||
|     my $tftpdir = "/tftpboot"; | ||||
|     my @entries =  xCAT::TableUtils->get_site_attribute("$tftpdir"); | ||||
|     my $t_entry = $entries[0]; | ||||
|     if ( defined($t_entry) ) { | ||||
|         $tftpdir = $t_entry; | ||||
|     } | ||||
|     mkpath ("$tftpdir/xcat/miccfg/"); | ||||
|  | ||||
|     # generate the configuration file for each host | ||||
|     # the configureation file should have the following format | ||||
|     #miclist=mic0 | ||||
|     #0:ip=10.10.10.1|br=mybr0|name=host1-mic0|onboot=yes|vlog=no | ||||
|     #imgpath=/install/mpss3.1 | ||||
|     #overlay=ol1 | ||||
|     my %imghash; # cache of osimage information | ||||
|     my @hosts = (keys %$host2mic); | ||||
|     foreach my $host (@hosts) { | ||||
|         my @cfgfile; | ||||
|         push @cfgfile, "#XCAT MIC CONFIGURATION FILE#"; | ||||
|         my $miclist = $host2mic->{$host}{'ids'}; | ||||
|         my @micids = split (/ /, $miclist); | ||||
|         $miclist =~ s/(\d+)/mic$1/g; | ||||
|         $miclist =~ s/ /,/g; | ||||
|         $miclist =~ s/^,//; | ||||
|          | ||||
|         push @cfgfile, "miclist=$miclist"; | ||||
|  | ||||
|         my $osimg; | ||||
|         foreach my $micid (@micids) { | ||||
|             if ($micid eq '') { next;} | ||||
|             my $micname = $host2mic->{$host}{$micid}; | ||||
|             # get the pkgdir of the osimage which set to the mic node, | ||||
|             # and make sure the osimage which set to the mic shold be same for all the mics on one host | ||||
|             if ($osimg) { | ||||
|                 if ($osimg ne $nthash->{$micname}->[0]->{'provmethod'}) { | ||||
|                     xCAT::MsgUtils->message("E", {error=>["The provmethod for the nodes in the same host should be same."], errorcode=>["1"]}, $callback); | ||||
|                     return; | ||||
|                 } | ||||
|             } else { | ||||
|                 $osimg = $nthash->{$micname}->[0]->{'provmethod'}; | ||||
|             } | ||||
|  | ||||
|             # get the ip of the mic node | ||||
|             # get the ip from system resolution first, if failed, get from host table | ||||
|             my $micip = xCAT::NetworkUtils->getipaddr($micname); | ||||
|             unless ($micip) { | ||||
|                 $micip = $hosthash->{$micname}->[0]->{'ip'}; | ||||
|                 unless ($micip) { | ||||
|                     xCAT::MsgUtils->message("E", {error=>["Cannot get the IP from hosts table or system resolution for the $micname."], errorcode=>["1"]}, $callback); | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             # get the virtual bridge for the mic node | ||||
|             my $micbrg = $michash->{$micname}->[0]->{'bridge'}; | ||||
|             unless ($micbrg) { | ||||
|                 xCAT::MsgUtils->message("E", {error=>["Cannot get the micbridge for the $micname."], errorcode=>["1"]}, $callback); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             # generate the mic specific entry in the configuration file | ||||
|             my $micattrs = "$micid:ip=$micip|br=$micbrg|name=$micname"; | ||||
|             if (defined ($michash->{$micname}->[0]->{'onboot'})) { | ||||
|                 $micattrs .= "|onboot=$michash->{$micname}->[0]->{'onboot'}"; | ||||
|             } | ||||
|             if (defined ($michash->{$micname}->[0]->{'vlog'})) { | ||||
|                 $micattrs .= "|vlog=$michash->{$micname}->[0]->{'vlog'}"; | ||||
|             } | ||||
|             push @cfgfile, $micattrs; | ||||
|  | ||||
|         } | ||||
|         push @cfgfile, "imgpath=$osimage{$osimg}"; | ||||
|  | ||||
|         # get all the overlay entries for the osimage and do the cache for image | ||||
|         # search all the dir in the overlay dir execpt the system dir (system dir includes the files | ||||
|         # which generated by genimage command, and will be copied to mic osimage separated) | ||||
|         if (defined ($imghash{$osimg}{'ollist'})) { | ||||
|             push @cfgfile, "overlay=$imghash{$osimg}{'ollist'}"; | ||||
|         } else { | ||||
|             my @overlays = <$osimage{$osimg}/opt/intel/mic/filesystem/overlay/*>; | ||||
|             my $ollist; # overlay list | ||||
|             foreach my $obj (@overlays) { | ||||
|                 my $objname = basename($obj); | ||||
|                 if (-d $obj && $objname ne "system") { | ||||
|                     $ollist .= ",$objname"; | ||||
|                 } | ||||
|             } | ||||
|             $ollist =~ s/^,//; | ||||
|  | ||||
|             $imghash{$osimg}{'ollist'} = $ollist; | ||||
|             push @cfgfile, "overlay=$ollist"; | ||||
|         } | ||||
|  | ||||
|         if (open (CFG, ">$tftpdir/xcat/miccfg/miccfg.$host")) { | ||||
|             foreach (@cfgfile) { | ||||
|                 print CFG $_."\n"; | ||||
|             } | ||||
|             close (CFG); | ||||
|         } else { | ||||
|             xCAT::MsgUtils->message("E", {error=>["Cannot open the file $tftpdir/xcat/miccfg/miccfg.$host to write."], errorcode=>["1"]}, $callback); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     # run the cmd on the host to configure the mic | ||||
|     my @args = ("-s", "-v", "-e"); | ||||
|     push @args, "$::XCATROOT/sbin/configmic"; | ||||
|     my $master = $request->{'_xcatdest'}; | ||||
|     push @args, ("-m", "$master"); | ||||
|     push @args, ("-p", "$tftpdir/xcat/miccfg"); | ||||
|  | ||||
|     $CALLBACK = $callback; | ||||
|     $subreq->({ command => ['xdsh'], | ||||
|                       node => \@hosts, | ||||
|                       #arg => \@args }, $callback); | ||||
|                       arg => \@args }, \&michost_cb); | ||||
| } | ||||
|  | ||||
| # Handle the return message from xdsh command for 'configmic' and 'flashmic' scripts to | ||||
| # replace the message with correct mic name at head. And remove the unnecessary messages  | ||||
| sub michost_cb { | ||||
|     no strict; | ||||
|     my $response = shift; | ||||
|     my $rsp; | ||||
|     foreach my $type (keys %$response) | ||||
|     { | ||||
|         my @newop; | ||||
|         foreach my $output (@{$response->{$type}}) | ||||
|         { | ||||
|             xCAT::MsgUtils->message("S", "cb: $type, $output\n"); | ||||
|             # since the remote run of mic configuration will be closed by force in the configmic | ||||
|             # script, remove the error message from xdsh | ||||
|             if ($type eq "error" && $output =~ /(remote shell had error code|remote Command had return code)/) { | ||||
|                 delete $response->{error}; | ||||
|                 delete $rsp->{error}; | ||||
|             } elsif ($type eq "data" && $output =~ /Connection to(.*)closed by remote host/) { | ||||
|                 delete $response->{error}; | ||||
|                 delete $response->{errorcode}; | ||||
|                 delete $rsp->{error}; | ||||
|                 delete $rsp->{errorcode}; | ||||
|             } else { | ||||
|                 $output =~ s/^[^:]+:\s*MICMSG://g; | ||||
|                 $output =~ s/\n[^:]+:\s*MICMSG:/\n/g; | ||||
|                 push @newop, $output; | ||||
|             } | ||||
|         } | ||||
|         $rsp->{$type} = \@newop; | ||||
|     } | ||||
|     $CALLBACK->($rsp); | ||||
| xCAT::MsgUtils->message("S", "cb: finish\n"); | ||||
| } | ||||
|  | ||||
| 1; | ||||
		Reference in New Issue
	
	Block a user