package xCAT_plugin::genimage; BEGIN { $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; } use lib "$::XCATROOT/lib/perl"; use xCAT::Utils; use xCAT::SvrUtils; use xCAT::Table; use Data::Dumper; use File::Path; use Getopt::Long; Getopt::Long::Configure("bundling"); Getopt::Long::Configure("pass_through"); my $prinic; #TODO be flexible on node primary nic my $othernics; #TODO be flexible on node primary nic my $netdriver; my $arch; my $profile; my $osver; my $rootlimit; my $tmplimit; my $installroot = "/install"; my $kerneldir; my $kernelver = ""; my $imagename; my $pkglist; my $srcdir; my $destdir; my $srcdir_otherpkgs; my $otherpkglist; my $postinstall_filename; my $rootimg_dir; my $mode; my $permission; #the permission works only for statelite mode currently my $krpmver; my $kerneldir; my $mode; sub handled_commands { return { genimage => "genimage", } } sub process_request { my $request = shift; my $callback = shift; my $doreq = shift; my $installroot = xCAT::Utils->getInstallDir(); @ARGV = @{$request->{arg}}; #my $rsp; #$rsp->{data}->[0]="genimage plugin gets called with ARGV=@ARGV" ; #$callback->($rsp); GetOptions( 'a=s' => \$arch, 'p=s' => \$profile, 'o=s' => \$osver, 'n=s' => \$netdriver, 'i=s' => \$prinic, 'r=s' => \$othernics, 'l=s' => \$rootlimit, 't=s' => \$tmplimit, 'k=s' => \$kernelver, 'g=s' => \$krpmver, 'm=s' => \$mode, 'kerneldir=s' => \$kerneldir, 'permission=s' => \$permission ); my $osimagetab; my $linuximagetab; my $ref_linuximage_tab; my $ref_osimage_tab; my %keyhash = (); my %updates_os = (); # the hash for updating osimage table my %updates_linux = (); # the hash for updating linuximage table #always save the input values to the db if ($arch) { $updates_os{'osarch'}=$arch; } if ($profile) { $updates_os{'profile'} = $profile; } if ($osver) { $updates_os{'osvers'} = $osver; } if ($netdriver) { $updates_linux{'netdrivers'} = $netdriver; } if ($prinic) { $updates_linux{'nodebootif'} = $prinic; } if ($othernics) { $updates_linux{'otherifce'} = $othernics; } if ($kernelver) { $updates_linux{'kernelver'} = $kernelver; } if ($krpmver) { $updates_linux{'krpmver'} = $krpmver; } if ($kerneldir) { $updates_linux{'kerneldir'} = $kerneldir; } if ($permission){ $updates_linux{'permission'} = $permission; } # get the info from the osimage and linuximage table $osimagetab = xCAT::Table->new('osimage', -create=>1); unless ($osimagetab) { $callback->({error=>["The osimage table cannot be open."],errorcode=>[1]}); return 1; } $linuximagetab = xCAT::Table->new('linuximage', -create=>1); unless($linuximagetab) { $callback->({error=>["The linuximage table cannot be open."],errorcode=>[1]}); return 1; } if (@ARGV > 0) { $imagename=$ARGV[0]; if ($arch or $osver or $profile) { $callback->({error=>["-o, -p and -a options are not allowed when a image name is specified."],errorcode=>[1]}); return 1; } (my $ref_osimage_tab) = $osimagetab->getAttribs({imagename => $imagename}, 'osvers', 'osarch', 'profile', 'provmethod'); unless ($ref_osimage_tab) { $callback->({error=>["Cannot find image \'$imagename\' from the osimage table."],errorcode=>[1]}); return 1; } (my $ref_linuximage_tab) = $linuximagetab->getAttribs({imagename => $imagename}, 'pkglist', 'pkgdir', 'otherpkglist', 'otherpkgdir', 'postinstall', 'rootimgdir', 'kerneldir', 'krpmver', 'nodebootif', 'otherifce', 'kernelver', 'netdrivers', 'permission'); unless ($ref_linuximage_tab) { $callback->({error=>["Cannot find $imagename from the linuximage table."],errorcode=>[1]}); return 1; } $osver=$ref_osimage_tab->{'osvers'}; $arch=$ref_osimage_tab->{'osarch'}; $profile=$ref_osimage_tab->{'profile'}; my $provmethod=$ref_osimage_tab->{'provmethod'}; # TODO: not necessary, and need to update both statelite and stateless modes unless ($osver and $arch and $profile and $provmethod) { $callback->({error=>["osimage.osvers, osimage.osarch, osimage.profile and osimage.provmethod must be specified for the image $imagename in the database."],errorcode=>[1]}); return 1; } unless ($provmethod eq 'netboot' || $provmethod eq 'statelite') { $callback->({error=>["\'$imagename\' cannot be used to build diskless image. Make sure osimage.provmethod is 'netboot'."],errorcode=>[1]}); return 1; } unless ( $ref_linuximage_tab->{'pkglist'}) { $callback->({error=>["A .pkglist file must be specified for image \'$imagename\' in the linuximage table."],errorcode=>[1]}); return 1; } $pkglist = $ref_linuximage_tab->{'pkglist'}; $srcdir = $ref_linuximage_tab->{'pkgdir'}; $srcdir_otherpkgs = $ref_linuximage_tab->{'otherpkgdir'}; $otherpkglist = $ref_linuximage_tab->{'otherpkglist'}; $postinstall_filename = $ref_linuximage_tab->{'postinstall'}; $destdir = $ref_linuximage_tab->{'rootimgdir'}; # TODO: how can we do if the user specifies one wrong value to the following attributes? # currently, one message is output to indicate the users there will be some updates if ($prinic) { if ($prinic ne $ref_linuximage_tab->{'nodebootif'}) { $callback->({info=>["The primary nic is different from the value in linuximage table, will update it."]}); $updates{'nodebootif'} = $prinic; } } else { $prinic = $ref_linuximage_tab->{'nodebootif'}; } if ($othernics) { if ($othernics ne $ref_linuximage_tab->{'otherifce'}) { $callback->({info=>["The other ifces are different from the value in linuximage table, will update it."]}); $updates{'otherifce'} = $othernics; } } else { $othernics = $ref_linuximage_tab->{'otherifce'}; } if ($kernelver) { if ($kernelver ne $ref_linuximage_tab->{'kernelver'}) { $callback->({info=>["The kernelver is different from the value in linuximage table, will update it."]}); $updates{'kernelver'} = $kernelver; } } else { $kernelver = $ref_linuximage_tab->{'kernelver'}; } if ($krpmver) { if ($krpmver ne $ref_linuximage_tab->{'krpmver'}) { $callback->({info=>["The krpmver is different from the value in linuximage table, will update it."]}); $updates{'krpmver'} = $krpmver; } } else { $krpmver = $ref_linuximage_tab->{'krpmver'}; } if ($kerneldir) { if ($kerneldir ne $ref_linuximage_tab->{'kerneldir'}) { print "The kerneldir is different from the value in linuximage table, will update it\n"; $updates{'kerneldir'} = $kerneldir; } } else { $kerneldir = $ref_linuximage_tab->{'kerneldir'}; } if ($netdriver) { if ($netdriver ne $ref_linuximage_tab->{'netdrivers'}) { $callback->({info=>["The netdrivers is different from the value in linuximage table, will update it."]}); $updates{'netdrivers'} = $netdriver; } } else { $netdriver = $ref_linuximage_tab->{'netdrivers'}; } if ($permission) { if ($permission ne $ref_linuximage_tab->{'permission'}) { $callback->({info=>["The permission is different from the value in linuximage table, will update it."]}); $updates{'permission'} = $permission; } } else { $permission = $ref_linuximage_tab->{'permission'}; } } ### Get the Profile #### my $osfamily = $osver; $osfamily =~ s/\d+//g; $osfamily =~ s/\.//g; if($osfamily =~ /rh/){ $osfamily = "rh"; } # OS version on s390x can contain 'sp', e.g. sles11sp1 # If the $osfamily contains 'sles' and 'sp', the $osfamily = sles if ($osfamily =~ /sles/ && $osfamily =~ /sp/) { $osfamily = "sles"; } $osfamily =~ s/ //g; #-m flag is used only for ubuntu, debian and ferdora12, for others genimage will create #initrd.gz for both netboot and statelite, no -m is needed. if ($mode) { if (($osfamily ne "ubuntu") && ($osfamily ne "debian") && ($osver !~ /fedora12/)) { $mode=""; $callback->({error=>["-m flag is valid for Ubuntu, Debian and Fedora12 only."],errorcode=>[1]}); return 1; } } $profDir = "$::XCATROOT/share/xcat/netboot/$osfamily"; unless(-d $profDir){ $callback->({error=>["Unable to find genimage script in $profDir."],errorcode=>[1]}); return 1; } if ($krpmver) { if ($osfamily ne "sles") { $krpmver=""; $callback->({error=>["-g flag is valid for Sles only."],errorcode=>[1]}); return 1; } } my $cmd="cd $profDir; ./genimage"; if ($arch) { $cmd .= " -a $arch";} if ($osver) { $cmd .= " -o $osver";} if ($profile) { $cmd .= " -p $profile";} if ($netdriver) { $cmd .= " -n $netdriver";} if ($prinic) { $cmd .= " -i $prinic";} if ($othernics) { $cmd .= " -r $othernics";} if ($rootlimit) { $cmd .= " -l $rootlimit";} if ($tmplimit) { $cmd .= " -t $tmplimit";} if ($kernelver) { $cmd .= " -k $kernelver";} if ($krpmver) { $cmd .= " -g $krpmver";} if ($mode) { $cmd .= " -m $mode";} if ($permission) { $cmd .= " --permission $permission"; } if ($kerneldir) { $cmd .= " --kerneldir $kerneldir"; } $cmd.= " --internal"; if ($srcdir) { $cmd .= " --srcdir $srcdir";} if ($pkglist) { $cmd .= " --pkglist $pkglist";} if ($srcdir_otherpkgs) { $cmd .= " --otherpkgdir $srcdir_otherpkgs"; } if ($otherpkglist) { $cmd .= " --otherpkglist $otherpkglist"; } if ($postinstall_filename) { $cmd .= " --postinstall $postinstall_filename"; } if ($destdir) { $cmd .= " --rootimgdir $destdir"; } if ($imagename) { $cmd.= " $imagename"; } # now run the specific genimage command $callback->({info=>["$cmd"]}); $::CALLBACK=$callback; #my $output = xCAT::Utils->runcmd("$cmd", 0, 1); my $output = xCAT::Utils->runcmd_S("$cmd", 0, 1); # stream output open(FILE, ">/tmp/genimageoutput"); foreach my $entry (@$output) { print FILE $entry; print FILE "\n"; } close FILE; #save the new settings to the osimage and linuximage tables $cmd="cat /tmp/genimageoutput"; $output = xCAT::Utils->runcmd("$cmd", 0, 1); if ($output && (@$output > 0)) { my $i=0; while ($i < @$output) { if ( $output->[$i] =~ /The output for table updates starts here/) { #print "----got here $i\n"; my $tn; my %keyhash; my %updates; my $s1=$output->[$i +1]; my $s2=$output->[$i +2]; my $s3=$output->[$i +3]; if ($s1 =~ /^table::(.*)$/) { $tn=$1; } if ($s2 =~ /^imagename::(.*)$/) { $keyhash{'imagename'} = $1; } if ($tn eq 'osimage') { %updates=%updates_os; } elsif ($tn eq 'linuximage') { %updates=%updates_linux; } my @a=split("::", $s3); for (my $j=0; $j < @a; $j=$j+2) { $updates{$a[$j]} = $a[$j+1]; } splice(@$output, $i, 5); if (($tn) && (keys(%keyhash) > 0) && (keys(%updates) > 0)) { my $tab= xCAT::Table->new($tn, -create=>1); if ($tab) { $tab->setAttribs(\%keyhash, \%updates); #print "table=$tn,%keyhash,%updates\n"; #print Dumper(%keyhash); #print Dumper(%updates); } } } else { $i++; } } # remove tmp file #`rm /tmp/genimageoutput`; #remove the database upgrade section # runcmd_S displays the output #$callback->({info=>$output}); } } 1;