Created
September 24, 2010 16:38
-
-
Save lamont-granquist/595645 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
#!/usr/local/perl-5.10.1/bin/perl | |
# | |
# Init file runs on firstboot | |
# | |
# chkconfig: 2345 57 43 | |
# description: rhapsody firstboot startup script | |
# | |
# | |
# RH7.3/RHEL3/RHEL4 /etc/rc.d/rc voodoo incantation: "action " | |
# RHEL5 /etc/rc.d/rc voodoo incantation: "init.d/functions" | |
# | |
use strict; | |
use warnings; | |
use Socket; | |
use LWP; | |
use JSON; | |
my %DOMAINS = ( | |
"sea0.rhapsody.com" => 10, | |
"sea1.rhapsody.com" => 11, | |
"sea2.rhapsody.com" => 12, | |
"sfo1.rhapsody.com" => 21, | |
); | |
my %STAGES = ( | |
"corp" => 1, | |
"prod" => 1, | |
"dev" => 1, | |
"test" => 1, | |
"int" => 1, | |
"load" => 1, | |
"beta" => 1, | |
); | |
$SIG{HUP} = sub { die "USER HANGUP"; }; | |
$SIG{INT} = sub { die "USER INTERRUPT"; }; | |
$SIG{PIPE} = 'IGNORE'; | |
my $arg = shift @ARGV; | |
exit 0 unless defined $arg && $arg eq 'start'; | |
open my $motd, ">", "/etc/motd"; | |
print $motd "WARNING: rhapsody-firstboot did not finish correctly\n"; | |
print $motd "WARNING: either login on the console and finish the process\n"; | |
print $motd "WARNING: or run:\n"; | |
print $motd "\t/etc/rc.d/init.d/rhapsody-firstboot start\n"; | |
close $motd; | |
print "Doing firstboot configuration...\n"; | |
# | |
# set xen hostname based on xencenter name | |
# | |
system("/usr/bin/yum -y install xen-detect >/dev/null"); | |
if ( system("/usr/local/bin/xen-detect --pv >/dev/null") == 0 ) { | |
print "PV guest detected: installing xe-guest-utilities\n"; | |
# fuck you citrix, get out of my yum. | |
system("/bin/rm -f /etc/yum.repos.d/Citrix.repo"); | |
system("/usr/bin/yum clean all > /dev/null"); | |
system("/usr/bin/yum -y install xe-guest-utilities >/dev/null"); | |
my $xen_hostname=`/usr/local/bin/xen-hostname 2>/dev/null`; | |
chomp $xen_hostname; | |
print "PV guest setting hostname to: $xen_hostname\n"; | |
system("/bin/hostname $xen_hostname"); | |
} | |
# | |
# loop if we catch a ctrl-c, exit if we get a SIGHUP | |
# | |
while(1) { | |
eval { | |
main(); | |
}; | |
if ( $@ ) { | |
if ( $@ =~ /USER INTERRUPT/ ) { | |
next; | |
} elsif ( $@ =~ /USER HANGUP/ ) { | |
last; | |
} else { | |
die $@; | |
} | |
} | |
last; | |
} | |
sub main { | |
# | |
# see if our hostname is already valid and/or prompt for a valid hostname | |
# | |
my $hostname = `/bin/hostname`; | |
chomp $hostname; | |
my $virt = `/usr/local/bin/hostinfo --virt`; | |
chomp $virt; | |
if ( $virt ne "xen_dom0" ) { # don't prompt for hostnames on dom0's | |
while(1) { | |
if ( valid_hostname( $hostname ) ) { | |
last; | |
} else { | |
while(1) { | |
print STDERR "\nEnter Valid Hostname: "; | |
$hostname = <STDIN>; | |
chomp $hostname; | |
print "\n$hostname correct? "; | |
my $ans = <STDIN>; | |
last if $ans =~ /^[yY]/; | |
} | |
} | |
} | |
} else { | |
# for now, just ignore dom0s | |
exit_cleanup(); | |
} | |
set_hostname( $hostname ); | |
if ( $hostname =~ /newbuild/ ) { | |
die "bad hostname: $hostname"; | |
} | |
if ( $hostname =~ /localhost/ ) { | |
die "bad hostname: $hostname"; | |
} | |
# | |
# find an IP addr to use | |
# | |
print "Setting ip address...\n"; | |
my $iaddr = gethostbyname($hostname); | |
if ( $iaddr ) { | |
# | |
# already have an IP address in DNS, just use it | |
# | |
my $ip = inet_ntoa($iaddr); | |
if ( system("ping -W 1 -c 3 $ip >/dev/null") == 0 ) { | |
# | |
# probably this means we're on this IP already, and all is actually good, otherwise | |
# we have a valid A record pointing to this IP addr and someone is squatting on the IP, | |
# so we need to kill ourselves because that's bad... | |
# | |
warn "cowardly refusing to use IPADDR already responding to ping: $ip\n"; | |
exit_cleanup(); | |
} | |
set_ip($ip); | |
} else { | |
while(1) { | |
my $eth0ip = `ifconfig eth0 | egrep 'inet addr'`; | |
chomp $eth0ip; | |
$eth0ip =~ s/.*inet addr:(\S+).*/$1/; | |
my $ua = new LWP::UserAgent; | |
$ua->agent("rhapsody-firstboot " . $ua->agent); | |
my $url = "http://cmdb/json/ip-allocate.json?fqdn=$hostname&addr=$eth0ip"; | |
my $req = new HTTP::Request GET => $url; | |
my $res; | |
eval { | |
local $SIG{ALRM} = sub { die "Alarm timeout"; }; | |
alarm(15); | |
$res = $ua->request($req); | |
alarm(0); | |
}; | |
if ($@) { | |
if ( $@ =~ /Alarm timeout/ ) { | |
warn "timeout requesting IP address from cmdb, is it down?\n"; | |
warn "waiting 60 seconds...\n"; | |
sleep 60; | |
next; | |
} else { | |
warn "some kinda error: $@\n"; | |
warn "waiting 60 seconds...\n"; | |
sleep 60; | |
next; | |
} | |
} | |
if (!$res->is_success) { | |
warn "some kinda error: " . $res->status_line . "\n"; | |
warn "waiting 60 seconds...\n"; | |
sleep 60; | |
next; | |
} | |
my $response = from_json( $res->content ); | |
if ( defined $response && exists $response->{ip_address} ) { | |
set_ip( $response->{ip_address} ); | |
last; | |
} | |
warn "waiting 60 seconds because something didn't work...\n"; | |
sleep 60; | |
} | |
} | |
exit_cleanup(); | |
} | |
sub valid_hostname { | |
my ($hostname) = @_; | |
my ($short, $domain) = ( $hostname =~ /([^\.]*)\.(.*)/ ); | |
if ( !exists $DOMAINS{$domain} ) { | |
print STDERR "invalid domain: $domain\n"; | |
print STDERR "valid domains:\n"; | |
foreach my $domain ( sort keys %DOMAINS ) { | |
print "\t$domain\n"; | |
} | |
return; # false | |
} | |
if ( $short =~ /newbuild/ ) { | |
print STDERR "invalid short hostname: $short\n"; | |
return; # false | |
} | |
if ( $short =~ /localhost/ ) { | |
print STDERR "invalid short hostname: $short\n"; | |
return; # false | |
} | |
my $digits = $DOMAINS{$domain}; | |
if ( $short !~ /\-$digits[0-9][0-9]$/ ) { | |
print STDERR "invalid short hostname: $short\n"; | |
print STDERR "must end in -${digits}NN for $domain\n"; | |
return; # false | |
} | |
my $stage = $short; | |
$stage =~ s/\-$digits[0-9][0-9]$//; | |
$stage =~ s/.*\-//; | |
if ( ! exists $STAGES{$stage} ) { | |
print STDERR "invalid short hostname: $short\n"; | |
print STDERR "must be format <app>-<stage>-${digits}NN\n"; | |
print STDERR "valid stages:\n"; | |
foreach my $stage ( sort keys %STAGES ) { | |
print "\t$stage\n"; | |
} | |
return; # false | |
} | |
return 1; # true | |
} | |
sub set_ip { | |
my ($ip) = @_; | |
my $netmask = "255.255.255.0"; | |
my $gateway = $ip; | |
$gateway =~ s/\.\d+$/.1/; | |
open my $ifcfg, ">", "/etc/sysconfig/network-scripts/ifcfg-eth0" or die; | |
print $ifcfg <<EOF; | |
# Generated by /etc/rc.d/init.d/rhapsody-firstboot | |
DEVICE=eth0 | |
BOOTPROTO=static | |
IPADDR=$ip | |
NETMASK=$netmask | |
GATEWAY=$gateway | |
ONBOOT=yes | |
EOF | |
close $ifcfg or die; | |
print "fixed static IP: $ip\n"; | |
system("/etc/rc.d/init.d/network restart"); | |
} | |
sub set_hostname { | |
my ($hostname) = @_; | |
print "setting hostname to $hostname\n"; | |
system("/bin/hostname $hostname"); | |
my $short = $hostname; | |
$short =~ s/\..*//; | |
open my $old, "<", "/etc/sysconfig/network" or die; | |
open my $new, ">", "/etc/sysconfig/network.new" or die; | |
while(<$old>) { | |
if ( /^HOSTNAME\s*=/ ) { | |
print $new "HOSTNAME=$hostname\n"; | |
next; | |
} | |
if ( /^DHCP_HOSTNAME\s*=/ ) { | |
print $new "DHCP_HOSTNAME=$short\n"; | |
next; | |
} | |
print $new $_; | |
} | |
close $new or die; | |
close $old or die; | |
chown 0, 0, "/etc/sysconfig/network.new"; | |
chmod 0644, "/etc/sysconfig/network"; | |
rename "/etc/sysconfig/network.new", "/etc/sysconfig/network"; | |
} | |
sub exit_cleanup { | |
open my $motd, ">", "/etc/motd"; | |
print $motd "\nAuthorized uses only. All activity may be monitored and reported.\n\n"; | |
close $motd; | |
system("/sbin/chkconfig rhapsody-firstboot off"); | |
exit 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment