-
-
Save anonymous/82e81240a3ec2a996fb6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use strict; | |
use warnings; | |
use Cwd; | |
use Compress::Zlib; | |
use Digest::SHA; | |
use File::Basename; | |
use File::Path; | |
use Getopt::Long 2.36 qw(GetOptionsFromString); | |
use IO::Zlib; | |
use LWP::UserAgent; | |
my $whoami = basename $0; | |
my $dir = getcwd; | |
### | |
### COMMAND-LINE AND CONFIGURATION-FILE OPTION PARSING | |
### | |
my $usage = "Usage: $whoami [--help] [--dry-run] [--debug] [--verbose] [...options...] | |
Script options: | |
[--centos-iso=filename.iso] [--rpm-cache=directory-name] | |
[--appliance-manager=hostname] [--output-file=filename.iso] | |
[--template=template-name] [--config-file=file-name] | |
VM options: | |
--virtual|--physical [--dell] [--hyperv] [--scsi|--ide] [--[no]vmware-tools] | |
--isv-release=#.#.#.#.#.#.# --netproto=static|dhcp --hostname=host-name | |
[--address=ip-address] [--netmask=netmask] [--gateway=ip-address] | |
[--nameserver=ip-address[,ip-address[,...]]] [--root-password=pw] | |
[--grub-password=pw] [--[no]emacs] [--[no]64bit] [--[no]boston]\n"; | |
# Hidden options, primary for development and debugging: | |
# | |
# --nofetch - skip fetching RPMs, they're already fetched | |
# --preserve - Preserve temporary files | |
my %templates = ( | |
"vmimage" => { | |
"hostname" => "vmimage", | |
"netproto" => "static", | |
"address" => "10.22.60.74", | |
"netmask" => "255.255.255.0", | |
"gateway" => "10.22.60.254", | |
"nameserver" => "10.22.74.97,10.22.74.197", | |
"virtual" => 1, | |
}, | |
"stockimage" => { | |
"hostname" => "stockimage", | |
"netproto" => "static", | |
"address" => "10.22.60.76", | |
"netmask" => "255.255.255.0", | |
"gateway" => "10.22.60.254", | |
"nameserver" => "10.22.74.97,10.22.74.197", | |
"physical" => 1, | |
}, | |
"stockimage_dell" => { | |
"hostname" => "stockimage_dell", | |
"netproto" => "static", | |
"address" => "10.22.60.76", | |
"netmask" => "255.255.255.0", | |
"gateway" => "10.22.60.254", | |
"nameserver" => "10.22.74.97,10.22.74.197", | |
"physical" => 1, | |
"dell" => 1 | |
} | |
); | |
my $prod_app_manager = 'download01.tamalesoftware.com'; | |
my(%centos_iso_urls) = ( | |
"bit32" => "http://vault.centos.org/5.4/isos/i386/CentOS-5.4-i386-bin-1of6.iso", | |
"bit64" => "http://vault.centos.org/5.4/isos/x86_64/CentOS-5.4-x86_64-bin-1of7.iso", | |
); | |
my(@gpg_keys) = ('BEC-RPM-GPG-KEY', 'TS-RPM-GPG-KEY'); | |
my(@emacs_rpms) = qw(emacs emacs-common Xaw3d giflib | |
xorg-x11-fonts-ISO8859-1-75dpi); | |
my(@vmware_tools_rpms) = qw(binutils gcc glibc-devel glibc-headers | |
kernel-devel libgomp); | |
# Eventually we may need to support different versions of VMware-tools for | |
# different VM host platforms, but for the time being we're using just one. | |
my $vmware_tools_repo = "vmware-tools"; | |
my $vmware_tools_url_tail = "$vmware_tools_repo/VMwareTools-3.5.0-153875.i386.rpm"; | |
my(%c, %c2, %c3); | |
my $wd = "/tmp/$whoami.$$"; | |
my(@arg_specs) = qw(dryrun|dry-run debug verbose | |
virtual physical dell hyperv scsi ide vmwaretools|vmware-tools! | |
isvrelease|isv-release=s netproto=s hostname=s address=s netmask=s | |
gateway=s nameserver=s rootpassword|root-password=s | |
grubpassword|grub-password=s emacs! bit64|64bit! boston! | |
centosiso|centos-iso=s rpmcache|rpm-cache=s | |
appmanager|app-manager|appliance-manager=s | |
outputfile|output-file=s preserve | |
fetch!); | |
print "check 1 "; | |
$c{fetch} = 1; | |
GetOptions(\%c, "help", "configfile|config-file|configuration-file=s", "template=s", @arg_specs) | |
or die $usage; | |
if ($c{help}) { | |
print $usage; | |
exit; | |
} | |
print "check 2 "; | |
if ($^O eq "linux") { | |
print "check 3 "; | |
if ($>) { | |
print "check 4 "; | |
#die "$whoami: Must be run as root on Linux\n"; | |
} | |
} | |
print "check 5 @ARGV"; | |
if (@ARGV) { | |
die "$whoami: Extra arguments: @ARGV\n"; | |
} | |
if ($c{configfile}) { | |
my($data); | |
if (! -f $c{configfile}) { | |
die "$whoami: Config file $c{configfile} does not exist\n"; | |
} | |
open(CONFIGFILE, "<", $c{configfile}) or | |
die "$whoami: open($c{configfile}): $!\n"; | |
{ local($/) = undef; $data = <CONFIGFILE>; } | |
close(CONFIGFILE) or die "$whoami: close($c{configfile}): $!\n"; | |
my($ret, $args) = GetOptionsFromString($data, \%c2, "template=s", | |
@arg_specs); | |
if ($args && @{$args}) { | |
die "$whoami: Extra arguments in $c{configfile}: @{$args}\n"; | |
} | |
if (! $ret) { | |
die "$whoami: Invalid option(s) in $c{configfile}\n$usage"; | |
} | |
} | |
if ($c{template} || $c2{template}) { | |
my $template = $c{template} || $c2{template}; | |
if (! $templates{$template}) { | |
warn "$whoami: Invalid template: \"$template\"\n"; | |
die("$whoami: Valid templates are: ", join(", ", sort keys %templates), | |
"\n"); | |
} | |
%c3 = %{$templates{$template}}; | |
} | |
if ($c{physical} or $c{virtual}) { | |
if (delete $c2{physical} and $c{virtual}) { | |
warn "$whoami: Warning: Ignoring --physical in config file\n"; | |
} | |
if (delete $c2{virtual} and $c{physical}) { | |
warn "$whoami: Warning: Ignoring --virtual in config file\n"; | |
} | |
if (delete $c2{dell} and $c{virtual}) { | |
warn "$whoami: Warning: Ignoring --dell in config file\n"; | |
} | |
if (delete $c3{physical} and $c{virtual}) { | |
warn "$whoami: Warning: Ignoring --physical in template\n"; | |
} | |
if (delete $c3{virtual} and $c{physical}) { | |
warn "$whoami: Warning: Ignoring --virtual in template\n"; | |
} | |
if (delete $c3{dell} and $c{virtual}) { | |
warn "$whoami: Warning: Ignoring --dell in template\n"; | |
} | |
} | |
if ($c2{physical} or $c2{virtual}) { | |
if (delete $c3{physical} and $c{virtual}) { | |
warn "$whoami: Warning: Ignoring --physical in template\n"; | |
} | |
if (delete $c3{virtual} and $c{physical}) { | |
warn "$whoami: Warning: Ignoring --virtual in template\n"; | |
} | |
if (delete $c3{dell} and $c{virtual}) { | |
warn "$whoami: Warning: Ignoring --dell in template\n"; | |
} | |
} | |
if ($c{ide} and $c{scsi}) { | |
die "$whoami: Can't specify both --ide and --scsi on command line\n"; | |
} | |
if ($c2{ide} and $c2{scsi}) { | |
die "$whoami: Can't specify both --ide and --scsi in config file\n"; | |
} | |
if ($c3{ide} and $c3{scsi}) { | |
die "$whoami: Internal error: can't specify both --ide and --scsi in template\n"; | |
} | |
if ($c{dell} and $c{virtual}) { | |
die "$whoami: Can't specify both --dell and --virtual on command line\n"; | |
} | |
if ($c2{dell} and $c2{virtual}) { | |
die "$whoami: Can't specify both --dell and --virtual in config file\n"; | |
} | |
if ($c3{dell} and $c3{virtual}) { | |
die "$whoami: Internal error: can't specify both --dell and --virtual in template\n"; | |
} | |
if ($c{hyperv}) { | |
$c{ide} = 1 if (! $c{scsi}); | |
$c{virtual} = 1 if (! $c{physical}); | |
$c{vmwaretools} = 0 if (! defined($c{vmwaretools})); | |
} | |
if ($c2{hyperv}) { | |
$c2{ide} = 1 if (! ($c{scsi} or $c2{scsi})); | |
$c2{virtual} = 1 if (! $c2{physical}); | |
$c2{vmwaretools} = 0 if (! defined($c2{vmwaretools})); | |
} | |
if ($c3{hyperv}) { | |
$c3{ide} = 1 if (! ($c{scsi} or $c2{scsi} or $c3{scsi})); | |
$c3{virtual} = 1 if (! $c3{physical}); | |
$c3{vmwaretools} = 0 if (! defined($c3{vmwaretools})); | |
} | |
if ($c{dell}) { | |
$c{physical} = 1; | |
} | |
if ($c2{dell}) { | |
$c2{physical} = 1; | |
} | |
if ($c3{dell}) { | |
$c3{physical} = 1; | |
} | |
if ($c{ide}) { | |
if ($c2{scsi}) { | |
delete $c2{scsi}; | |
warn "$whoami: Ignoring --scsi in config file\n"; | |
} | |
if ($c3{scsi}) { | |
delete $c3{scsi}; | |
warn "$whoami: Ignoring --scsi in template\n"; | |
} | |
} | |
if ($c2{ide}) { | |
if ($c3{scsi}) { | |
delete $c3{scsi}; | |
warn "$whoami: Ignore --scsi in template\n"; | |
} | |
} | |
if ($c{scsi}) { | |
if ($c2{ide}) { | |
delete $c2{ide}; | |
warn "$whoami: Ignoring --ide in config file\n"; | |
} | |
if ($c3{ide}) { | |
delete $c3{ide}; | |
warn "$whoami: Ignoring --ide in template\n"; | |
} | |
} | |
if ($c2{scsi}) { | |
if ($c3{ide}) { | |
delete $c3{ide}; | |
warn "Ignoring --ide in template\n"; | |
} | |
} | |
if (defined($c{vmwaretools})) { | |
if (defined($c2{vmwaretools}) and $c{vmwaretools} != $c2{vmwaretools}) { | |
delete $c2{vmwaretools}; | |
warn "$whoami: Ignoring VMware tools setting in config file\n"; | |
} | |
if (defined($c3{vmwaretools}) and $c{vmwaretools} != $c3{vmwaretools}) { | |
delete $c3{vmwaretools}; | |
warn "$whoami: Ignoring VMware tools setting in template\n"; | |
} | |
} | |
if (defined($c2{vmwaretools})) { | |
if (defined($c3{vmwaretools}) and $c2{vmwaretools} != $c3{vmwaretools}) { | |
delete $c3{vmwaretools}; | |
warn "$whoami: Ignoring VMware tools setting in template\n"; | |
} | |
} | |
foreach my $setting (keys %c) { | |
if (defined($c2{$setting})) { | |
delete $c2{$setting}; | |
warn "$whoami: Warning: Overriding --$setting in config file from command line\n"; | |
} | |
if (defined($c3{$setting})) { | |
delete $c3{$setting}; | |
warn "$whoami: Warning: Overriding --$setting in template from command line\n"; | |
} | |
} | |
foreach my $setting (keys %c2) { | |
if (defined($c3{$setting})) { | |
delete $c3{$setting}; | |
warn "$whoami: Warning: Overriding --$setting in template from config file\n"; | |
} | |
} | |
%c = (%c3, %c2, %c); | |
if (! defined($c{rootpassword})) { | |
$c{rootpassword} = 'be1nformed'; | |
} | |
elsif (! $c{rootpassword}) { | |
die "$whoami: Can't set empty root password\n"; | |
} | |
if (! defined($c{grubpassword})) { | |
$c{grubpassword} = $c{rootpassword}; | |
} | |
if ($c{grubpassword} =~ /[\"\\]/) { | |
die "$whoami: Grub password can't contain \" or \\\n"; | |
} | |
if ($c{dell} and $c{virtual}) { | |
die "$whoami: Can't specify both --dell and --virtual\n"; | |
} | |
if ($c{physical} and $c{virtual}) { | |
die "$whoami: Can't specify both --physical and --virtual\n"; | |
} | |
elsif (! ($c{physical} or $c{virtual})) { | |
die "$whoami: Must specify --physical or --virtual\n"; | |
} | |
else { | |
$c{physical} = ! $c{virtual}; | |
} | |
if ($c{virtual}) { | |
if (! defined($c{vmwaretools})) { | |
$c{vmwaretools} = 1; | |
} | |
} | |
else { | |
$c{vmwaretools} = 0; | |
} | |
if (! $c{ide}) { | |
$c{scsi} = 1; | |
} | |
if (! $c{isvrelease}) { | |
die "$whoami: Must specify ISV release with --isv-release\n"; | |
} | |
elsif ($c{isvrelease} !~ /^(?:\d+.){6}\d+$/) { | |
die "$whoami: Invalid ISV release number: $c{isvrelease}\n"; | |
} | |
if (! $c{netproto}) { | |
die "$whoami: Must specify --netproto=static|dhcp\n"; | |
} | |
else { | |
$c{netproto} =~ tr/A-Z/a-z/; | |
if ($c{netproto} !~ /^(?:static|dhcp)$/) { | |
die "$whoami: invalid netproto \"$c{netproto}\"; should be \"static\" or \"dhcp\"\n"; | |
} | |
} | |
if ($c{netproto} eq "static") { | |
foreach my $setting ("address", "netmask", "gateway") { | |
die "$whoami: Must specify --$setting with --netproto=static\n" | |
if (! $c{$setting}); | |
} | |
if (! $c{nameserver}) { | |
warn "$whoami: Warning: No --nameserver specified; configuring without nameservers\n"; | |
} | |
} | |
else { | |
foreach my $setting ("address", "netmask", "gateway", "nameserver") { | |
if ($c{$setting}) { | |
warn "$whoami: Warning: Ignoring --$setting for DHCP\n"; | |
delete $c{$setting}; | |
} | |
} | |
} | |
if (! $c{hostname}) { | |
die "$whoami: Must specify --hostname\n"; | |
} | |
if (! &check_address($c{address})) { | |
die "$whoami: Invalid IP address $c{address}\n"; | |
} | |
if (! &check_netmask($c{netmask})) { | |
die "$whoami: Invalid netmask $c{netmask}\n"; | |
} | |
if (! &check_address($c{gateway})) { | |
die "$whoami: Invalid gateway IP address $c{gateway}\n"; | |
} | |
if ($c{nameserver}) { | |
$c{nameserver} =~ s/\s+//g; | |
foreach my $nameserver (split(/,/, $c{nameserver})) { | |
if (! &check_address($nameserver)) { | |
die "$whoami: Invalid nameserver $nameserver\n"; | |
} | |
} | |
} | |
sub check_address { | |
return 1 if (! $_[0]); | |
my(@nums) = split(/\./, $_[0]); | |
return 0 if (@nums != 4); | |
foreach my $num (@nums) { | |
return 0 if ($num !~ /^\d+$/); | |
return 0 if ($num > 255); | |
} | |
return 1; | |
} | |
sub check_netmask { | |
return 1 if (! $_[0]); | |
return 0 if (! &check_address($_[0])); | |
my(@nums) = split(/\./, $_[0]); | |
my $binary = sprintf("%b%b%b%b", @nums); | |
if ($binary =~ /0.*1/) { | |
warn "$whoami: Warning: Weird netmask $_[0]; please make sure it's correct\n"; | |
} | |
return 1; | |
} | |
if ($c{centosiso} and ! -f $c{centosiso}) { | |
die "$whoami: $c{centosiso} does not exist\n"; | |
} | |
if (! $c{rpmcache}) { | |
$c{rpmcache} = "/tmp/$whoami-cache"; | |
} | |
if (! -d $c{rpmcache}) { | |
eval { mkpath($c{rpmcache}); }; | |
if ($@) { | |
warn "$@"; | |
die "$whoami: Error creating $c{rpmcache}\n"; | |
} | |
} | |
if (! $c{appmanager}) { | |
my $ipconfig; | |
if ($^O eq "cygwin" or $^O eq "MSWin32") { | |
$ipconfig = `ipconfig`; | |
} | |
else { | |
$ipconfig = `ifconfig`; | |
} | |
if ($ipconfig =~ /\b(?:10\.2\.159|10\.5\.3[23])\./) { | |
$c{appmanager} = 'app-manager.bos.tamalesoftware.com'; | |
} | |
else { | |
$c{appmanager} = $prod_app_manager; | |
} | |
warn "$whoami: Using appliance manager $c{appmanager}\n"; | |
} | |
if (! $c{outputfile}) { | |
$c{outputfile} = "rms.iso"; | |
warn "$whoami: Saving ISO as $c{outputfile}\n"; | |
} | |
### | |
### END COMMAND-LINE AND CONFIGURATION-FILE OPTION PARSING | |
### | |
my $app_manager_url = &app_manager_url($c{appmanager}); | |
#my $cs_scripts_url = &app_manager_url($prod_app_manager); | |
my $cs_scripts_url = $app_manager_url; | |
my $ua = LWP::UserAgent->new; | |
&verbose("Verifying that ISV release $c{isvrelease} exists..."); | |
my $isv_response = &get_memory("$app_manager_url/isv/$c{isvrelease}/RPMs/"); | |
&verbose(" done\n"); | |
&verbose("Verifying that ISV release $c{isvrelease} is correct architecture..."); | |
my $platform_response = | |
&get_memory("$app_manager_url/isv/$c{isvrelease}/RPMs/platform/RPMs/"); | |
if ($platform_response->content =~ /\.x86_64\.rpm/) { | |
if (! $c{bit64}) { | |
die "$whoami: 64-bit ISV specified for 32-bit ISO\n"; | |
} | |
} | |
elsif ($c{bit64}) { | |
#die "$whoami: 32-bit ISV specified for 64-bit ISO\n"; | |
} | |
print "check 6 "; | |
&verbose(" done\n"); | |
&verbose("Fetching CS scripts repository listing..."); | |
my $cs_response = &get_memory("$cs_scripts_url/cs/mkrmsiso/"); | |
print "check 7 "; | |
&verbose(" done\n"); | |
# Fetch the CentOS ISO if necessary | |
if (! $c{centosiso}) { | |
print "check 8 "; | |
my $url = $centos_iso_urls{$c{bit64} ? "bit64" : "bit32"}; | |
$c{centosiso} = &maybe_fetch($url); | |
} | |
# Download and collect names of needed RPMs | |
&verbose("Building RPM lists..."); | |
print "check 9 "; | |
eval { rmtree($wd); }; | |
mkpath($wd); | |
mkpath("$wd/platform-manager"); | |
chdir("$wd/platform-manager") | |
or die "$whoami: chdir($wd/platform-manager: $!\n"; | |
print "check 10 "; | |
my $pmfile = &maybe_fetch(&find_rpm_urls("platform-manager", $platform_response), | |
{always => 1}); | |
system("rpm2cpio $pmfile | cpio --quiet --extract --make-directories &>/dev/null") and die; | |
my(@platform_rpms, @isv_rpms, @cs_scripts_rpms); | |
# Fetch the appropriate platform-manager-* RPM. Extract the file list | |
# from it and fetch all the matching RPMs. | |
sub get_rpms_from_manager_rpm { | |
local($_); | |
my($rpm, $rpm_file, $response) = @_; | |
my $url = &find_rpm_urls("$rpm", $response); | |
my $file = &maybe_fetch($url, {always => 1}); | |
&debug("Extracting RPM list from $rpm RPM..."); | |
system("rpm2cpio $file | cpio --extract --quiet --make-directories &>/dev/null") | |
and die; | |
open(LIST, "<", "./etc/rpmmgr/rpms.d/$rpm_file") | |
or die "$whoami: open($wd/platform-manager/etc/rpmmgr/rpms.d/$rpm_file): $!\n"; | |
my(@rpms) = <LIST>; | |
chomp(@rpms); | |
@rpms = grep($_ ne "gpg-pubkey", @rpms); | |
close(LIST) or | |
die "$whoami: close($wd/platform-manager/etc/rpmmgr/rpms.d/$rpm_file): $!\n"; | |
&debug(" done (@rpms)\n"); | |
return(@rpms); | |
} | |
push(@platform_rpms, &get_rpms_from_manager_rpm("platform-manager-linux", | |
"linux", $platform_response)); | |
push(@platform_rpms, &get_rpms_from_manager_rpm("platform-manager-tamaleserver", | |
"tamaleserver", | |
$platform_response)); | |
if ($c{physical}) { | |
push(@platform_rpms, &get_rpms_from_manager_rpm("platform-manager-hardware", | |
"hardware", | |
$platform_response)); | |
if($c{dell}){ | |
push(@platform_rpms, &get_rpms_from_manager_rpm("platform-manager-hardware_dell", | |
"hardware_dell", | |
$platform_response)); | |
} | |
} | |
else { | |
push(@platform_rpms, &get_rpms_from_manager_rpm("platform-manager-virtual", | |
"virtual", | |
$platform_response)); | |
} | |
push(@cs_scripts_rpms, &get_rpms_from_manager_rpm("cs-scripts", | |
"cs-scripts.rpms", | |
$cs_response)); | |
if ($c{emacs}) { | |
&debug("Adding emacs RPMs @emacs_rpms to platform RPM list\n"); | |
push(@platform_rpms, @emacs_rpms); | |
} | |
if ($c{vmwaretools}) { | |
&debug("Adding VMwareTools dependencies @vmware_tools_rpms to RPM list\n"); | |
push(@platform_rpms, @vmware_tools_rpms); | |
} | |
push(@isv_rpms, &get_rpms_from_manager_rpm("platform-manager-isv", "isv", | |
$isv_response)); | |
&verbose(" done\n"); | |
&verbose("Downloading RPMs..."); | |
my @rpm_files; | |
print "check 11 "; | |
foreach my $rpm (@platform_rpms) { | |
push(@rpm_files, &maybe_fetch(&find_rpm_urls($rpm, $platform_response))); | |
} | |
print "check 12 "; | |
foreach my $rpm (@isv_rpms) { | |
push(@rpm_files, &maybe_fetch(&find_rpm_urls($rpm, $isv_response))); | |
} | |
print "check 13 "; | |
foreach my $rpm (@cs_scripts_rpms) { | |
push(@rpm_files, &maybe_fetch(&find_rpm_urls($rpm, $cs_response))); | |
# There might be a newer version in the platform | |
if (my(@urls) = &find_rpm_urls($rpm, $platform_response, {optional=>1})) { | |
push(@rpm_files, &maybe_fetch(@urls)); | |
} | |
} | |
print "check 14 "; | |
if ($c{vmwaretools}) { | |
push(@rpm_files, &maybe_fetch("$app_manager_url/$vmware_tools_url_tail")); | |
} | |
print "check 15 "; | |
chdir("..") or die; | |
print "check 16 "; | |
if (! $c{preserve}) { | |
rmtree("$wd/platform-manager"); | |
} | |
&verbose(" done\n"); | |
# Build ISO tree | |
&verbose("Extracting needed files from CentOS ISO..."); | |
mkpath("$wd/iso-root"); | |
chdir("iso-root") or die; | |
print "check 17 "; | |
mkdir("CentOS") or die "$whoami: mkdir($wd/iso-root/CentOS): $!\n"; | |
mkdir("repodata") or die "$whoami: mkdir($wd/iso-root/repodata): $!\n"; | |
mkdir("gpg-keys") or die "$whoami: mkdir($wd/iso-root/gpg-keys): $!\n"; | |
my(@wanted) = qw(.discinfo .treeinfo images/stage2.img isolinux | |
repodata/comps.xml); | |
if (! $c{dryrun}) { | |
if ($^O eq "linux") { | |
my $mp = "/mnt/CentOS"; | |
system("mkdir -p $mp") and die; | |
print "check 18 "; | |
#print "<br>centosiso: " . $c{centosiso}; | |
my $cmd = "sudo mount -o loop $c{centosiso} $mp"; | |
print "<br>CMD: " . $cmd; # This line prints: sudo mount -o loop /tmp/test.pl-cache/CentOS-5.4-x86_64-bin-1of7.iso /mnt/CentOS | |
system("sudo mount -o loop $c{centosiso} $mp") and die; | |
print " check 18.1 "; | |
system("tar -C $mp -c @wanted | tar -x") and die; | |
print "check 19 "; | |
system("umount $mp") or die; | |
} | |
else { | |
my $zip = "/cygdrive/c/Program Files/7-Zip/7z.exe"; | |
die "$whoami: Couldn't find $zip; do you have 7-Zip installed?\n" | |
if (! -f $zip); | |
chomp(my $wp = `cygpath -w $c{centosiso}`); | |
my $pid = fork; | |
die "$whoami: fork: $!\n" if (! defined($pid)); | |
if (! $pid) { | |
close(STDOUT); | |
exec($zip, "x", "-y", $wp, @wanted) and die; | |
} | |
else { | |
waitpid($pid, 0); | |
die "$whoami: CentOS ISO extract with 7-Zip failed\n" if ($?); | |
} | |
} | |
} | |
&verbose(" done\n"); | |
&verbose("Fixing isolinux configuration..."); | |
if (! $c{dryrun}) { | |
my($match1, $match2, $match3, $match4); | |
#print exec("pwd"); | |
print "check 20 "; | |
open(CFGIN, "<", "isolinux/isolinux.cfg") or die; | |
print "check 21 "; | |
open(CFGOUT, ">", "isolinux/isolinux.cfg.new") or die; | |
while (<CFGIN>) { | |
if (!$match1 && s/^default linux$/default ks/) { | |
$match1 = 1; | |
} | |
elsif (!$match2 && s/^timeout 600$/timeout 1/) { | |
$match2 = 1; | |
} | |
elsif (!$match3 && s/append ks /append ks=cdrom:\/ks.cfg /) { | |
$match3 = 1; | |
} | |
elsif (!$match4 && /^label ks$/) { | |
$match4 = 1; | |
} | |
print "check 17.3 "; | |
print(CFGOUT $_) or die; | |
} | |
print "check 17.4 "; | |
#close(CFGIN) or die; | |
print "check 17.5 "; | |
close(CFGOUT) or die; | |
print "check 17.6 "; | |
die "$whoami: isolinux/isolinux.cfg in unexpected format\n" | |
if (! ($match1 && $match2 && $match3 && $match4)); | |
print "check 17.7 "; | |
rename("isolinux/isolinux.cfg.new", "isolinux/isolinux.cfg") or die; | |
} | |
print "check 18 "; die; | |
&verbose(" done\n"); | |
&verbose("Putting RPMs into ISO root..."); | |
if (! $c{dryrun}) { | |
foreach my $rpm_path (@rpm_files) { | |
my $target = "CentOS/" . basename($rpm_path); | |
if (! -f $target) { | |
symlink($rpm_path, $target) | |
or die "$whoami: symlink($rpm_path, $target: $!\n"; | |
} | |
} | |
} | |
&verbose(" done\n"); | |
&verbose("Putting GPG keys into ISO root..."); | |
foreach my $key (@gpg_keys) { | |
&get_file("$app_manager_url/$key", "gpg-keys/$key"); | |
} | |
&verbose(" done\n"); | |
&verbose("Updating ISO yum metadata..."); | |
if (! $c{dryrun}) { | |
foreach my $type (qw(filelists other primary)) { | |
my $xml = "repodata/$type.xml.gz"; | |
&debug("Building $xml..."); | |
my $fh = IO::Zlib->new($xml, "wb") or die; | |
my $first = 1; | |
my $last; | |
foreach my $repo ("$app_manager_url/isv/$c{isvrelease}", | |
"$app_manager_url/isv/$c{isvrelease}/RPMs/platform", | |
"$cs_scripts_url/cs/mkrmsiso") { | |
my $r = &get_memory("$repo/repodata/$type.xml.gz"); | |
my $data = Compress::Zlib::memGunzip($r->content); | |
$data =~ s/(<[^>]+>\s*)$//; | |
$last = $1; | |
if ($first) { | |
$first = undef; | |
} | |
else { | |
$data =~ s/^(.*\n.*\n)//; | |
} | |
$data =~ s/(location href=\")(?:[^\"]+\/)?([^\"]+)/$1CentOS\/$2/g; | |
$fh->print($data) or die; | |
} | |
$fh->print($last) or die; | |
$fh->close or die; | |
&debug(" done\n"); | |
} | |
my $xml = "repodata/repomd.xml"; | |
&debug("Building $xml..."); | |
open(XML, ">", $xml) or die; | |
print(XML "<?xml version=\"1.0\" encoding=\"UTF-8\"?> | |
<repomd xmlns=\"http://linux.duke.edu/metadata/repo\">\n") or die; | |
foreach my $type (qw(other filelists primary comps)) { | |
my $file = "repodata/$type.xml"; | |
my $data_type = ($type eq "comps") ? "group" : $type; | |
my($compressed, $open_checksum); | |
if (! -f $file) { | |
$compressed = 1; | |
$file = "$file.gz"; | |
} | |
my($timestamp) = (stat($file))[9]; | |
my($checksum) = Digest::SHA->new(1)->addfile($file)->hexdigest | |
or die; | |
if ($compressed) { | |
open(UNCOMPRESSED, "-|", "zcat $file") or die; | |
$open_checksum = Digest::SHA->new(1)->addfile(*UNCOMPRESSED)->hexdigest | |
or die; | |
close(UNCOMPRESSED) or die; | |
} | |
print(XML " <data type=\"$data_type\"> | |
<location href=\"$file\"/> | |
<checksum type=\"sha\">$checksum</checksum> | |
<timestamp>$timestamp</timestamp>\n") or die; | |
if ($compressed) { | |
print(XML " <open-checksum type=\"sha\">$open_checksum</open-checksum>\n") or die; | |
} | |
print (XML " </data>\n") or die; | |
} | |
print(XML "</repomd>\n") or die; | |
close(XML) or die; | |
&debug(" done\n"); | |
} | |
&verbose(" done\n"); | |
&verbose("Creating kickstart configuration file..."); | |
open(KS, ">", "ks.cfg") or die; | |
print(KS "# Firewall configuration | |
firewall --disabled | |
# Install OS instead of upgrade | |
install | |
# Root password | |
rootpw $c{rootpassword} | |
# Network information\n") or die; | |
if ($c{netproto} eq "static") { | |
print(KS "network --bootproto=static --device=eth0 --gateway=$c{gateway} --ip=$c{address} ", ($c{nameserver} ? "--nameserver=$c{nameserver} " : ""), "--netmask=$c{netmask} --noipv6 --onboot=on --hostname=$c{hostname}\n") or die; | |
} | |
else { | |
print(KS "network --bootproto=dhcp --device=eth0 --onboot=on --hostname=$c{hostname}\n") or die; | |
} | |
my $divider; | |
if ($c{hyperv}) { | |
$divider = "--append divider=10"; | |
} | |
else { | |
$divider = ""; | |
} | |
print(KS "# System authorization information | |
auth --useshadow --passalgo=md5 | |
# Use text mode install | |
text | |
# System keyboard | |
keyboard us | |
# System language | |
lang en_US | |
# SELinux configuration | |
selinux --disabled | |
# Do not configure the X Window System | |
skipx | |
# Installation logging level | |
logging --level=info | |
# Use CDROM installation media | |
cdrom | |
# Halt after installation | |
halt | |
# System timezone | |
# See Red Hat Bugzilla #481617 | |
timezone --utc America/New_York | |
# System bootloader configuration | |
bootloader --location=mbr $divider") or die; | |
if ($c{grubpassword}) { | |
print(KS " --password=\"$c{grubpassword}\"") or die; | |
} | |
print(KS " | |
# Partition clearing information | |
clearpart --all | |
zerombr | |
# Disk partitioning information\n") or die; | |
my $hd_prefix; | |
if ($c{scsi}) { | |
$hd_prefix = "sd"; | |
} | |
else { | |
$hd_prefix = "hd"; | |
} | |
if ($c{virtual}) { | |
print(KS "part /boot --asprimary --fstype=\"ext3\" --ondisk=${hd_prefix}a --size=75 | |
part / --asprimary --fstype=\"ext3\" --ondisk=${hd_prefix}a --size=4096 | |
part /tmp --asprimary --fstype=\"ext2\" --grow --ondisk=${hd_prefix}a --size=1 | |
part swap --fstype=\"swap\" --ondisk=${hd_prefix}a --size=2048 | |
part /home --asprimary --fstype=\"ext3\" --grow --ondisk=${hd_prefix}b --size=1 | |
part /var --asprimary --fstype=\"ext3\" --grow --ondisk=${hd_prefix}c --size=1\n") or die; | |
} | |
else { | |
print(KS "part /boot --asprimary --fstype=\"ext3\" --ondisk=${hd_prefix}a --size=75 | |
part /var --asprimary --fstype=\"ext3\" --ondisk=${hd_prefix}a --size=39936 | |
part /tmp --asprimary --fstype=\"ext2\" --ondisk=${hd_prefix}a --size=50176 | |
part swap --fstype=\"swap\" --ondisk=${hd_prefix}a --size=2048 | |
part / --fstype=\"ext3\" --ondisk=${hd_prefix}a --size=4096 | |
part /home --fstype=\"ext3\" --grow --ondisk=${hd_prefix}a --size=1\n") or die; | |
} | |
print(KS "%packages --nobase\n") or die; | |
map { | |
print(KS "$_\n") or die; | |
} @platform_rpms, @isv_rpms, @cs_scripts_rpms; | |
print(KS "%pre | |
# See Red Hat Bugzilla #502936 | |
ifconfig lo up | |
# See Red Hat Bugzilla #383531 | |
chmod 666 /dev/null | |
hostname $c{hostname} # otherwise host_manager.sh will refuse to run | |
cp -r /mnt/source/gpg-keys /tmp\n") or die; | |
if ($c{vmwaretools}) { | |
print(KS "cp /mnt/source/CentOS/VMwareTools*.rpm /tmp\n") or die; | |
} | |
print(KS "# Needed later by expect, see Red Hat Bugzilla #502980 | |
\(while [ ! -d /mnt/sysimage/dev/pts ]; do sleep 5; done; mount -t devpts devpts /mnt/sysimage/dev/pts\) & | |
%post --nochroot | |
exec >/mnt/sysimage/root/install-post.log 2>&1 | |
# This has to be done outside of a chroot because otherwise the files | |
# aren't available to import. | |
for file in /tmp/gpg-keys/*; do | |
rpm --root /mnt/sysimage --import \$file | |
done\n\n") or die; | |
if ($c{vmwaretools}) { | |
print(KS "# This has to be done outside of a chroot because otherwise the file | |
# isn't available to copy. | |
cp /tmp/VMwareTools*.rpm /mnt/sysimage/root\n") or die; | |
} | |
print(KS "\n# Do the rest inside a chroot. | |
chroot /mnt/sysimage /bin/bash <<\\CHROOTEOF | |
# See Red Hat Bugzilla #481617 | |
ln -f /usr/share/zoneinfo/Etc/UTC /etc/localtime | |
perl -i -e '\$/ = undef; \$_ = <>; | |
s,America/New_York,Etc/UTC, or warn \"Could not update time zone in \$ARGV\\n\"; | |
print;' /etc/sysconfig/clock | |
# Otherwise rpm_manager.sh will complain that gpg-pubkey isn't installed | |
rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5\n\n") or die; | |
if ($c{emacs}) { | |
print(KS "# Make sure emacs will not get uninstalled | |
cat > /etc/rpmmgr/rpms.d/emacs <<EOF\n", join("\n", @emacs_rpms), "\nEOF\n") | |
or die; | |
} | |
if ($c{vmwaretools}) { | |
print(KS "# Make sure VMwareTools won't get uninstalled | |
echo VMwareTools > /etc/rpmmgr/rpms.d/VMwareTools | |
# Gross but effective -- configure VMware Tools at next reboot, before | |
# the network is brought up. | |
VMTC=/etc/rc.d/rc3.d/S09VMwareToolsConfig | |
cat > \$VMTC <<EOF | |
#!/bin/bash -e | |
rpm -U /root/VMwareTools*.rpm | |
/usr/bin/vmware-config-tools.pl -d | |
/usr/sbin/vmware-guestd --cmd 'vmx.set_option synctime 0 1' | |
/usr/sbin/rpm_manager.sh --nodebug --nonagios || : | |
/bin/rm -f /root/VMwareTools*.rpm \$VMTC | |
EOF | |
chmod +x \$VMTC\n") or die; | |
} | |
print(KS "RCLOCAL=/etc/rc.d/rc.local | |
cat > \$RCLOCAL.ts <<EOF | |
#!/bin/sh | |
exec >/root/rc.local.postinstall.log 2>&1 | |
set -x | |
# Put things here that we want to run just once the first time the appliance | |
# is booted after it is installed.\n\n") or die; | |
if ($c{boston}) { | |
print(KS "perl -i -e '\\\$/ = undef; \\\$_ = <>; s/download01/app-manager.bos/; print;' \\ | |
/etc/yum.repos.d/rms.repo\n") or die; | |
} | |
print(KS "# Definitely necessary for DHCP, not always necessary for static, but | |
# doesn't hurt and might help to ensure that things are in a | |
# consistent state. | |
/usr/sbin/host_manager.sh | |
# Prevent NSCA spool file from having incorrect permissions. | |
python -c 'import shelve; db = shelve.open(\"/var/spool/send_nsca_spool/nscaspool.db\", \"c\");' | |
chown nagios /var/spool/send_nsca_spool/nscaspool.db | |
# Run the original rc.local and move it back into place. | |
\. \$RCLOCAL.post | |
mv -f \$RCLOCAL.post \$RCLOCAL | |
EOF | |
mv -f \$RCLOCAL \$RCLOCAL.post | |
mv -f \$RCLOCAL.ts \$RCLOCAL | |
chmod +x \$RCLOCAL | |
CHROOTEOF\n") or die; | |
close(KS) or die; | |
&verbose(" done\n"); | |
&verbose("Creating ISO\n"); | |
chdir($dir) or die; | |
if (! $c{dryrun}) { | |
chmod('0755', "isolinux/isolinux.bin"); | |
system("mkisofs", "-f", "-R", "-J", "-T", "-r", "-l", "-d", "-o", | |
$c{outputfile}, "-b", "isolinux/isolinux.bin", "-c", | |
"isolinux/boot.cat", "-no-emul-boot", "--boot-load-size", "4", | |
"-boot-info-table", "$wd/iso-root") and die; | |
} | |
# Clean up | |
if (! $c{preserve}) { | |
&verbose("Cleaning up..."); | |
rmtree("$wd"); | |
&verbose(" done\n"); | |
} | |
&verbose("\nDone!\n"); | |
### | |
### UTILITY FUNCTIONS | |
### | |
# Display a message if running in verbose mode | |
sub verbose { | |
my(@message) = @_; | |
return if (! $c{verbose}); | |
print(STDERR @message); | |
} | |
# Display a message if running in debug mode | |
sub debug { | |
my(@message) = @_; | |
return if (! $c{debug}); | |
print(STDERR @message); | |
} | |
# Fetch a URL into memory | |
sub get_memory { | |
my($url) = @_; | |
&debug("Fetching $url into memory..."); | |
my $response = $ua->get($url); | |
if (! $response->is_success) { | |
die "$whoami: Failed to fetch $url\n"; | |
} | |
&debug(" done\n"); | |
return $response; | |
} | |
# Fetch a URL into a file | |
sub get_file { | |
my($url, $file) = @_; | |
my $response = $ua->get($url, ":content_file" => $file); | |
if (! $response->is_success) { | |
die "$whoami: Failed to fetch $url into $file\n"; | |
} | |
return $response; | |
} | |
# Fetch files if we don't already have them with the correct size. | |
# Also, update the timestamps on the files to the current time even if | |
# we don't fetch them (so that they won't get cleaned up | |
# automatically). Returns the paths of the files. | |
sub maybe_fetch { | |
my(@urls) = @_; | |
my(%o); | |
if (ref $urls[-1] eq 'HASH') { | |
%o = %{pop @urls}; | |
} | |
my(@files); | |
foreach my $url (@urls) { | |
my $file = $c{rpmcache} . "/" . basename($url); | |
push(@files, $file); | |
if ($c{fetch}) { | |
my $bytes; | |
my $head = $ua->head($url); | |
if ($head->is_success) { | |
$bytes = $head->header('content-length'); | |
if (-f $file) { | |
&debug("Checking if $url is same size as $file..."); | |
if ($bytes == -s $file) { | |
&debug(" yes; refreshing timestamp\n"); | |
utime(time(), time(), $file); | |
next; | |
} | |
else { | |
&debug(" no\n"); | |
unlink($file); | |
} | |
} | |
} | |
else { | |
&debug("Failed to fetch header for $url\n"); | |
} | |
&verbose("Fetching $url into $file", ($bytes ? " ($bytes bytes)" : ""), | |
"..."); | |
&get_file($url, $file) if ($o{always} || ! $c{dryrun}); | |
&verbose(" done\n"); | |
} | |
} | |
return wantarray ? @files : $files[0]; | |
} | |
# Find the URL of a particular RPM in the listing in the specified | |
# HTTP response | |
sub find_rpm_urls { | |
my($rpm, $response, $o) = @_; | |
my(%o) = $o ? %{$o} : (); | |
my $base = $response->base->as_string; | |
my $rpm_re = $rpm; | |
$rpm_re =~ s/(\W)/\\$1/g; | |
my(@basenames) = ($response->content =~ /\"($rpm_re-[^-\"]+-[^-\"]+\.[^.\"]+\.rpm)\"/g); | |
if (! (@basenames || $o{optional})) { | |
print "$whoami: Couldn't find RPM $rpm on appliance manager\n"; | |
} | |
my(@urls) = map($base . $_, @basenames); | |
return wantarray ? @urls : (@urls ? $urls[0] : undef); | |
} | |
# Get the appliance manager base URL for a particular appliance manager host | |
sub app_manager_url { | |
"https://tamaleserver:gyqsdi34wesd\@$_[0]/yum"; | |
} | |
print " last check"; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment