diff --git a/perl-xCAT/xCAT/Schema.pm b/perl-xCAT/xCAT/Schema.pm index 6741f40fb..de40f3931 100644 --- a/perl-xCAT/xCAT/Schema.pm +++ b/perl-xCAT/xCAT/Schema.pm @@ -624,7 +624,7 @@ osimage => { }, }, linuximage => { - cols => [qw(imagename template pkglist pkgdir otherpkglist otherpkgdir exlist postinstall rootimgdir kerneldir nodebootif otherifce netdrivers kernelver krpmver permission dump crashkernelsize partitionfile comments disable)], + cols => [qw(imagename template pkglist pkgdir otherpkglist otherpkgdir exlist postinstall rootimgdir kerneldir nodebootif otherifce netdrivers kernelver krpmver permission dump crashkernelsize partitionfile driverupdatesrc comments disable)], keys => [qw(imagename)], table_desc => 'Information about a Linux operating system image that can be used to deploy cluster nodes.', descriptions => { @@ -647,6 +647,7 @@ linuximage => { dump => qq{The NFS directory to hold the Linux kernel dump file (vmcore) when the node with this image crashes, its format is "nfs:///". If you want to use the node's "xcatmaster" (its SN or MN), can be left blank. For example, "nfs:///" means the NFS directory to hold the kernel dump file is on the node's SN, or MN if there's no SN.}, crashkernelsize => 'the size that assigned to the kdump kernel. If the kernel size is not set, 256M will be the default value.', partitionfile => 'There are 2 format about this attribute. One is "", the content of the partition file must use the corresponding format with the OS type. The other one is "s:", the content of the partition file should be a shell script which must write the partition difinition into /tmp/partitionfile. This attribute only works for diskful install.', + driverupdatesrc => 'The source of the drivers which need to be loaded during the boot. Two types of driver update source are supported: Driver update disk and Driver rpm package. The value for this attribute should be comma separated sources. Each source should be the format tab:full_path_of_srouce_file. The tab keyword can be: dud (for Driver update disk) and rpm (for driver rpm). If missing the tab, the rpm format is the default. e.g. dud:/install/dud/dd.img,rpm:/install/rpm/d.rpm', comments => 'Any user-written notes.', disable => "Set to 'yes' or '1' to comment out this row.", }, @@ -2104,6 +2105,11 @@ push(@{$defspec{node}->{'attrs'}}, @nodeattrs); tabentry => 'linuximage.partitionfile', access_tabentry => 'linuximage.imagename=attr:imagename', }, + {attr_name => 'driverupdatesrc', + only_if => 'imagetype=linux', + tabentry => 'linuximage.driverupdatesrc', + access_tabentry => 'linuximage.imagename=attr:imagename', + }, #################### # nimimage table# #################### diff --git a/xCAT-server/lib/xcat/plugins/anaconda.pm b/xCAT-server/lib/xcat/plugins/anaconda.pm index c2a8b1521..c7f5b07d2 100644 --- a/xCAT-server/lib/xcat/plugins/anaconda.pm +++ b/xCAT-server/lib/xcat/plugins/anaconda.pm @@ -21,6 +21,8 @@ Getopt::Long::Configure("pass_through"); use File::Path; use File::Copy; use File::Temp qw/mkdtemp/; +use File::Find; +use File::Basename; use Socket; @@ -839,6 +841,8 @@ sub mkinstall my $platform; my $xcatmaster; my $partfile; + my $netdrivers; + my $driverupdatesrc; my $ient = $rents{$node}->[0]; if ($ient and $ient->{xcatmaster}) @@ -885,6 +889,12 @@ sub mkinstall if ($ref1->{'partitionfile'}) { $img_hash{$imagename}->{partitionfile} = $ref1->{'partitionfile'}; } + if ($ref1->{'driverupdatesrc'}) { + $img_hash{$imagename}->{driverupdatesrc}=$ref1->{'driverupdatesrc'}; + } + if ($ref1->{'netdrivers'}) { + $img_hash{$imagename}->{netdrivers}=$ref1->{'netdrivers'}; + } } # if the install template wasn't found, then lets look for it in the default locations. unless($img_hash{$imagename}->{template}){ @@ -932,6 +942,9 @@ sub mkinstall $pkgdir="$installroot/$os/$arch"; } $pkglistfile=$ph->{pkglist}; + + $netdrivers = $ph->{netdrivers}; + $driverupdatesrc = $ph->{driverupdatesrc}; } else { $os = $ent->{os}; @@ -1108,9 +1121,16 @@ sub mkinstall if($esxi){ copyesxiboot($pkgdir, "$tftpdir/xcat/$os/$arch"); }else{ - copy($kernpath,"$tftpdir/xcat/$os/$arch"); - copy($initrdpath,"$tftpdir/xcat/$os/$arch/initrd.img"); - &insert_dd($callback, $os, $arch, "$tftpdir/xcat/$os/$arch/initrd.img"); + my $tftppath; + if ($profile) { + $tftppath = "/$tftpdir/xcat/$os/$arch/$profile"; + } else { + $tftppath = "/$tftpdir/xcat/$os/$arch"; + } + mkpath ("$tftppath"); + copy($kernpath,"$tftppath"); + copy($initrdpath,"$tftppath/initrd.img"); + &insert_dd($callback, $os, $arch, "$tftppath/initrd.img", $driverupdatesrc, $netdrivers); } $doneimgs{"$os|$arch"} = 1; } @@ -1228,8 +1248,13 @@ sub mkinstall $kcmdline .= " --- xcat/$os/$arch/$_"; } }else{ - $k = "xcat/$os/$arch/vmlinuz"; - $i = "xcat/$os/$arch/initrd.img"; + if ($profile) { + $k = "xcat/$os/$arch/$profile/vmlinuz"; + $i = "xcat/$os/$arch/$profile/initrd.img"; + } else { + $k = "xcat/$os/$arch/vmlinuz"; + $i = "xcat/$os/$arch/initrd.img"; + } } $bptab->setNodeAttribs( @@ -1576,31 +1601,530 @@ sub copyesxiboot { } } -# Get the driver update disk from /install/driverdisk// -# Take out the drivers from driver update disk and insert them -# into the initrd +# callback subroutine for 'find' command to return the path +my $driver_name; +my $real_path; +sub get_path () +{ + if ($File::Find::name =~ /\/$driver_name/) { + $real_path = $File::Find::name; + } +} + +# callback subroutine for 'find' command to return the path for all the matches +my @all_real_path; +sub get_all_path () +{ + if ($File::Find::name =~ /\/$driver_name/) { + push @all_real_path, $File::Find::name; + } +} + +# Get the driver disk or driver rpm from the osimage.driverupdatesrc +# The valid value: dud:/install/dud/dd.img,rpm:/install/rpm/d.rpm, if missing the tag: 'dud'/'rpm' +# the 'rpm' is default. +# +# If cannot find the driver disk from osimage.driverupdatesrc, will try to search driver disk +# from /install/driverdisk// +# +# For driver rpm, the driver list will be gotten from osimage.netdrivers. If not set, copy all the drivers from driver +# rpm to the initrd. +# + sub insert_dd { my $callback = shift; my $os = shift; my $arch = shift; my $img = shift; + my $driverupdatesrc = shift; + my $drivers = shift; my $install_dir = xCAT::Utils->getInstallDir(); - # Find out the dirver disk which need to be inserted into initrd - if (! -d "$install_dir/driverdisk/$os/$arch") { - return (); + my $cmd; + + my @inserted_dd = (); + my @dd_drivers = (); + + my @dd_list; + my @rpm_list; + my @driver_list; + + my @rpm_drivers; + + # Parse the parameters to the the source of Driver update disk and Driver rpm, and driver list as well + if ($driverupdatesrc) { + my @srcs = split(',', $driverupdatesrc); + foreach my $src (@srcs) { + if ($src =~ /dud:(.*)/i) { + push @dd_list, $1; + } elsif ($src =~ /rpm:(.*)/i) { + push @rpm_list, $1; + } else { + push @rpm_list, $src; + } + } + } + if (! @dd_list) { + # get Driver update disk from the default path if not specified in osimage + # check the Driver Update Disk images, it can be .img or .iso + if (-d "$install_dir/driverdisk/$os/$arch") { + $cmd = "find $install_dir/driverdisk/$os/$arch -type f"; + @dd_list = xCAT::Utils->runcmd($cmd, -1); + } } - my $cmd = "find $install_dir/driverdisk/$os/$arch -type f"; - my @dd_list = xCAT::Utils->runcmd($cmd, -1); - chomp(@dd_list); - if (!@dd_list) { - return (); + foreach (split /,/,$drivers) { + unless (/\.ko$/) { + s/$/.ko/; + } + push @driver_list, $_; } + + chomp(@dd_list); + chomp(@rpm_list); + + unless (@dd_list || @rpm_list ) { + return undef; + } + # Create the tmp dir for dd hack my $dd_dir = mkdtemp("/tmp/ddtmpXXXXXXX"); - if (<$install_dir/$os/$arch/Packages/dracut*>) { #new style, skip the fanagling, copy over the dds and append them... + + # regenerate the original initrd for non dracut or need to add the drivers from rpm packages + # dracut + drvier rpm + # !dracut + driver rpm + # !dracut + driver disk + if (!<$install_dir/$os/$arch/Packages/dracut*> || @rpm_list) { + mkpath "$dd_dir/initrd_img"; # The dir for the new initrd + + # unzip the initrd image + $cmd = "gunzip -c $img > $dd_dir/initrd"; + xCAT::Utils->runcmd($cmd, -1); + if ($::RUNCMD_RC != 0) { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update disk failed. Could not gunzip the initial initrd."; + xCAT::MsgUtils->message("E", $rsp, $callback); + return undef; + } + + # Extract the files from original initrd + $cmd = "cd $dd_dir/initrd_img; cpio -id --quiet < ../initrd"; + xCAT::Utils->runcmd($cmd, -1); + if ($::RUNCMD_RC != 0) { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update disk failed. Could not extract files from the initial initrd."; + xCAT::MsgUtils->message("E", $rsp, $callback); + return undef; + } + + if (@rpm_list) { + # Extract the files from rpm to the tmp dir + mkpath "$dd_dir/rpm"; + foreach my $rpm (@rpm_list) { + if (-r $rpm) { + $cmd = "cd $dd_dir/rpm; rpm2cpio $rpm | cpio -idum"; + xCAT::Utils->runcmd($cmd, -1); + if ($::RUNCMD_RC != 0) { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update failed. Could not extract files from the rpm $rpm."; + xCAT::MsgUtils->message("I", $rsp, $callback); + } + } else { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update failed. Could not read the rpm $rpm."; + xCAT::MsgUtils->message("I", $rsp, $callback); + } + } + } + + # The rh6 has different initrd format with old version (rh 5.x) + # The new format of initrd is made by dracut, it has the /lib/modules/ + # directory like the root image + # If the os has dracut rpm packet, then copy the drivers to the /lib/modules/ + # and recreate the dependency by the depmod command + + if (<$install_dir/$os/$arch/Packages/dracut*>) { #rh6, fedora13 ... + # For dracut mode, only copy the drivers from rpm packages to the /lib/modules/ + # The driver disk will be handled that append the whole disk to the orignial initrd + + if (@rpm_list) { + # Copy the firmware to the rootimage + if (-d "$dd_dir/rpm/lib/firmware") { + if (! -d "$dd_dir/initrd_img/lib") { + mkpath "$dd_dir/initrd_img/lib"; + } + $cmd = "cp -rf $dd_dir/rpm/lib/firmware $dd_dir/initrd_img/lib"; + xCAT::Utils->runcmd($cmd, -1); + if ($::RUNCMD_RC != 0) { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update failed. Could not copy firmware to the initrd."; + xCAT::MsgUtils->message("I", $rsp, $callback); + } + } + + # Copy the drivers to the initrd + # Figure out the kernel version + my @kernelpaths = <$dd_dir/initrd_img/lib/modules/*>; + my @kernelvers; + foreach (@kernelpaths) { + if (basename($_) =~ /^[\d\.]+/) { + push @kernelvers, basename($_); + } + } + + foreach my $kernelver (@kernelvers) { + if (@driver_list) { + foreach my $driver (@driver_list) { + $driver_name = $driver; + $real_path = ""; + find(\&get_path, <$dd_dir/rpm/lib/modules/$kernelver/*>); + if ($real_path && $real_path =~ m!$dd_dir/rpm(/lib/modules/$kernelver/.*?)[^\/]*$!) { + if (! -d "$dd_dir/initrd_img$1") { + mkpath "$dd_dir/initrd_img$1"; + } + $cmd = "cp -rf $real_path $dd_dir/initrd_img$1"; + xCAT::Utils->runcmd($cmd, -1); + if ($::RUNCMD_RC != 0) { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update failed. Could not copy driver $driver to the initrd."; + xCAT::MsgUtils->message("I", $rsp, $callback); + } else { + push @rpm_drivers, $driver; + } + } + } + } else { + # copy all the drviers to the rootimage + if (-d "$dd_dir/rpm/lib/modules/$kernelver") { + $cmd = "cp -rf $dd_dir/rpm/lib/modules/$kernelver $dd_dir/initrd_img/lib/modules/"; + xCAT::Utils->runcmd($cmd, -1); + if ($::RUNCMD_RC != 0) { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update failed. Could not copy /lib/modules/$kernelver to the initrd."; + xCAT::MsgUtils->message("I", $rsp, $callback); + } + } else { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update failed. Could not find /lib/modules/$kernelver from the driver rpms."; + xCAT::MsgUtils->message("I", $rsp, $callback); + } + } + + # regenerate the modules dependency + foreach my $kernelver (@kernelvers) { + $cmd = "depmod -b $dd_dir/initrd_img $kernelver"; + xCAT::Utils->runcmd($cmd, -1); + if ($::RUNCMD_RC != 0) { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update failed. Could not generate the depdency for the drivers in the initrd."; + xCAT::MsgUtils->message("I", $rsp, $callback); + } + } + } + } + } else {# non dracut mode, for rh5, fedora12 ... + # For non-dracut mode, the drviers need to be merged into the initrd with the specific format + + # Create directory for the driver modules hack + mkpath "$dd_dir/modules"; + + # Extract files from the modules.cgz of initrd + $cmd = "cd $dd_dir/modules; gunzip -c $dd_dir/initrd_img/modules/modules.cgz | cpio -id"; + xCAT::Utils->runcmd($cmd, -1); + if ($::RUNCMD_RC != 0) { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update disk failed. Could not gunzip modules.cgz from the initial initrd."; + xCAT::MsgUtils->message("E", $rsp, $callback); + return undef; + } + + my @modinfo = (); + foreach my $dd (@dd_list) { + mkpath "$dd_dir/mnt"; + mkpath "$dd_dir/dd_modules"; + + $cmd = "mount -o loop $dd $dd_dir/mnt"; + xCAT::Utils->runcmd($cmd, -1); + if ($::RUNCMD_RC != 0) { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update disk failed. Could not mount the driver update disk."; + xCAT::MsgUtils->message("E", $rsp, $callback); + return undef; + } + + $cmd = "cd $dd_dir/dd_modules; gunzip -c $dd_dir/mnt/modules.cgz | cpio -id"; + xCAT::Utils->runcmd($cmd, -1); + + if ($::RUNCMD_RC != 0) { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update disk failed. Could not gunzip the modules.cgz from the driver update disk."; + xCAT::MsgUtils->message("E", $rsp, $callback); + system("umount -f $dd_dir/mnt"); + return undef; + } + + # Copy all the driver files out + $cmd = "cp -rf $dd_dir/dd_modules/* $dd_dir/modules"; + xCAT::Utils->runcmd($cmd, -1); + + # Copy the firmware into the initrd + mkpath "$dd_dir/initrd_img/firmware"; + $cmd = "cp -rf $dd_dir/dd_modules/firmware/* $dd_dir/initrd_img/firmware"; + xCAT::Utils->runcmd($cmd, -1); + + my $drivername; + # Get the entries from modinfo + open (DDMODINFO, "<", "$dd_dir/mnt/modinfo"); + while () { + if ($_ =~ /^Version/) { next; } + if ($_ =~ /^(\S+)/) { + push @dd_drivers, $1; + $drivername=$1; + } + push @modinfo, $_; + } + close (DDMODINFO); + + # Append the modules.alias + if (-r "$dd_dir/mnt/modules.alias") { + $cmd = "cat $dd_dir/mnt/modules.alias >> $dd_dir/initrd_img/modules/modules.alias"; + xCAT::Utils->runcmd($cmd, -1); + } + + # Append the modules.dep + my $depfile; + my $target; + open($target,">>","$dd_dir/initrd_img/modules/modules.dep"); + open($depfile,"<","$dd_dir/mnt/modules.dep"); + my $curline; + while ($curline=<$depfile>) { + if ($curline !~ /:/) { #missing the rather important first half of the equation here.... + $curline = $drivername.": ".$curline; + } + print $target $curline; + } + close($target); + close($depfile); + + # Append the pcitable + if (-r "$dd_dir/mnt/pcitable") { + $cmd = "cat $dd_dir/mnt/pcitable >> $dd_dir/initrd_img/modules/pcitable"; + xCAT::Utils->runcmd($cmd, -1); + } + + if (-r "$dd_dir/mnt/modules.pcimap") { + $cmd = "cat $dd_dir/mnt/modules.pcimap >> $dd_dir/initrd_img/modules/modules.pcimap"; + xCAT::Utils->runcmd($cmd, -1); + } + + $cmd = "umount -f $dd_dir/mnt"; + xCAT::Utils->runcmd($cmd, -1); + if ($::RUNCMD_RC != 0) { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update disk failed. Could not unmount the driver update disk."; + xCAT::MsgUtils->message("E", $rsp, $callback); + system("umount -f $dd_dir/mnt"); + return undef; + } + + # Clean the env + rmtree "$dd_dir/mnt"; + rmtree "$dd_dir/dd_modules"; + + push @inserted_dd, $dd; + } + + # Merge the drviers from rpm packages to the initrd + if (@rpm_list) { + # Copy the firmware to the rootimage + if (-d "$dd_dir/rpm/lib/firmware") { + if (! -d "$dd_dir/initrd_img/lib") { + mkpath "$dd_dir/initrd_img/lib"; + } + $cmd = "cp -rf $dd_dir/rpm/lib/firmware $dd_dir/initrd_img"; + xCAT::Utils->runcmd($cmd, -1); + if ($::RUNCMD_RC != 0) { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update failed. Could not copy firmware to the initrd."; + xCAT::MsgUtils->message("I", $rsp, $callback); + } + } + + # Copy the drivers to the initrd + # Figure out the kernel version + my @kernelpaths = <$dd_dir/modules/*>; + my @kernelvers; + foreach (@kernelpaths) { + push @kernelvers, basename($_); + } + + foreach my $kernelver (@kernelvers) { + # find the $kernelver/$arch dir in the $dd_dir/modules + my $arch4modules; + foreach (<$dd_dir/modules/$kernelver/*>) { + if (basename($_) =~ $arch) { + $arch4modules = basename($_); + } + } + if (!$arch4modules) { + $arch4modules = basename(<$dd_dir/modules/$kernelver/*>); + } + if (! -d "$dd_dir/modules/$kernelver/$arch4modules/") { + next; + } + if (@driver_list) { + # copy all the specific drviers to the initrd + foreach my $driver (@driver_list) { + $driver_name = $driver; + $real_path = ""; + find(\&get_path, <$dd_dir/rpm/lib/modules/$kernelver/*>); + if ($real_path ) { + + $cmd = "cp -rf $real_path $dd_dir/modules/$kernelver/$arch4modules/"; + xCAT::Utils->runcmd($cmd, -1); + if ($::RUNCMD_RC != 0) { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update failed. Could not copy driver $driver to the initrd."; + xCAT::MsgUtils->message("I", $rsp, $callback); + } else { + push @rpm_drivers, $driver; + } + } + } + } else { + # copy all the drviers to the initrd + if (-d "$dd_dir/rpm/lib/modules/$kernelver") { + find(\&get_all_path, <$dd_dir/rpm/lib/modules/$kernelver/*>); + foreach my $driverpath (@all_real_path) { + $cmd = "cp -rf $driverpath $dd_dir/modules/$kernelver/$arch4modules/"; + xCAT::Utils->runcmd($cmd, -1); + if ($::RUNCMD_RC != 0) { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update failed. Could not copy $driverpath to the initrd."; + xCAT::MsgUtils->message("I", $rsp, $callback); + } + if ($driverpath =~ s/([^\/]*)\.ko//) { + push @rpm_drivers, $1; + } + } + } else { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update failed. Could not find /lib/modules/$kernelver from the driver rpms."; + xCAT::MsgUtils->message("I", $rsp, $callback); + } + } + + # Append the modules.dep to the one in the initrd + if (-f "$dd_dir/rpm/lib/modules/$kernelver/modules.dep") { + $cmd = "cat $dd_dir/rpm/lib/modules/$kernelver/modules.dep >> $dd_dir/initrd_img/modules/modules.dep"; + xCAT::Utils->runcmd($cmd, -1); + } + } + } + + # Regenerate the modules.dep + # 'depmod' command only can handle the drivers in /lib/modules/kernelver strcuture, so copy the drivers to a temporary + # dirctory $dd_dir/depmod/lib/modules/$mk, run 'depmod' and copy the modules.dep to the correct dir + my ($mk, $ma); + $mk = <$dd_dir/modules/*>; + if (-d $mk) { + $mk = basename($mk); + $ma = <$dd_dir/modules/$mk/*>; + if (-d $ma) { + mkpath "$dd_dir/depmod/lib/modules/$mk"; + xCAT::Utils->runcmd("cp -rf $ma/* $dd_dir/depmod/lib/modules/$mk", -1); + $cmd = "depmod -b $dd_dir/depmod/"; + xCAT::Utils->runcmd($cmd, -1); + if ($::RUNCMD_RC != 0) { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update failed. Could not generate the depdency for the drivers in the initrd."; + xCAT::MsgUtils->message("I", $rsp, $callback); + } + if (-f "$dd_dir/depmod/lib/modules/$mk/modules.dep") { + copy ("$dd_dir/depmod/lib/modules/$mk/modules.dep", "$dd_dir/initrd_img/modules/modules.dep"); + } + + # remove the path and postfix of the driver modules from the new generated modules.dep since original format has not path and postfix + my @newdep; + if (open (DEP, "<$dd_dir/initrd_img/modules/modules.dep")) { + while () { + s/\/lib\/modules\/$mk\/([^\.]+)\.ko/$1/g; + if (/:\s*\S+/) { + push @newdep, $_; + } + } + close (DEP); + } + if (open (NEWDEP, ">$dd_dir/initrd_img/modules/modules.dep")) { + print NEWDEP @newdep; + close (NEWDEP); + } + } + } + + + # Append the modinfo into the module-info + open (MODINFO, "<", "$dd_dir/initrd_img/modules/module-info"); + open (MODINFONEW, ">", "$dd_dir/initrd_img/modules/module-info.new"); + my $removeflag = 0; + my @orig_drivers; + while () { + my $line = $_; + if ($line =~ /^(\S+)/) { + if (grep /$1/, @dd_drivers) { + $removeflag = 1; + next; + } else { + push @orig_drivers, $1; + $removeflag = 0; + } + } + + if ($removeflag == 1) { next; } + print MODINFONEW $line; + } + + print MODINFONEW @modinfo; + + # add the drivers from rpm + foreach my $dr (@rpm_drivers) { + $dr =~ s/\.ko//; + if (! grep /^$dr$/, (@orig_drivers,@dd_drivers)) { + print MODINFONEW $dr."\n"; + } + } + + close (MODINFONEW); + close (MODINFO); + move ("$dd_dir/initrd_img/modules/module-info.new", "$dd_dir/initrd_img/modules/module-info"); + + # Repack the modules + $cmd = "cd $dd_dir/modules; find . -print | cpio -o -H crc | gzip -9 > $dd_dir/initrd_img/modules/modules.cgz"; + xCAT::Utils->runcmd($cmd, -1); + if ($::RUNCMD_RC != 0) { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update disk failed. Could not pack the hacked modules.cgz."; + xCAT::MsgUtils->message("E", $rsp, $callback); + return undef; + } + } # End of non dracut + + # Repack the initrd + $cmd = "cd $dd_dir/initrd_img; find .|cpio -H newc -o|gzip -9 -c - > $dd_dir/initrd.img"; + xCAT::Utils->runcmd($cmd, -1); + if ($::RUNCMD_RC != 0) { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update disk failed. Could not pack the hacked initrd."; + xCAT::MsgUtils->message("E", $rsp, $callback); + return undef; + } + + copy ("$dd_dir/initrd.img", $img); + } + + # dracut + driver disk, just append the driver disk to the initrd + if (<$install_dir/$os/$arch/Packages/dracut*> && @dd_list) { #new style, skip the fanagling, copy over the dds and append them... mkpath("$dd_dir/dd"); if (scalar(@dd_list) == 1) { #only one, just append it.. copy($dd_list[0],"$dd_dir/dd/dd.img"); @@ -1627,323 +2151,39 @@ sub insert_dd { } else { #there should be no else... die "This should never occur"; } - chdir($dd_dir."/dd"); - $cmd = "find .|cpio -H newc -o|gzip -9 -c - > ../dd.gz"; - xCAT::Utils->runcmd($cmd, -1); - unless (-f "../dd.gz") { - die "Error attempting to archive driver disk"; - } - my $ddhdl; - my $inithdl; - open($inithdl,">>",$img); - open($ddhdl,"<","../dd.gz"); - binmode($ddhdl); - binmode($inithdl); - { - local $/ = \32768; - while (my $block = <$ddhdl>) { print $inithdl $block; } - } - chdir("/"); - xCAT::Utils->runcmd("rm -rf $dd_dir"); - my $rsp; - push @{$rsp->{data}}, "Inserted the driver update disk:".join(',',@dd_list)."."; - xCAT::MsgUtils->message("I", $rsp, $callback); - - return @dd_list; - return; + + chdir($dd_dir."/dd"); + $cmd = "find .|cpio -H newc -o|gzip -9 -c - > ../dd.gz"; + xCAT::Utils->runcmd($cmd, -1); + unless (-f "../dd.gz") { + die "Error attempting to archive driver disk"; + } + my $ddhdl; + my $inithdl; + open($inithdl,">>",$img); + open($ddhdl,"<","../dd.gz"); + binmode($ddhdl); + binmode($inithdl); + { + local $/ = \32768; + while (my $block = <$ddhdl>) { print $inithdl $block; } + } + chdir("/"); + push @inserted_dd, @dd_list; } - mkpath "$dd_dir/initrd_img"; # The dir for the new initrd - - # unzip the initrd image - $cmd = "gunzip -c $img > $dd_dir/initrd"; - xCAT::Utils->runcmd($cmd, -1); - if ($::RUNCMD_RC != 0) { - my $rsp; - push @{$rsp->{data}}, "Handle the driver update disk failed. Could not gunzip the initial initrd."; - xCAT::MsgUtils->message("E", $rsp, $callback); - return undef; - } - - # Extract the files from original initrd - $cmd = "cd $dd_dir/initrd_img; cpio -id --quiet < ../initrd"; - xCAT::Utils->runcmd($cmd, -1); - if ($::RUNCMD_RC != 0) { - my $rsp; - push @{$rsp->{data}}, "Handle the driver update disk failed. Could not extract files from the initial initrd."; - xCAT::MsgUtils->message("E", $rsp, $callback); - return undef; - } - - # Create directory for the driver modules hack - mkpath "$dd_dir/modules"; - - my @inserted_dd = (); - my @dd_drivers = (); - - # The rh6 has different initrd format with old version (rh 5.x) - # The new format of initrd is made by dracut, it has the /lib/modules/ - # directory like the root image - # If the os has dracut rpm packet, then copy the drivers to the /lib/modules/ - # and recreate the dependency by the depmod command - - $cmd = "find $install_dir/$os/$arch/ | grep dracut"; - my @dracut = xCAT::Utils->runcmd($cmd, -1); - if (grep (/dracut-.*\.rpm/, @dracut)) {#dracut mode, for rh6, fedora13 ... - #copy the firmware into the initrd - if (-d "$dd_dir/mnt/firmware") { - $cmd = "cp -rf $dd_dir/mnt/firmware/* $dd_dir/initrd_img/lib/firmware"; - xCAT::Utils->runcmd($cmd, -1); - } - - # Figure out the kernel version of the initrd - my $kernelver; - opendir (KERNEL, "$dd_dir/initrd_img/lib/modules"); - while ($kernelver = readdir(KERNEL)) { - if ($kernelver =~ /^\./ || $kernelver !~ /^\d/) { - $kernelver = ""; - next; - } - if (-d "$dd_dir/initrd_img/lib/modules/$kernelver") { - last; - } - $kernelver = ""; - } - - # The initrd has problem - if ($kernelver eq "") { - return (); - } - - # Copy the drivers to the lib/modules/<$kernelver>/ - if (! -d "$dd_dir/initrd_img/lib/modules/$kernelver/kernel/drivers/driverdisk") { - mkpath "$dd_dir/initrd_img/lib/modules/$kernelver/kernel/drivers/driverdisk"; - } - - foreach my $dd (@dd_list) { - mkpath "$dd_dir/mnt"; - mkpath "$dd_dir/dd_modules"; - - $cmd = "mount -o loop $dd $dd_dir/mnt"; - xCAT::Utils->runcmd($cmd, -1); - if ($::RUNCMD_RC != 0) { - my $rsp; - push @{$rsp->{data}}, "Handle the driver update disk failed. Could not mount the driver update disk."; - xCAT::MsgUtils->message("E", $rsp, $callback); - return undef; - } - - $cmd = "cd $dd_dir/dd_modules; gunzip -c $dd_dir/mnt/modules.cgz | cpio -id"; - xCAT::Utils->runcmd($cmd, -1); - - if ($::RUNCMD_RC != 0) { - my $rsp; - push @{$rsp->{data}}, "Handle the driver update disk failed. Could not gunzip the modules.cgz from the driver update disk."; - xCAT::MsgUtils->message("E", $rsp, $callback); - system("umount -f $dd_dir/mnt"); - return undef; - } - - # Get all the drivers which belong to $kernelver/$arch - $cmd = "find $dd_dir/dd_modules/$kernelver/$arch/ -type f"; - - my @drivers = xCAT::Utils->runcmd($cmd, -1); - foreach my $d (@drivers) { - chomp($d); - # The drivers in the initrd is in zip format - $cmd = "gzip $d"; - xCAT::Utils->runcmd($cmd, -1); - $d .= ".gz"; - - my $driver_name = $d; - $driver_name =~ s/.*\///; - - # If the driver file existed, then over write - $cmd = "find $dd_dir/initrd_img/lib/modules/$kernelver -type f -name $driver_name"; - my @exist_file = xCAT::Utils->runcmd($cmd, -1); - if (! @exist_file) { - $cmd = "cp $d $dd_dir/initrd_img/lib/modules/$kernelver/kernel/drivers/driverdisk"; - } else { - $cmd = "cp $d $exist_file[0]"; - } - xCAT::Utils->runcmd($cmd, -1); - } - - $cmd = "umount -f $dd_dir/mnt"; - xCAT::Utils->runcmd($cmd, -1); - if ($::RUNCMD_RC != 0) { - my $rsp; - push @{$rsp->{data}}, "Handle the driver update disk failed. Could not unmount the driver update disk."; - xCAT::MsgUtils->message("E", $rsp, $callback); - system("umount -f $dd_dir/mnt"); - return undef; - } - - # Clean the env - rmtree "$dd_dir/mnt"; - rmtree "$dd_dir/dd_modules"; - - push @inserted_dd, $dd; - } - - # Generate the dependency relationship - $cmd = "chroot $dd_dir/initrd_img/ depmod $kernelver"; - xCAT::Utils->runcmd($cmd, -1); - } else { - # Extract files from the modules.cgz of initrd - $cmd = "cd $dd_dir/modules; gunzip -c $dd_dir/initrd_img/modules/modules.cgz | cpio -id"; - xCAT::Utils->runcmd($cmd, -1); - if ($::RUNCMD_RC != 0) { - my $rsp; - push @{$rsp->{data}}, "Handle the driver update disk failed. Could not gunzip modules.cgz from the initial initrd."; - xCAT::MsgUtils->message("E", $rsp, $callback); - return undef; - } - - my @modinfo = (); - foreach my $dd (@dd_list) { - mkpath "$dd_dir/mnt"; - mkpath "$dd_dir/dd_modules"; - - $cmd = "mount -o loop $dd $dd_dir/mnt"; - xCAT::Utils->runcmd($cmd, -1); - if ($::RUNCMD_RC != 0) { - my $rsp; - push @{$rsp->{data}}, "Handle the driver update disk failed. Could not mount the driver update disk."; - xCAT::MsgUtils->message("E", $rsp, $callback); - return undef; - } - - $cmd = "cd $dd_dir/dd_modules; gunzip -c $dd_dir/mnt/modules.cgz | cpio -id"; - xCAT::Utils->runcmd($cmd, -1); - - if ($::RUNCMD_RC != 0) { - my $rsp; - push @{$rsp->{data}}, "Handle the driver update disk failed. Could not gunzip the modules.cgz from the driver update disk."; - xCAT::MsgUtils->message("E", $rsp, $callback); - system("umount -f $dd_dir/mnt"); - return undef; - } - - # Copy all the driver files out - $cmd = "cp -rf $dd_dir/dd_modules/* $dd_dir/modules"; - xCAT::Utils->runcmd($cmd, -1); - - # Copy the firmware into the initrd - mkpath "$dd_dir/initrd_img/firmware"; - $cmd = "cp -rf $dd_dir/dd_modules/firmware/* $dd_dir/initrd_img/firmware"; - xCAT::Utils->runcmd($cmd, -1); - - # Get the entries from modinfo - my $drivername; - open (DDMODINFO, "<", "$dd_dir/mnt/modinfo"); - while () { - if ($_ =~ /^Version/) { next; } - if ($_ =~ /^(\S+)/) { - push @dd_drivers, $1; - $drivername=$1; - } - push @modinfo, $_; - } - close (DDMODINFO); - - # Append the modules.alias - $cmd = "cat $dd_dir/mnt/modules.alias >> $dd_dir/initrd_img/modules/modules.alias"; - xCAT::Utils->runcmd($cmd, -1); - - # Append the modules.dep - my $depfile; - my $target; - open($target,">>","$dd_dir/initrd_img/modules/modules.dep"); - open($depfile,"<","$dd_dir/mnt/modules.dep"); - my $curline; - while ($curline=<$depfile>) { - if ($curline !~ /:/) { #missing the rather important first half of the equation here.... - $curline = $drivername.": ".$curline; - } - print $target $curline; - } - close($target); - close($depfile); - - # Append the pcitable - if (-r "$dd_dir/mnt/pcitable") { - $cmd = "cat $dd_dir/mnt/pcitable >> $dd_dir/initrd_img/modules/pcitable"; - xCAT::Utils->runcmd($cmd, -1); - } - if (-r "$dd_dir/mnt/modules.pcimap") { - $cmd = "cat $dd_dir/mnt/modules.pcimap >> $dd_dir/initrd_img/modules/modules.pcimap"; - xCAT::Utils->runcmd($cmd, -1); - } - - $cmd = "umount -f $dd_dir/mnt"; - xCAT::Utils->runcmd($cmd, -1); - if ($::RUNCMD_RC != 0) { - my $rsp; - push @{$rsp->{data}}, "Handle the driver update disk failed. Could not unmount the driver update disk."; - xCAT::MsgUtils->message("E", $rsp, $callback); - system("umount -f $dd_dir/mnt"); - return undef; - } - - # Clean the env - rmtree "$dd_dir/mnt"; - rmtree "$dd_dir/dd_modules"; - - push @inserted_dd, $dd; - } - - # Append the modinfo into the module-info - open (MODINFO, "<", "$dd_dir/initrd_img/modules/module-info"); - open (MODINFONEW, ">", "$dd_dir/initrd_img/modules/module-info.new"); - my $removeflag = 0; - while () { - my $line = $_; - if ($line =~ /^(\S+)/) { - if (grep /$1/, @dd_drivers) { - $removeflag = 1; - next; - } else { - $removeflag = 0; - } - } - - if ($removeflag == 1) { next; } - print MODINFONEW $line; - } - - print MODINFONEW @modinfo; - close (MODINFONEW); - close (MODINFO); - move ("$dd_dir/initrd_img/modules/module-info.new", "$dd_dir/initrd_img/modules/module-info"); - - # Repack the modules - $cmd = "cd $dd_dir/modules; find . -print | cpio -o -H crc | gzip -9 > $dd_dir/initrd_img/modules/modules.cgz"; - xCAT::Utils->runcmd($cmd, -1); - if ($::RUNCMD_RC != 0) { - my $rsp; - push @{$rsp->{data}}, "Handle the driver update disk failed. Could not pack the hacked modules.cgz."; - xCAT::MsgUtils->message("E", $rsp, $callback); - return undef; - } - } # End of non dracut - - # Repack the initrd - $cmd = "cd $dd_dir/initrd_img; find .|cpio -H newc -o|gzip -9 -c - > $dd_dir/initrd.img"; - xCAT::Utils->runcmd($cmd, -1); - if ($::RUNCMD_RC != 0) { - my $rsp; - push @{$rsp->{data}}, "Handle the driver update disk failed. Could not pack the hacked initrd."; - xCAT::MsgUtils->message("E", $rsp, $callback); - return undef; - } - - copy ("$dd_dir/initrd.img", $img); - + # clean the env rmtree $dd_dir; - + my $rsp; - push @{$rsp->{data}}, "Inserted the driver update disk:".join(',',@inserted_dd)."."; + if (@dd_list) { + push @{$rsp->{data}}, "Inserted the driver update disk:".join(',',@inserted_dd)."."; + } + if (@driver_list) { + push @{$rsp->{data}}, "Inserted the drivers:".join(',', sort(@rpm_drivers))." from driver packages."; + } elsif (@rpm_list) { + push @{$rsp->{data}}, "Inserted the drivers from driver packages:".join(',', sort(@rpm_list))."."; + } xCAT::MsgUtils->message("I", $rsp, $callback); return @inserted_dd; diff --git a/xCAT-server/lib/xcat/plugins/genimage.pm b/xCAT-server/lib/xcat/plugins/genimage.pm index 5db295fb9..714e0a822 100644 --- a/xCAT-server/lib/xcat/plugins/genimage.pm +++ b/xCAT-server/lib/xcat/plugins/genimage.pm @@ -132,7 +132,7 @@ sub process_request { return 1; } - (my $ref_linuximage_tab) = $linuximagetab->getAttribs({imagename => $imagename}, 'pkglist', 'pkgdir', 'otherpkglist', 'otherpkgdir', 'postinstall', 'rootimgdir', 'kerneldir', 'krpmver', 'nodebootif', 'otherifce', 'kernelver', 'netdrivers', 'permission'); + (my $ref_linuximage_tab) = $linuximagetab->getAttribs({imagename => $imagename}, 'pkglist', 'pkgdir', 'otherpkglist', 'otherpkgdir', 'postinstall', 'rootimgdir', 'kerneldir', 'krpmver', 'nodebootif', 'otherifce', 'kernelver', 'netdrivers', 'permission','driverupdatesrc'); unless ($ref_linuximage_tab) { $callback->({error=>["Cannot find $imagename from the linuximage table."],errorcode=>[1]}); return 1; @@ -164,6 +164,7 @@ sub process_request { $otherpkglist = $ref_linuximage_tab->{'otherpkglist'}; $postinstall_filename = $ref_linuximage_tab->{'postinstall'}; $destdir = $ref_linuximage_tab->{'rootimgdir'}; + $driverupdatesrc = $ref_linuximage_tab->{'driverupdatesrc'}; # 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 @@ -294,6 +295,7 @@ sub process_request { if ($postinstall_filename) { $cmd .= " --postinstall $postinstall_filename"; } if ($destdir) { $cmd .= " --rootimgdir $destdir"; } if ($tempfile) { $cmd .= " --tempfile $tempfile"; } + if ($driverupdatesrc) { $cmd .= " --driverupdatesrc $driverupdatesrc"; } if ($imagename) { $cmd.= " $imagename"; diff --git a/xCAT-server/lib/xcat/plugins/sles.pm b/xCAT-server/lib/xcat/plugins/sles.pm index 67e1a784a..2554a0d0b 100644 --- a/xCAT-server/lib/xcat/plugins/sles.pm +++ b/xCAT-server/lib/xcat/plugins/sles.pm @@ -22,6 +22,8 @@ use File::Copy; use File::Temp qw/mkdtemp/; my $httpmethod = "http"; my $httpport = "80"; +use File::Find; +use File::Basename; use Socket; @@ -646,6 +648,8 @@ sub mkinstall my $plat = ""; my $tftpdir; my $partfile; + my $netdrivers; + my $driverupdatesrc; if ($resents->{$node} and $resents->{$node}->[0]->{tftpdir}) { $tftpdir = $resents->{$node}->[0]->{tftpdir}; } else { @@ -668,7 +672,7 @@ sub mkinstall if (!$linuximagetab) { $linuximagetab=xCAT::Table->new('linuximage', -create=>1); } - (my $ref1) = $linuximagetab->getAttribs({imagename => $imagename}, 'template', 'pkgdir', 'pkglist'); + (my $ref1) = $linuximagetab->getAttribs({imagename => $imagename}, 'template', 'pkgdir', 'pkglist', 'driverupdatesrc', 'netdrivers'); if ($ref1) { if ($ref1->{'template'}) { $img_hash{$imagename}->{template}=$ref1->{'template'}; @@ -682,6 +686,12 @@ sub mkinstall if ($ref1->{'partitionfile'}) { $img_hash{$imagename}->{partitionfile}=$ref1->{'partitionfile'}; } + if ($ref1->{'driverupdatesrc'}) { + $img_hash{$imagename}->{driverupdatesrc}=$ref1->{'driverupdatesrc'}; + } + if ($ref1->{'netdrivers'}) { + $img_hash{$imagename}->{netdrivers}=$ref1->{'netdrivers'}; + } } } else { $callback->( @@ -702,6 +712,8 @@ sub mkinstall } $pkglistfile=$ph->{pkglist}; $partfile=$ph->{partitionfile}; + $netdrivers = $ph->{netdrivers}; + $driverupdatesrc = $ph->{driverupdatesrc}; } else { $os = $ent->{os}; @@ -827,26 +839,27 @@ sub mkinstall #TODO: driver slipstream, targetted for network. unless ($doneimgs{"$os|$arch|$tftpdir"}) { - mkpath("/$tftpdir/xcat/$os/$arch"); + my $tftppath; + if ($profile) { + $tftppath = "/$tftpdir/xcat/$os/$arch/$profile"; + } else { + $tftppath = "/$tftpdir/xcat/$os/$arch"; + } + mkpath("$tftppath"); if ($arch =~ /x86_64/) { - copy("$pkgdir/1/boot/$arch/loader/linux", - "/$tftpdir/xcat/$os/$arch/"); - copy("$pkgdir/1/boot/$arch/loader/initrd", - "/$tftpdir/xcat/$os/$arch/"); - @dd_drivers = &insert_dd($callback, $os, $arch, "/$tftpdir/xcat/$os/$arch/initrd"); + copy("$pkgdir/1/boot/$arch/loader/linux", "$tftppath"); + copy("$pkgdir/1/boot/$arch/loader/initrd", "$tftppath"); + @dd_drivers = &insert_dd($callback, $os, $arch, "$tftppath/initrd", $driverupdatesrc, $netdrivers); } elsif ($arch =~ /x86/) { - copy("$pkgdir/1/boot/i386/loader/linux", - "/$tftpdir/xcat/$os/$arch/"); - copy("$pkgdir/1/boot/i386/loader/initrd", - "/$tftpdir/xcat/$os/$arch/"); - @dd_drivers = &insert_dd($callback, $os, $arch, "/$tftpdir/xcat/$os/$arch/initrd"); + copy("$pkgdir/1/boot/i386/loader/linux", "$tftppath"); + copy("$pkgdir/1/boot/i386/loader/initrd", "$tftppath"); + @dd_drivers = &insert_dd($callback, $os, $arch, "$tftppath/initrd", $driverupdatesrc, $netdrivers); } elsif ($arch =~ /ppc/) { - copy("$pkgdir/1/suseboot/inst64", - "/$tftpdir/xcat/$os/$arch"); - @dd_drivers = &insert_dd($callback, $os, $arch, "/$tftpdir/xcat/$os/$arch/inst64"); + copy("$pkgdir/1/suseboot/inst64", "$tftppath"); + @dd_drivers = &insert_dd($callback, $os, $arch, "$tftppath/inst64", $driverupdatesrc, $netdrivers); } $doneimgs{"$os|$arch|$tftpdir"} = 1; } @@ -953,23 +966,39 @@ sub mkinstall { $kcmdline .= " dhcptimeout=150"; } + + my $kernelpath; + my $initrdpath; + if ($arch =~ /x86/) { + if ($profile) { + $kernelpath = "xcat/$os/$arch/$profile/linux"; + $initrdpath = "xcat/$os/$arch/$profile/initrd"; + } else { + $kernelpath = "xcat/$os/$arch/linux"; + $initrdpath = "xcat/$os/$arch/initrd"; + } $bptab->setNodeAttribs( $node, { - kernel => "xcat/$os/$arch/linux", - initrd => "xcat/$os/$arch/initrd", + kernel => $kernelpath, + initrd => $initrdpath, kcmdline => $kcmdline } ); } elsif ($arch =~ /ppc/) { + if ($profile) { + $kernelpath = "xcat/$os/$arch/profile/inst64"; + } else { + $kernelpath = "xcat/$os/$arch/inst64"; + } $bptab->setNodeAttribs( $node, { - kernel => "xcat/$os/$arch/inst64", + kernel => $kernelpath, initrd => "", kcmdline => $kcmdline } @@ -1324,26 +1353,78 @@ sub copycd } } -# Get the driver update disk from /install/driverdisk// -# Take out the drivers from driver update disk and insert them -# into the initrd +# callback subroutine for 'find' command to return the path +my $driver_name; +my $real_path; +sub get_path () +{ + if ($File::Find::name =~ /\/$driver_name/) { + $real_path = $File::Find::name; + } +} -sub insert_dd { +# Get the driver disk or driver rpm from the osimage.driverupdatesrc +# The valid value: dud:/install/dud/dd.img,rpm:/install/rpm/d.rpm, if missing the tag: 'dud'/'rpm' +# the 'rpm' is default. +# +# If cannot find the driver disk from osimage.driverupdatesrc, will try to search driver disk +# from /install/driverdisk// +# +# For driver rpm, the driver list will be gotten from osimage.netdrivers. If not set, copy all the drivers from driver +# rpm to the initrd. +# + +sub insert_dd () { my $callback = shift; my $os = shift; my $arch = shift; my $img = shift; + my $driverupdatesrc = shift; + my $drivers = shift; my $install_dir = xCAT::Utils->getInstallDir(); - # Find out the dirver disk which need to be insert into initrd - if (! -d "$install_dir/driverdisk/$os/$arch") { - return (); + my $cmd; + + my @dd_list; + my @rpm_list; + my @driver_list; + + my @rpm_drivers; + + # Parse the parameters to the the source of Driver update disk and Driver rpm, and driver list as well + if ($driverupdatesrc) { + my @srcs = split(',', $driverupdatesrc); + foreach my $src (@srcs) { + if ($src =~ /dud:(.*)/i) { + push @dd_list, $1; + } elsif ($src =~ /rpm:(.*)/i) { + push @rpm_list, $1; + } else { + push @rpm_list, $src; + } + } } - my $cmd = "find $install_dir/driverdisk/$os/$arch -type f"; - my @dd_list = xCAT::Utils->runcmd($cmd, -1); + if (! @dd_list) { + # get Driver update disk from the default path if not specified in osimage + # check the Driver Update Disk images, it can be .img or .iso + if (-d "$install_dir/driverdisk/$os/$arch") { + $cmd = "find $install_dir/driverdisk/$os/$arch -type f"; + @dd_list = xCAT::Utils->runcmd($cmd, -1); + } + } + + foreach (split /,/,$drivers) { + unless (/\.ko$/) { + s/$/.ko/; + } + push @driver_list, $_; + } + chomp(@dd_list); - if (!@dd_list) { + chomp(@rpm_list); + + unless (@dd_list || @rpm_list ) { return undef; } @@ -1354,25 +1435,125 @@ sub insert_dd { my $pkgdir="$install_dir/$os/$arch"; # Unzip the original initrd - if ($arch =~/ppc/) { - $cmd = "gunzip --quiet -c $pkgdir/1/suseboot/initrd64 > $dd_dir/initrd"; - xCAT::Utils->runcmd($cmd, -1); - if ($::RUNCMD_RC != 0) { - my $rsp; - push @{$rsp->{data}}, "Handle the driver update disk failed. Could not gunzip the initial initrd."; - xCAT::MsgUtils->message("E", $rsp, $callback); - return (); - } + # This only needs to be done for ppc or handling the driver rpm + # For the driver disk against x86, append the driver disk to initrd directly + if ($arch =~/ppc/ || @rpm_list) { + if ($arch =~ /ppc/) { + $cmd = "gunzip --quiet -c $pkgdir/1/suseboot/initrd64 > $dd_dir/initrd"; + } elsif ($arch =~ /x86/) { + $cmd = "gunzip --quiet -c $img > $dd_dir/initrd"; + } + xCAT::Utils->runcmd($cmd, -1); + if ($::RUNCMD_RC != 0) { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update failed. Could not gunzip the initial initrd."; + xCAT::MsgUtils->message("E", $rsp, $callback); + return (); + } + + # Unpack the initrd + $cmd = "cd $dd_dir/initrd_img; cpio -id --quiet < $dd_dir/initrd"; + xCAT::Utils->runcmd($cmd, -1); + if ($::RUNCMD_RC != 0) { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update disk failed. Could not extract files from the initial initrd."; + xCAT::MsgUtils->message("E", $rsp, $callback); + return (); + } + + # Start to load the drivers from rpm packages + if (@rpm_list) { + # Extract the files from rpm to the tmp dir + mkpath "$dd_dir/rpm"; + foreach my $rpm (@rpm_list) { + if (-r $rpm) { + $cmd = "cd $dd_dir/rpm; rpm2cpio $rpm | cpio -idum"; + xCAT::Utils->runcmd($cmd, -1); + if ($::RUNCMD_RC != 0) { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update failed. Could not extract files from the rpm $rpm."; + xCAT::MsgUtils->message("I", $rsp, $callback); + } + } else { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update failed. Could not read the rpm $rpm."; + xCAT::MsgUtils->message("I", $rsp, $callback); + } + } + + # Copy the firmware to the rootimage + if (-d "$dd_dir/rpm/lib/firmware") { + if (! -d "$dd_dir/initrd_img/lib") { + mkpath "$dd_dir/initrd_img/lib"; + } + $cmd = "cp -rf $dd_dir/rpm/lib/firmware $dd_dir/initrd_img/lib"; + xCAT::Utils->runcmd($cmd, -1); + if ($::RUNCMD_RC != 0) { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update failed. Could not copy firmware to the initrd."; + xCAT::MsgUtils->message("I", $rsp, $callback); + } + } + + # Copy the drivers to the rootimage + # Figure out the kernel version + my @kernelpaths = <$dd_dir/initrd_img/lib/modules/*>; + my @kernelvers; + foreach (@kernelpaths) { + push @kernelvers, basename($_); + } + + foreach my $kernelver (@kernelvers) { + if (@driver_list) { + # copy the specific drivers to initrd + foreach my $driver (@driver_list) { + $driver_name = $driver; + $real_path = ""; + find(\&get_path, <$dd_dir/rpm/lib/modules/$kernelver/*>); + if ($real_path && $real_path =~ m!$dd_dir/rpm(/lib/modules/$kernelver/.*?)[^\/]*$!) { + if (! -d "$dd_dir/initrd_img$1") { + mkpath "$dd_dir/initrd_img$1"; + } + $cmd = "cp -rf $real_path $dd_dir/initrd_img$1"; + xCAT::Utils->runcmd($cmd, -1); + if ($::RUNCMD_RC != 0) { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update failed. Could not copy driver $driver to the initrd."; + xCAT::MsgUtils->message("I", $rsp, $callback); + } else { + push @rpm_drivers, $driver; + } + } + } + } else { + # copy all the drviers to the initrd + if (-d "$dd_dir/rpm/lib/modules/$kernelver") { + $cmd = "cp -rf $dd_dir/rpm/lib/modules/$kernelver $dd_dir/initrd_img/lib/modules/"; + xCAT::Utils->runcmd($cmd, -1); + if ($::RUNCMD_RC != 0) { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update failed. Could not copy /lib/modules/$kernelver to the initrd."; + xCAT::MsgUtils->message("I", $rsp, $callback); + } + } else { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update failed. Could not find /lib/modules/$kernelver from the driver rpms."; + xCAT::MsgUtils->message("I", $rsp, $callback); + } + } - # Unpack the initrd - $cmd = "cd $dd_dir/initrd_img; cpio -id --quiet < $dd_dir/initrd"; - xCAT::Utils->runcmd($cmd, -1); - if ($::RUNCMD_RC != 0) { - my $rsp; - push @{$rsp->{data}}, "Handle the driver update disk failed. Could not extract files from the initial initrd."; - xCAT::MsgUtils->message("E", $rsp, $callback); - return (); - } + # regenerate the modules dependency + foreach my $kernelver (@kernelvers) { + $cmd = "cd $dd_dir/initrd_img; depmod -b . $kernelver"; + xCAT::Utils->runcmd($cmd, -1); + if ($::RUNCMD_RC != 0) { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update failed. Could not generate the depdency for the drivers in the initrd."; + xCAT::MsgUtils->message("I", $rsp, $callback); + } + } + } + } # end of loading drivers from rpm packages } # Create the dir for driver update disk @@ -1394,41 +1575,54 @@ sub insert_dd { xCAT::MsgUtils->message("E", $rsp, $callback); return (); } - + # zip the initrd #move ("$dd_dir/initrd.new", "$dd_dir/initrd"); $cmd = "gzip -f $dd_dir/initrd"; xCAT::Utils->runcmd($cmd, -1); - if ($arch =~ /x86/) { - my $rdhandle; - my $ddhandle; - open($rdhandle,">>",$img); - open ($ddhandle,"<","$dd_dir/initrd.gz"); - binmode($rdhandle); - binmode($ddhandle); - { local $/ = 32768; my $block; while ($block = <$ddhandle>) { print $rdhandle $block; } } - close($rdhandle); - close($ddhandle); - } elsif ($arch =~/ppc/) { - # make sure the src kernel existed - $cmd = "gunzip -c $pkgdir/1/suseboot/linux64.gz > $dd_dir/kernel"; - xCAT::Utils->runcmd($cmd, -1); - - # create the zimage - $cmd = "env -u POSIXLY_CORRECT /lib/lilo/scripts/make_zimage_chrp.sh --vmlinux $dd_dir/kernel --initrd $dd_dir/initrd.gz --output $img"; - xCAT::Utils->runcmd($cmd, -1); - if ($::RUNCMD_RC != 0) { - my $rsp; - push @{$rsp->{data}}, "Handle the driver update disk failed. Could not pack the hacked initrd."; - xCAT::MsgUtils->message("E", $rsp, $callback); - return (); + if ($arch =~/ppc/ || @rpm_list) { + if ($arch =~/ppc/) { + # make sure the src kernel existed + $cmd = "gunzip -c $pkgdir/1/suseboot/linux64.gz > $dd_dir/kernel"; + xCAT::Utils->runcmd($cmd, -1); + + # create the zimage + $cmd = "env -u POSIXLY_CORRECT /lib/lilo/scripts/make_zimage_chrp.sh --vmlinux $dd_dir/kernel --initrd $dd_dir/initrd.gz --output $img"; + xCAT::Utils->runcmd($cmd, -1); + if ($::RUNCMD_RC != 0) { + my $rsp; + push @{$rsp->{data}}, "Handle the driver update disk failed. Could not pack the hacked initrd."; + xCAT::MsgUtils->message("E", $rsp, $callback); + return (); + } + } elsif ($arch =~/x86/) { + copy ("$dd_dir/initrd.gz", "$img"); } + } elsif ($arch =~ /x86/) { + my $rdhandle; + my $ddhandle; + open($rdhandle,">>",$img); + open ($ddhandle,"<","$dd_dir/initrd.gz"); + binmode($rdhandle); + binmode($ddhandle); + { local $/ = 32768; my $block; while ($block = <$ddhandle>) { print $rdhandle $block; } } + close($rdhandle); + close($ddhandle); } + + # clean the env system("rm -rf $dd_dir"); my $rsp; - push @{$rsp->{data}}, "Inserted the driver update disk:".join(',', sort(@dd_list))."."; + if (@dd_list) { + push @{$rsp->{data}}, "Inserted the driver update disk:".join(',', sort(@dd_list))."."; + } + if (@driver_list) { + push @{$rsp->{data}}, "Inserted the drivers:".join(',', sort(@rpm_drivers))." from driver packages."; + } elsif (@rpm_list) { + push @{$rsp->{data}}, "Inserted the drivers from driver packages:".join(',', sort(@rpm_list))."."; + } xCAT::MsgUtils->message("I", $rsp, $callback); my @dd_files = (); diff --git a/xCAT-server/share/xcat/netboot/rh/genimage b/xCAT-server/share/xcat/netboot/rh/genimage index fad6a227b..cb5fcbc79 100755 --- a/xCAT-server/share/xcat/netboot/rh/genimage +++ b/xCAT-server/share/xcat/netboot/rh/genimage @@ -85,6 +85,7 @@ GetOptions( 'otherpkglist=s' => \$otherpkglist, #internal flag 'postinstall=s' => \$postinstall_filename, #internal flag 'rootimgdir=s' => \$destdir, #internal flag + 'driverupdatesrc=s' => \$driverupdatesrc, #internal flag 'interactive' =>\$prompt, ); @@ -435,7 +436,7 @@ foreach my $dd (@dd_drivers) { unless (grep { $_ eq $dd} @ndrivers) { push @new_order, $dd; } - print "Added driver $dd from driver update disk.\n"; + print "Added driver $dd from driver update disk or driver rpm.\n"; } @ndrivers = (@new_order, @ndrivers); @@ -1495,18 +1496,68 @@ sub get_path () } } -#load the driver update disk, and return the driver names by loading order +my @all_real_path; +sub get_all_path () +{ + if ($File::Find::name =~ /\/$driver_name/) { + push @all_real_path, $File::Find::name; + } +} + +# Load driver disk and driver rpm to the initrd +# Get the driver disk or driver rpm from the osimage.driverupdatesrc +# The valid value: dud:/install/dud/dd.img,rpm:/install/rpm/d.rpm, if missing the tag: 'dud'/'rpm' +# the 'rpm' is default. +# +# If cannot find the driver disk from osimage.driverupdatesrc, will try to search driver disk +# from /install/driverdisk// +# +# For driver rpm, the driver list will be gotten from osimage.netdrivers. If not set, copy all the drivers from driver +# rpm to the initrd. +# +# Return the driver names by loading order + sub load_dd () { - # Get the Driver Update Disk images, it can be .img or .iso - if (! -d "$installroot/driverdisk/$osver/$arch") { - return (); + my @dd_list; + my @rpm_list; + my @driver_list; + + my @rpm_drivers; + + # Parse the parameters to the the source of Driver update disk and Driver rpm, and driver list as well + if ($driverupdatesrc) { + my @srcs = split(',', $driverupdatesrc); + foreach my $src (@srcs) { + if ($src =~ /dud:(.*)/i) { + push @dd_list, $1; + } elsif ($src =~ /rpm:(.*)/i) { + push @rpm_list, $1; + } else { + push @rpm_list, $src; + } + } + } + if (! @dd_list) { + # get Driver update disk from the default path if not specified in osimage + # check the Driver Update Disk images, it can be .img or .iso + if (-d "$installroot/driverdisk/$osver/$arch") { + @dd_list = `find $installroot/driverdisk/$osver/$arch -type f`; + } } - my @dd_list = `find $installroot/driverdisk/$osver/$arch -type f`; - chomp(@dd_list); + foreach (split /,/,$netdriver) { + unless (/\.ko$/) { + s/$/.ko/; + } + push @driver_list, $_; + } - if (! @dd_list) { + + chomp(@dd_list); + chomp(@rpm_list); + + unless (@dd_list || @rpm_list ) { return (); } @@ -1515,7 +1566,7 @@ sub load_dd () mkpath "$dd_dir/mnt"; mkpath "$dd_dir/mods"; - my @dd_drivers = (); #dirver name + my @dd_drivers = (); #driver name # Loading drivers from each Driver Disk foreach my $dd (@dd_list) { @@ -1589,6 +1640,59 @@ sub load_dd () } } + # Loading the drivers from rpm packages + if (@rpm_list) { + if (@rpm_list) { + # Extract the files from rpm to the tmp dir + mkpath "$dd_dir/rpm"; + foreach my $rpm (@rpm_list) { + if (-r $rpm) { + if (system ("cd $dd_dir/rpm; rpm2cpio $rpm | cpio -idum")) { + print "Error: Cannot extract the files from the rpm $rpm.\n"; + } + } else { + print "Error: Cannot read the rpm $rpm.\n"; + } + } + # Copy the firmware to the rootimage + if (-d "$dd_dir/rpm/lib/firmware") { + system ("cp -rf $dd_dir/rpm/lib/firmware $rootimg_dir/lib"); + } + # Copy the drivers to the rootimage + if (-d "$dd_dir/rpm/lib/modules/$kernelver") { + if (@driver_list) { + foreach my $driver (@driver_list) { + $driver_name = $driver; + $real_path = ""; + find(\&get_path, <$dd_dir/rpm/lib/modules/$kernelver/*>); + if ($real_path && $real_path =~ m!$dd_dir/rpm(/lib/modules/$kernelver/.*?)[^\/]*$!) { + if (! -d "$rootimg_dir$1") { + mkpath "$rootimg_dir$1"; + } + system ("cp -rf $real_path $rootimg_dir$1"); + push @rpm_drivers, $driver; + } else { + print "Error: cannot find the driver $driver from the driver rpms\n"; + } + } + } else { + # copy all the drviers to the rootimage + system ("cp -rf $dd_dir/rpm/lib/modules/$kernelver $rootimg_dir/lib/modules/"); + find(\&get_all_path, <$dd_dir/rpm/lib/modules/$kernelver/*>); + foreach (@all_real_path) { + if (basename($_) =~ /\.ko$/) { + push @rpm_drivers, basename($_); + } + } + } + } else { + print "Warning: cannot find the kernel $kernelver from drvier rpms\n"; + } + } + + push @dd_drivers, @rpm_drivers; + } + # Generate the dependency relationship system ("chroot '$rootimg_dir' depmod $kernelver"); diff --git a/xCAT-server/share/xcat/netboot/sles/genimage b/xCAT-server/share/xcat/netboot/sles/genimage index ad6462a35..f37a9d632 100755 --- a/xCAT-server/share/xcat/netboot/sles/genimage +++ b/xCAT-server/share/xcat/netboot/sles/genimage @@ -101,6 +101,7 @@ GetOptions( 'otherpkglist=s' => \$otherpkglist, #internal flag 'postinstall=s' => \$postinstall_filename, #internal flag 'rootimgdir=s' => \$destdir, #internal flag + 'driverupdatesrc=s' => \$driverupdatesrc, #internal flag 'interactive' =>\$prompt, ); @@ -711,7 +712,7 @@ foreach my $dd (@dd_drivers) { unless (grep { $_ eq $dd} @ndrivers) { push @new_order, $dd; } - print "Added driver $dd from driver update disk.\n"; + print "Added driver $dd from driver update disk or driver rpm.\n"; } @ndrivers = (@new_order, @ndrivers); @@ -1549,19 +1550,68 @@ sub get_path () } } -#load the driver update disk, and return the driver names by loading order +my @all_real_path; +sub get_all_path () +{ + if ($File::Find::name =~ /\/$driver_name/) { + push @all_real_path, $File::Find::name; + } +} + +# Load driver disk and driver rpm to the initrd +# Get the driver disk or driver rpm from the osimage.driverupdatesrc +# The valid value: dud:/install/dud/dd.img,rpm:/install/rpm/d.rpm, if missing the tag: 'dud'/'rpm' +# the 'rpm' is default. +# +# If cannot find the driver disk from osimage.driverupdatesrc, will try to search driver disk +# from /install/driverdisk// +# +# For driver rpm, the driver list will be gotten from osimage.netdrivers. If not set, copy all the drivers from driver +# rpm to the initrd. +# +# Return the driver names by loading order + sub load_dd() { - # check the Driver Update Disk images, it can be .img or .iso - if (! -d "$installroot/driverdisk/$osver/$arch") { - return (); + my @dd_list; + my @rpm_list; + my @driver_list; + + my @rpm_drivers; + + # Parse the parameters to the the source of Driver update disk and Driver rpm, and driver list as well + if ($driverupdatesrc) { + my @srcs = split(',', $driverupdatesrc); + foreach my $src (@srcs) { + if ($src =~ /dud:(.*)/i) { + push @dd_list, $1; + } elsif ($src =~ /rpm:(.*)/i) { + push @rpm_list, $1; + } else { + push @rpm_list, $src; + } + } + } + if (! @dd_list) { + # get Driver update disk from the default path if not specified in osimage + # check the Driver Update Disk images, it can be .img or .iso + if (-d "$installroot/driverdisk/$osver/$arch") { + @dd_list = `find $installroot/driverdisk/$osver/$arch -type f`; + } } - my @dd_list = `find $installroot/driverdisk/$osver/$arch -type f`; - chomp(@dd_list); + foreach (split /,/,$netdriver) { + unless (/\.ko$/) { + s/$/.ko/; + } + push @driver_list, $_; + } - if (! @dd_list) { - return (); + chomp(@dd_list); + chomp(@rpm_list); + + unless (@dd_list || @rpm_list ) { + return undef; } # Create the work space, it should be cleaned at end of genimage @@ -1569,7 +1619,7 @@ sub load_dd() mkpath "$dd_dir/mnt"; mkpath "$dd_dir/mods"; - my @dd_drivers = (); #dirver names + my @dd_drivers = (); #driver names # Load drivers from each Driver Disk # For multiple dd, if want to make it has order, rename the dd with a number @@ -1692,6 +1742,58 @@ sub load_dd() } } + # Loading the drivers from rpm packages + if (@rpm_list) { + # Extract the files from rpm to the tmp dir + mkpath "$dd_dir/rpm"; + foreach my $rpm (@rpm_list) { + if (-r $rpm) { + if (system ("cd $dd_dir/rpm; rpm2cpio $rpm | cpio -idum")) { + print "Error: Cannot extract the files from the rpm $rpm.\n"; + } + } else { + print "Error: Cannot read the rpm $rpm.\n"; + } + } + # Copy the firmware to the rootimage + if (-d "$dd_dir/rpm/lib/firmware") { + system ("cp -rf $dd_dir/rpm/lib/firmware $rootimg_dir/lib"); + } + # Copy the drivers to the rootimage + if (-d "$dd_dir/rpm/lib/modules/$kernelver") { + #mkpath "$rootimg_dir/lib/modules/$kernelver/updates/"; + if (@driver_list) { + foreach my $driver (@driver_list) { + $driver_name = $driver; + $real_path = ""; + find(\&get_path, <$dd_dir/rpm/lib/modules/$kernelver/*>); + if ($real_path && $real_path =~ m!$dd_dir/rpm(/lib/modules/$kernelver/.*?)[^\/]*$!) { + if (! -d "$rootimg_dir$1") { + mkpath "$rootimg_dir$1"; + } + system ("cp -rf $real_path $rootimg_dir$1"); + push @rpm_drivers, $driver; + } else { + print "Error: cannot find the driver $driver from the driver rpms\n"; + } + } + } else { + # copy all the drviers to the rootimage + system ("cp -rf $dd_dir/rpm/lib/modules/$kernelver $rootimg_dir/lib/modules/"); + find(\&get_all_path, <$dd_dir/rpm/lib/modules/$kernelver/*>); + foreach (@all_real_path) { + if (basename($_) =~ /\.ko$/) { + push @rpm_drivers, basename($_); + } + } + } + } else { + print "Warning: cannot find the kernel $kernelver from drvier rpms\n"; + } + + push @dd_drivers, @rpm_drivers; + } + # Generate the dependency relationship system ("chroot '$rootimg_dir' depmod $kernelver");