#!/usr/bin/perl -w # # Create a new Xen instances containing an installation of Debian # # This is a reasonably simple script which is more of a cheap hack # than a production tool, however it does appear to work nicely for # my own uses. # # The output of this script will be two files for each new instance: # # 1. One 2Gb file for the installations primary disk image. # 2. One 128Mb file for the images swap partition. # # Usage: # # ./xen-create-image --hostname='vm03' --dir=/home/zen \ # --ip=192.168.1.93 --gateway=192.168.1.1 \ # --network=192.168.1.0 --mask=255.255.255.0 \ # # The initial two arguments '--hostname' and '--dir' are mandatory, # and control the hostname and output directory respectively. Other # parameters are all network based, either give the list as shown above # or use the '--dhcp' option to setup the host with a DHCP allocated # IP address. # # 'dir' is used to create the output disk images which are referenced # in the Xen configuration file. They will be created as: # # # $dir/domains/ # $dir/domains/$hostname/disk.img # $dir/domains/$hostname/swap.img # # The '/domains/' subdirectory, and sub-subdirectory named after the # hostname will be created if necessary. # # Basic setup with your hosts file, resolv.conf, etc works just fine. # # The image will also have an OpenSSH server installed upon it, and # an appropriate /etc/inittab file created. # # You are *strongly* advised to chroot() into the new instance once # it has been setup to prune the users in the /etc/passwd file which # will be copied from your hosts system. # # # Steve # -- # http://www.steve.org.uk/ # # $Id: xen-create-image,v 1.8 2005-12-18 03:53:33 steve Exp $ # use strict; use File::Copy; use File::Temp qw/ tempdir /; use Getopt::Long; # # Options set on the command line. # my $HOSTNAME; # Mandatory. my $DIR; # Mandatory. # # Either *all* the relevent networking options must be setup, or # DHCP must be selected. # # my $IP; # set with '--ip=dd.dd.dd.dd' my $GATEWAY; # set with '--gateway=dd.dd.dd.dd' my $NETMASK="255.255.255.0"; # set with '--mask=dd.dd.dd.dd' my $BROADCAST="192.168.1.255"; # set with '--broadcase=ddd.dd.dd.d' my $NETWORK="192.168.1.0"; # set with '--network=dd.dd.dd.dd' my $DHCP=0; # This setting overides the other network options my $MIRROR="http://ftp.us.debian.org/debian"; # set with '--mirror=http://www.etc.com"' my $SIZE="2000M"; # set with '--size=1000M[b] / 1G[b]" my $SWAP_SIZE="128M"; # set with '--swapsize=... like --size" my $MEMORY="96M"; # set with --memory=128Mb/128M my $FS='ext3'; # # Constants for filesystem usage. # my %FILESYSTEM_CREATE; my %FILESYSTEM_MOUNT; $FILESYSTEM_CREATE{'ext3'} = '/sbin/mkfs.ext3 -F '; $FILESYSTEM_CREATE{'xfs'} = '/sbin/mkfs.xfs -d name='; $FILESYSTEM_MOUNT{'ext3'} = '-t ext3'; $FILESYSTEM_MOUNT{'xfs'} = '-t xfs'; # # Parse options. # GetOptions( "hostname=s", \$HOSTNAME, "ip=s", \$IP, "gateway=s", \$GATEWAY, "mask=s", \$NETMASK, "broadcast=s", \$BROADCAST, "network=s", \$NETWORK, "dir=s", \$DIR, "dhcp", \$DHCP, "mirror=s", \$MIRROR, "size=s", \$SIZE, "swapsize=s", \$SWAP_SIZE, "memory=s", \$MEMORY, "fs=s", \$FS ); # # Check that the arguments the user has supplied are both # valid, and complete. # checkArguments(); # # If the output directories don't exist then create them. # if ( ! -d $DIR . "/domains/" ) { mkdir $DIR . '/domains', 0777 || die "Cannot create $DIR/domains - $!"; } if ( ! -d $DIR . "/domains/" . $HOSTNAME ) { mkdir $DIR. '/domains/' . $HOSTNAME, 0777 || die "Cannot create $DIR/domains/$HOSTNAME - $!" ; } # # The two images we'll use, one for the disk image, one for swap. # my $image = $DIR . '/domains/' . $HOSTNAME . "/disk.img" ; my $swap = $DIR . '/domains/' . $HOSTNAME . "/swap.img" ; # # Create swapfile and initialise it. # print "Creating swapfile : $swap\n"; $SWAP_SIZE =~ s/Mb*$//i; `/bin/dd if=/dev/zero of=$swap bs=1024k count=$SWAP_SIZE >/dev/null 2>/dev/null`; print "Initializing swap file\n"; `/sbin/mkswap $swap`; print "Done\n"; # # Create disk file and initialise it. # print "Creating disk image: $image\n"; $SIZE =~ s/Mb*$/k/i; `/bin/dd if=/dev/zero of=$image bs=$SIZE count=1 seek=1024 >/dev/null 2>/dev/null`; print "Creating EXT3 filesystem\n"; my $create = $FILESYSTEM_CREATE{lc( $FS ) } . $image; `$create`; print "Done\n"; # # Now mount the image, in a secure temporary location. # my $dir = tempdir( CLEANUP => 1 ); my $mount_cmd = "mount " . $FILESYSTEM_MOUNT{lc($FS)} . " -o loop $image $dir"; `$mount_cmd`; # Test that the mount worked my $mount = `/bin/mount`; if ( ! $mount =~ /$image/) { print "Something went wrong trying to mount the new filesystem\n"; exit; } # # Install the base system. # print "Running debootstrap to install the system. This will take a while!\n"; `debootstrap sarge $dir $MIRROR`; print "Done\n"; # # If the debootstrap failed then we'll setup the output directories # for the configuration files here. # `mkdir -p $dir/etc/apt`; `mkdir -p $dir/etc/network`; # # OK now we can do the basic setup. # print "Setting up APT sources .. "; open( APT, ">", $dir . "/etc/apt/sources.list" ); print APT<", $dir . "/etc/fstab" ); print TAB<", "/etc/xen/$HOSTNAME.cfg" ); print XEN< Mb if ( $SIZE =~ /^(\d+)Gb*$/i ) { $SIZE = $1 * 1024 . "M"; } if ( $SWAP_SIZE =~ /^(\d+)Gb*$/i ) { $SWAP_SIZE = $1 * 1024 . "M"; } # Strip trailing Mb from the memory size. if ( $MEMORY =~ /^(\d+)Mb*$/i ) { $MEMORY = $1; } # # Check mirror format # if (!($MIRROR =~ /^http/i)) { print "Please enter a valid mirror.\n"; exit; } # # Only one of DHCP / IP is required. # if ( $DHCP && $IP ) { print "You've chosen both DHCP and an IP address.\n"; print "Only one is supported\n"; exit; } if ( $DHCP ) { $GATEWAY=""; $NETMASK=""; $BROADCAST=""; $IP=""; } # # Ensure we know how to create *and* mount the given filesystem. # if ( !defined( $FILESYSTEM_CREATE{lc( $FS ) } ) || !defined( $FILESYSTEM_MOUNT{lc( $FS ) } ) ) { print "Unknown filesystem. Valid choices are:\n"; foreach my $key (sort keys %FILESYSTEM_MOUNT ) { print "\t" . $key . "\n"; } exit; } } =head2 setupNetworking Setup the /etc/network/interfaces file, and the hostname upon the virtual instance. =cut sub setupNetworking { my ( $prefix ) = ( @_ ); `echo '$HOSTNAME' > $prefix/etc/hostname`; open( IP, ">", $prefix . "/etc/network/interfaces" ); if ( $DHCP ) { print IP< ) { chomp $line; if ( $line =~ /:respawn:/ ) { if ( $line =~ /^1/ ) { $line = "s0:12345:respawn:/sbin/getty 115200 ttyS0 linux" } else { $line = "#" . $line; } } push @init, $line; } close( INITTAB ); open( OUTPUT, ">", "$prefix/etc/inittab" ); foreach my $line ( @init ) { print OUTPUT $line . "\n"; } close( OUTPUT ) }