From bbeddd775a496fb0aa1c223ed3b568a6ae6561a4 Mon Sep 17 00:00:00 2001 From: daniceexi Date: Sun, 30 Jun 2013 04:30:33 +0000 Subject: [PATCH] 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 --- xCAT-server/lib/xcat/plugins/mic.pm | 818 ++++++++++++++++++++++++++++ 1 file changed, 818 insertions(+) create mode 100644 xCAT-server/lib/xcat/plugins/mic.pm diff --git a/xCAT-server/lib/xcat/plugins/mic.pm b/xCAT-server/lib/xcat/plugins/mic.pm new file mode 100644 index 000000000..31913acef --- /dev/null +++ b/xCAT-server/lib/xcat/plugins/mic.pm @@ -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;