Skip to content

Instantly share code, notes, and snippets.

@lamont-granquist
Created September 24, 2010 16:38
Show Gist options
  • Save lamont-granquist/595645 to your computer and use it in GitHub Desktop.
Save lamont-granquist/595645 to your computer and use it in GitHub Desktop.
#!/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