diff --git a/perl-xCAT/xCAT/DSHCLI.pm b/perl-xCAT/xCAT/DSHCLI.pm index 85693ec22..631b412c2 100644 --- a/perl-xCAT/xCAT/DSHCLI.pm +++ b/perl-xCAT/xCAT/DSHCLI.pm @@ -804,6 +804,46 @@ sub fork_fanout_dcp my @dcp_command; my $rsyncfile; + + my %envardict; + foreach my $varstr (split(',',$$target_properties{'envar'})){ + if($varstr =~ m/(.*)=(.*)/){ + my ($myvar,$myvalue)=($1,$2); + $envardict{$myvar}=$myvalue; + } + } + + if(%envardict){ + my $dest_srcdict=$$options{'destDir_srcFile'}{$user_target}; + for my $dest (keys %{$dest_srcdict}){ + my $newdest=$dest; + $newdest=xCAT::Utils->varsubinline($newdest,\%envardict); + for my $label(keys %{$$dest_srcdict{$dest}}){ + my $myref; + if('ARRAY' eq ref($$dest_srcdict{$dest}{$label})){ + for my $path(@{$$dest_srcdict{$dest}{$label}}){ + $path=xCAT::Utils->varsubinline($path,\%envardict); + } + }elsif('HASH' eq ref($$dest_srcdict{$dest}{$label})){ + for my $path(keys(%{$$dest_srcdict{$dest}{$label}})){ + my $newpath=$path; + $newpath=xCAT::Utils->varsubinline($newpath,\%envardict); + if($newpath ne $path){ + $$dest_srcdict{$dest}{$label}{$newpath}=$$dest_srcdict{$dest}{$label}{$path}; + delete $$dest_srcdict{$dest}{$label}{$path}; + } + } + } + } + if($newdest ne $dest){ + $$dest_srcdict{$newdest}=$$dest_srcdict{$dest}; + delete $$dest_srcdict{$dest}; + } + + } + } + + if (!$$target_properties{'localhost'}) # this is to a remote host { my $target_type = $$target_properties{'type'}; @@ -3293,6 +3333,13 @@ sub bld_resolve_nodes_hash $rsp->{info}->[0] = "Command: $cmd failed. Continuing..."; xCAT::MsgUtils->message("I", $rsp, $::CALLBACK); } + + + my $ostab = xCAT::Table->new('nodetype'); + my %oents = %{ $ostab->getNodesAttribs(\@target_list, [qw(provmethod)]) }; + + + foreach my $target (@target_list) { @@ -3306,12 +3353,27 @@ sub bld_resolve_nodes_hash if (($mname eq $target) || ($localhostname eq $target)) { $localhost = $target; } + + my $envar=undef; + my $ent = $oents{$target}->[0]; + if ($ent and $ent->{provmethod} and \ + ($ent->{provmethod} ne 'install') and ($ent->{provmethod} ne 'netboot') and ($ent->{provmethod} ne 'statelite')) { + + my $imagename = $ent->{provmethod}; + my $osimagetab = xCAT::Table->new('osimage', -create => 1); + (my $ref) = $osimagetab->getAttribs({ imagename => $imagename }, 'environvar'); + if($ref){ + $envar=$ref->{'environvar'}; + } + } + my %properties = ( 'hostname' => $hostname, 'ip-address' => $ip_address, 'localhost' => $localhost, 'user' => $user, 'context' => $context, + 'envar' => $envar, 'unresolved' => $target ); @@ -4405,6 +4467,7 @@ sub parse_and_run_dcp $::XCATROOT = "/opt/xcat"; } + # parse the arguments Getopt::Long::Configure("posix_default"); Getopt::Long::Configure("no_gnu_compat"); @@ -4914,6 +4977,15 @@ sub rsync_to_image my ($input_file, $image) = @_; my $rc = 0; + + my %osimgenv; + if($ENV{'XCAT_OSIMAGE_ENV'}){ + foreach my $myenv(split(',',$ENV{'XCAT_OSIMAGE_ENV'})){ + if($myenv =~ /\s*(\S+)\s*=\s*(\S+)\s*/) { + $osimgenv{$1}=$2; + } + } + } open(INPUTFILE, "< $input_file") || die "File $input_file does not exist\n"; while (my $line = ) { @@ -4923,6 +4995,8 @@ sub rsync_to_image next; } + $line=xCAT::Utils->varsubinline($line,\%osimgenv); + # process no more lines, do not exec # do not execute postscripts when syncing images if (($line =~ /EXECUTE:/) || ($line =~ /EXECUTEALWAYS:/) diff --git a/perl-xCAT/xCAT/Schema.pm b/perl-xCAT/xCAT/Schema.pm index a77358ce0..3a78f33a8 100755 --- a/perl-xCAT/xCAT/Schema.pm +++ b/perl-xCAT/xCAT/Schema.pm @@ -768,7 +768,7 @@ passed as argument rather than by table value', }, }, osimage => { - cols => [qw(imagename groups profile imagetype description provmethod rootfstype osdistroname osupdatename cfmdir osname osvers osarch synclists postscripts postbootscripts serverrole isdeletable kitcomponents comments disable)], + cols => [qw(imagename groups profile imagetype description provmethod rootfstype osdistroname osupdatename cfmdir osname osvers osarch synclists postscripts postbootscripts serverrole isdeletable kitcomponents environvar comments disable)], keys => [qw(imagename)], tablespace => 'XCATTBS32K', table_desc => 'Basic information about an operating system image that can be used to deploy cluster nodes.', @@ -795,6 +795,7 @@ passed as argument rather than by table value', serverrole => 'The role of the server created by this osimage. Default roles: mgtnode, servicenode, compute, login, storage, utility.', isdeletable => 'A flag to indicate whether this image profile can be deleted. This attribute is only used by PCM.', kitcomponents => 'List of Kit Component IDs assigned to this OS Image definition.', + environvar => 'Comma delimited environment variables for the osimage', comments => 'Any user-written notes.', disable => "Set to 'yes' or '1' to comment out this row.", }, @@ -3478,6 +3479,10 @@ push(@{ $defspec{node}->{'attrs'} }, @nodeattrs); tabentry => 'nimimage.comments', access_tabentry => 'nimimage.imagename=attr:imagename', }, + { attr_name => 'environvar', + tabentry => 'osimage.environvar', + access_tabentry => 'osimage.imagename=attr:imagename', + }, ); ######################### diff --git a/perl-xCAT/xCAT/Utils.pm b/perl-xCAT/xCAT/Utils.pm index 4130b3397..7b76bcb9c 100644 --- a/perl-xCAT/xCAT/Utils.pm +++ b/perl-xCAT/xCAT/Utils.pm @@ -5004,4 +5004,32 @@ sub console_sleep { sleep($time); } -1; + +# replace the variables in $line with the values in dict ref $refvardict +# return the substitued $line +sub varsubinline{ + my $class=shift; + my $line=shift; + my $refvardict=shift; + + my @varsinline= $line =~ /\$\{?(\w+)\}?/g; + my @unresolvedvars; + foreach my $var(@varsinline){ + if(exists $refvardict->{$var}){ + $line=~ s/\$\{$var\}/$refvardict->{$var}/g; + $line=~ s/\$$var/$refvardict->{$var}/g; + }else{ + push @unresolvedvars,$var; + } + } + + return $line; +} + +#remove the left and right white spaces from string +sub strim{ + my $class=shift; + my $str=shift; + $str =~ s/^\s+|\s+$//g; + return $str; +} diff --git a/xCAT-client/bin/xdsh b/xCAT-client/bin/xdsh index 89e4ff0a6..666f51d97 100644 --- a/xCAT-client/bin/xdsh +++ b/xCAT-client/bin/xdsh @@ -13,7 +13,7 @@ use File::Basename; use Cwd; use Socket; -#use Data::Dumper; +use Data::Dumper; use Getopt::Long; require xCAT::MsgUtils; require xCAT::DSHCLI; @@ -195,6 +195,11 @@ if ($ENV{'DSH_VERIFY'}) push(@{ $cmdref->{env} }, "DSH_VERIFY=$ENV{'DSH_VERIFY'}"); } +if ($ENV{'XCAT_OSIMAGE_ENV'}) +{ + push(@{ $cmdref->{env} }, "XCAT_OSIMAGE_ENV=$ENV{'XCAT_OSIMAGE_ENV'}"); +} + xCAT::Client::submit_request($cmdref, \&xCAT::Client::handle_response); exit $xCAT::Client::EXITCODE; diff --git a/xCAT-server/lib/perl/xCAT/Postage.pm b/xCAT-server/lib/perl/xCAT/Postage.pm index 7fe50d925..553892415 100644 --- a/xCAT-server/lib/perl/xCAT/Postage.pm +++ b/xCAT-server/lib/perl/xCAT/Postage.pm @@ -18,6 +18,7 @@ use xCAT::Template; use xCAT::SvrUtils; use xCAT::Zone; +use Data::Dumper; use File::Basename; use Socket; use strict; @@ -319,7 +320,7 @@ sub makescript { #%image_hash is used to store the attributes in linuximage and nimimage tabs my %image_hash; - getImage(\%image_hash); + getImage(\%image_hash); # get postscript and postscript from postscripts and osimage tabs my $script_hash = xCAT::Postage::getScripts($nodes, \%image_hash); @@ -512,6 +513,16 @@ sub makescript { $osimgname = $provmethod; } + + if($image_hash{$osimgname}{'environvar'}){ + my $myenvstr=$image_hash{$osimgname}{'environvar'}; + foreach my $myenv(split(',',$myenvstr)){ + if($myenv =~ /\s*(\S+)\s*=\s*(\S+)\s*/) { + $ENV{$1}=$2; + } + } + } + my $osimage_vars; $osimage_vars = getImageitems_for_node($node, \%image_hash, $nodesetstate); @@ -1114,7 +1125,7 @@ sub getImage if ($^O =~ /^linux/i) { my $linuximagetab = xCAT::Table->new('linuximage', -create => 1); - my @et2 = $linuximagetab->getAllAttribs('imagename', 'pkglist', 'pkgdir', 'otherpkglist', 'otherpkgdir'); + my @et2 = $linuximagetab->getAllAttribs('imagename', 'pkglist', 'pkgdir', 'otherpkglist', 'otherpkgdir','environvar'); if (@et2) { foreach my $tmp_et2 (@et2) { my $imagename = $tmp_et2->{imagename}; @@ -1122,6 +1133,7 @@ sub getImage $image_hash->{$imagename}->{pkgdir} = $tmp_et2->{pkgdir}; $image_hash->{$imagename}->{otherpkglist} = $tmp_et2->{otherpkglist}; $image_hash->{$imagename}->{otherpkgdir} = $tmp_et2->{otherpkgdir}; + $image_hash->{$imagename}->{environvar} = $tmp_et2->{environvar}; } } } @@ -1190,6 +1202,11 @@ sub getImageitems_for_node $result .= "export OTHERPKGDIR\n"; } } + if ($ref1->{'environvar'}){ + foreach my $myenvar(split(',',$ref1->{'environvar'})){ + $result .='export '.$myenvar."\n"; + } + } } } else @@ -1813,6 +1830,8 @@ sub includefile my $file = shift; my $idir = shift; my @text = (); + + $file=xCAT::Utils->varsubinline($file,\%ENV); unless ($file =~ /^\//) { $file = $idir . "/" . $file; @@ -1948,7 +1967,7 @@ sub getScripts $script_hash{default_postboot} = $et->{'postbootscripts'}; - my @et2 = $ostab->getAllAttribs('imagename', 'postscripts', 'postbootscripts', 'osvers', 'osarch', 'profile', 'provmethod', 'synclists', 'kitcomponents'); + my @et2 = $ostab->getAllAttribs('imagename', 'postscripts', 'postbootscripts', 'osvers', 'osarch', 'profile', 'provmethod', 'synclists', 'kitcomponents','environvar'); if (@et2) { foreach my $tmp_et2 (@et2) { my $imagename = $tmp_et2->{imagename}; @@ -1959,6 +1978,7 @@ sub getScripts $image_hash->{$imagename}->{profile} = $tmp_et2->{profile}; $image_hash->{$imagename}->{provmethod} = $tmp_et2->{provmethod}; $image_hash->{$imagename}->{synclists} = $tmp_et2->{synclists}; + $image_hash->{$imagename}->{environvar} = $tmp_et2->{environvar}; $image_hash->{$imagename}->{kitcomponents} = $tmp_et2->{kitcomponents} if ($tmp_et2->{kitcomponents}); } } diff --git a/xCAT-server/lib/perl/xCAT/Template.pm b/xCAT-server/lib/perl/xCAT/Template.pm index 1440272b3..64caa91ce 100644 --- a/xCAT-server/lib/perl/xCAT/Template.pm +++ b/xCAT-server/lib/perl/xCAT/Template.pm @@ -1489,6 +1489,7 @@ sub includefile #2 means pattern list, pattern list starts with @, #3 means remove package list, packages to be removed start with -. my $text = ""; + $file=xCAT::Utils->varsubinline($file,\%ENV); unless ($file =~ /^\//) { $file = $idir . "/" . $file; } diff --git a/xCAT-server/lib/xcat/plugins/anaconda.pm b/xCAT-server/lib/xcat/plugins/anaconda.pm index 1a1d4088c..5b780080e 100644 --- a/xCAT-server/lib/xcat/plugins/anaconda.pm +++ b/xCAT-server/lib/xcat/plugins/anaconda.pm @@ -18,7 +18,6 @@ use xCAT::MsgUtils; use xCAT::SvrUtils; use xCAT::Yum; -#use Data::Dumper; use Getopt::Long; Getopt::Long::Configure("bundling"); Getopt::Long::Configure("pass_through"); @@ -952,12 +951,13 @@ sub mkinstall if (!$osimagetab) { $osimagetab = xCAT::Table->new('osimage', -create => 1); } - (my $ref) = $osimagetab->getAttribs({ imagename => $imagename }, 'osvers', 'osarch', 'profile', 'provmethod', 'osupdatename'); + (my $ref) = $osimagetab->getAttribs({ imagename => $imagename }, 'osvers', 'osarch', 'profile', 'provmethod', 'osupdatename','environvar'); if ($ref) { $img_hash{$imagename}->{osver} = $ref->{'osvers'}; $img_hash{$imagename}->{osarch} = $ref->{'osarch'}; $img_hash{$imagename}->{profile} = $ref->{'profile'}; $img_hash{$imagename}->{provmethod} = $ref->{'provmethod'}; + $img_hash{$imagename}->{environvar} = $ref->{'environvar'}; if (!$linuximagetab) { $linuximagetab = xCAT::Table->new('linuximage', -create => 1); } @@ -1163,6 +1163,15 @@ sub mkinstall } else { $tmperr = "Unable to find template in /install/custom/install/$platform or $::XCATROOT/share/xcat/install/$platform (for $profile/$os/$arch combination)"; } + + if($img_hash{$imagename}->{environvar}){ + foreach my $myenv(split(',',$img_hash{$imagename}->{'environvar'})){ + if($myenv =~ /\s*(\S+)\s*=\s*(\S+)\s*/) { + $ENV{$1}=$2; + } + } + } + if (-r "$tmplfile") { $tmperr = diff --git a/xCAT-server/lib/xcat/plugins/genimage.pm b/xCAT-server/lib/xcat/plugins/genimage.pm index c98a05720..69d0c4c6d 100644 --- a/xCAT-server/lib/xcat/plugins/genimage.pm +++ b/xCAT-server/lib/xcat/plugins/genimage.pm @@ -73,6 +73,7 @@ sub process_request { my $dryrun; my $ignorekernelchk; my $noupdate; + my $envar; GetOptions( 'a=s' => \$arch, @@ -138,7 +139,7 @@ sub process_request { return 1; } - (my $ref_osimage_tab) = $osimagetab->getAttribs({ imagename => $imagename }, 'osvers', 'osarch', 'profile', 'provmethod'); + (my $ref_osimage_tab) = $osimagetab->getAttribs({ imagename => $imagename }, 'osvers', 'osarch', 'profile', 'provmethod','environvar'); unless ($ref_osimage_tab) { $callback->({ error => ["Cannot find image \'$imagename\' from the osimage table."], errorcode => [1] }); return 1; @@ -153,6 +154,7 @@ sub process_request { $osver = $ref_osimage_tab->{'osvers'}; $arch = $ref_osimage_tab->{'osarch'}; $profile = $ref_osimage_tab->{'profile'}; + $envar = $ref_osimage_tab->{'environvar'}; 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) { @@ -318,7 +320,7 @@ sub process_request { if ($kerneldir) { $cmd .= " --kerneldir $kerneldir"; } if ($interactive) { $cmd .= " --interactive" } if ($onlyinitrd) { $cmd .= " --onlyinitrd" } - + if ($envar) { $cmd .= " --env $envar"; } if ($srcdir) { $cmd .= " --srcdir \"$srcdir\""; } if ($pkglist) { $cmd .= " --pkglist $pkglist"; } if ($srcdir_otherpkgs) { $cmd .= " --otherpkgdir \"$srcdir_otherpkgs\""; } diff --git a/xCAT-server/lib/xcat/plugins/packimage.pm b/xCAT-server/lib/xcat/plugins/packimage.pm index 18a219b3d..fe08e6c2b 100755 --- a/xCAT-server/lib/xcat/plugins/packimage.pm +++ b/xCAT-server/lib/xcat/plugins/packimage.pm @@ -99,6 +99,7 @@ sub process_request { my $imagename; my $dotorrent; my $provmethod; + my $envars; my $help; my $version; my $lock; @@ -153,7 +154,7 @@ sub process_request { $callback->({ error => ["The linuximage table cannot be opened."], errorcode => [1] }); return 1; } - (my $ref) = $osimagetab->getAttribs({ imagename => $imagename }, 'osvers', 'osarch', 'profile', 'provmethod', 'synclists'); + (my $ref) = $osimagetab->getAttribs({ imagename => $imagename }, 'osvers', 'osarch', 'profile', 'provmethod', 'synclists','environvar'); unless ($ref) { $callback->({ error => ["Cannot find image \'$imagename\' from the osimage table."], errorcode => [1] }); return 1; @@ -169,6 +170,7 @@ sub process_request { $profile = $ref->{'profile'}; $syncfile = $ref->{'synclists'}; $provmethod = $ref->{'provmethod'}; + $envars = $ref->{'environvar'}; 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] }); @@ -422,8 +424,12 @@ sub process_request { # sync fils configured in the synclist to the rootimage $syncfile = xCAT::SvrUtils->getsynclistfile(undef, $osver, $arch, $profile, "netboot", $imagename); if ( defined($syncfile) && -f $syncfile && -d $rootimg_dir) { + my $myenv=''; + if($envars){ + $myenv.=" XCAT_OSIMAGE_ENV=$envars"; + } print "Syncing files from $syncfile to root image dir: $rootimg_dir\n"; - system("$::XCATROOT/bin/xdcp -i $rootimg_dir -F $syncfile"); + system("$myenv $::XCATROOT/bin/xdcp -i $rootimg_dir -F $syncfile"); } } else { print "Bypass of syncfiles requested, will not sync files to root image directory.\n"; diff --git a/xCAT-server/share/xcat/netboot/imgutils/imgutils.pm b/xCAT-server/share/xcat/netboot/imgutils/imgutils.pm index 71aae5185..e8cc25445 100644 --- a/xCAT-server/share/xcat/netboot/imgutils/imgutils.pm +++ b/xCAT-server/share/xcat/netboot/imgutils/imgutils.pm @@ -10,6 +10,24 @@ use File::Basename; use File::Path; use Cwd qw(realpath); +sub varsubinline{ + my $line=shift; + my $refvardict=shift; + + my @varsinline= $line =~ /\$\{?(\w+)\}?/g; + my @unresolvedvars; + foreach my $var(@varsinline){ + if(exists $refvardict->{$var}){ + $line=~ s/\$\{$var\}/$refvardict->{$var}/g; + $line=~ s/\$$var/$refvardict->{$var}/g; + }else{ + push @unresolvedvars,$var; + } + } + + return $line; +} + sub get_profile_def_filename { my $osver = shift; my $profile = shift; @@ -54,6 +72,8 @@ sub include_file my $file = shift; my $idir = shift; my @text = (); + + $file=varsubinline($file,\%ENV); unless ($file =~ /^\//) { $file = $idir . "/" . $file; } @@ -117,7 +137,6 @@ sub get_package_names { $pkgtext =~ s/#INCLUDE:([^#^\n]+)#/include_file($1,$idir)/eg; } } - #print "\n\npkgtext=$pkgtext\n\n"; my @tmp = split(',', $pkgtext); my $pass = 1; @@ -169,7 +188,6 @@ sub get_package_names { } } } - return %pkgnames; } diff --git a/xCAT-server/share/xcat/netboot/rh/genimage b/xCAT-server/share/xcat/netboot/rh/genimage index 2fd822aa0..b119c7ca8 100755 --- a/xCAT-server/share/xcat/netboot/rh/genimage +++ b/xCAT-server/share/xcat/netboot/rh/genimage @@ -69,7 +69,7 @@ my $prompt; my $ignorekernelchk; my $noupdate; my $lock; - +my $envar; sub xdie { @@ -186,6 +186,7 @@ GetOptions( 'onlyinitrd' => \$onlyinitrd, 'ignorekernelchk' => \$ignorekernelchk, 'noupdate' => \$noupdate, + 'env=s' => \$envar, ); if (@ARGV > 0) { @@ -376,6 +377,11 @@ unless ($onlyinitrd) { exit 1; } + my @envarlist=split(',',$envar); + foreach my $entry (@envarlist){ + my ($key,$value)=split('=',$entry); + $ENV{xCAT::Utils->strim($key)}=xCAT::Utils->strim($value); + } mount_chroot($rootimg_dir); my %pkg_hash = imgutils::get_package_names($pkglist); @@ -784,6 +790,7 @@ if ($postinstall_filename) { $ENV{IMG_OTHERPKGLIST}=$otherpkglist if("" ne $otherpkglist); $ENV{IMG_OTHERPKGDIR}=$srcdir_otherpkgs if("" ne $srcdir_otherpkgs); $ENV{IMG_ROOTIMGDIR}=$rootimg_dir if("" ne $rootimg_dir); + foreach my $postinstall (split /,/, $postinstall_filename) { if (!-x $postinstall) { @@ -1944,7 +1951,6 @@ sub generic_post { #This function is meant to leave the image in a state approxi print $cfgfile "tmpfs /dev/shm tmpfs defaults 0 0\n"; print $cfgfile "proc /proc proc defaults 0 0\n"; print $cfgfile "sysfs /sys sysfs defaults 0 0\n"; - if (!&using_systemd($osver)) { if ($tmplimit) { print $cfgfile "tmpfs /tmp tmpfs defaults,size=$tmplimit 0 2\n";