Skip to content

Instantly share code, notes, and snippets.

@kazeburo
Created March 17, 2010 03:56
Show Gist options
  • Save kazeburo/334894 to your computer and use it in GitHub Desktop.
Save kazeburo/334894 to your computer and use it in GitHub Desktop.
#!/usr/bin/perl
package KickstartHTTPD;
use strict;
use warnings;
use base qw(HTTP::Server::Simple::CGI);
my $KICKSTART;
sub kickstart {
my $class = shift;
$KICKSTART = shift;
}
sub handle_request {
my $self = shift;
my $cgi = shift;
print "HTTP/1.0 200 OK\r\n";
print $cgi->header(-type=>'text/plain', -length=>length($KICKSTART));
print $KICKSTART;
kill 'SIGUSR1', getppid();
}
package main;
use strict;
use warnings;
use IO::Socket::INET;
use Time::HiRes;
use Regexp::Common qw /net/;
use Getopt::Long;
my $opt = {};
my $sock = IO::Socket::INET->new(PeerAddr=>"ftp.iij.ad.jp", PeerPort=>80);
$opt->{ipaddr} = $sock->sockhost;
die 'cannot get ipaddr' if !$opt->{ipaddr} or $opt->{ipaddr} !~ $RE{net}{IPv4}{-keep};
my $realserver_name = sprintf("%03d%03d",$4,$5);
GetOptions(
'p|private=s' => \$opt->{private},
);
die 'private not defined or incorrect' if !$opt->{private} or $opt->{private} !~ $RE{net}{IPv4}{-keep};
$opt->{private_network} = "$2.$3.$4";
$opt->{vmname} = sprintf("v%s-%03d",$realserver_name,$5);
my $kickstart = join "", <DATA>;
$kickstart =~ s/\[%\s([^ ]+?)\s%\]/$opt->{$1}/ge;
KickstartHTTPD->kickstart($kickstart);
test_tcp(
client => sub {
my $port = shift;
my $KICKSTART_WAIT = 0;
local $SIG{USR1} = sub { $KICKSTART_WAIT++ };
system(
'virt-install',
'--connect', 'qemu:///system',
'-n', $opt->{vmname},
'-r', 512,
'--vcpus=1',
'-f', "/data/images/$opt->{vmname}.img",
'-s', '20',
'--nographics',
'--os-type', 'linux',
'--os-variant=virtio26',
'--accelerate',
'--network=bridge:br0',
'--hvm',
'--noautoconsole',
'--wait', '-1',
'--location', 'http://ftp.iij.ad.jp/pub/linux/centos/5.4/os',
'--extra-args', qq!ks=http://$opt->{ipaddr}:$port/kickstart.cfg ksdevice=eth0 ip=$opt->{private} netmask=255.255.255.0 gateway=$opt->{private_network}.1 dns=$opt->{private_network}.1 console=tty0 console=ttyS0,115200n8!
);
# system('curl',"http://$opt->{ipaddr}:$port/kickstart.cfg");
while( !$KICKSTART_WAIT ) { Time::HiRes::sleep(0.1) };
Time::HiRes::sleep(5);
},
server => sub {
my $port = shift;
KickstartHTTPD->new($port)->run;
}
);
sub find_port {
my $self = shift;
my $need = shift || 4;
my @port;
for my $test_port ( 11220..11250 ) {
my $sock = IO::Socket::INET->new(
PeerAddr => 'localhost',
PeerPort => $test_port,
Proto => 'tcp'
);
if ( !$sock ) {
push @port, $test_port;
last if @port >= $need;
}
}
die "couldnot find empty port" unless @port;
die "couldnot find enough empty ports" if @port < $need and wantarray;
return wantarray ? @port : $port[0];
}
sub test_tcp {
my %args = @_;
die 'client must be coderef' if( !$args{client} || ref $args{client} ne 'CODE');
die 'server must be coderef' if( !$args{server} || ref $args{server} ne 'CODE');
my $port = $args{port} || find_port();
if ( my $pid = fork() ) {
# parent.
my $sock;
for (1..30) {
Time::HiRes::sleep 0.1;
$sock = IO::Socket::INET->new(
PeerAddr => 'localhost',
PeerPort => $port,
Proto => 'tcp'
);
last if $sock;
}
die 'couldnot connect to $port' unless $sock;
close($sock);
$args{client}->($port);
kill TERM => $pid;
waitpid( $pid, 0 );
}
elsif ( $pid == 0 ) {
# child
$args{server}->($port);
}
else {
die "fork failed: $!";
}
}
__DATA__
install
url --url http://ftp.iij.ad.jp/pub/linux/centos/5.4/os/x86_64
lang en_US.UTF-8
keyboard us
network --device eth0 --bootproto static --ip [% private %] --netmask 255.255.255.0 --gateway [% private_network %].1 --nameserver [% private_network %].1 --hostname [% vmname %]
rootpw hogehoge
firewall --disabled
authconfig --enableshadow --enablemd5
selinux --disabled
timezone Asia/Tokyo
bootloader --location=mbr --driveorder=vda --append="console=ttyS0,115200n8"
clearpart --all --initlabel
part / --fstype ext3 --size=10000 --ondisk=vda --asprimary
part swap --size=2000 --ondisk=vda --asprimary
part /data --fstype ext3 --size=1 --grow --ondisk=vda
reboot
%packages
@base
@core
@development-libs
@development-tools
@editors
@text-internet
keyutils
trousers
fipscheck
device-mapper-multipath
imake
-firstboot-tui
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment