472 lines
9.5 KiB
Perl
Executable File
472 lines
9.5 KiB
Perl
Executable File
#!/usr/bin/perl -w
|
|
|
|
=head1 NAME
|
|
|
|
xen-create-nfs - Create a Xen configuration file for an NFS-root guest.
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
xen-create-nfs [options]
|
|
|
|
Help Options:
|
|
--help Show help information.
|
|
--manual Read the manual for this script.
|
|
--version Show the version information and exit.
|
|
--verbose Show diagnostic output.
|
|
|
|
Networking Options:
|
|
--broadcast The broadcast address to use when configured with a static IP.
|
|
--dhcp Configure the guest to use DHCP for IP allocation.
|
|
--gateway The gateway address to use when configured with a static IP.
|
|
--hostname The hostname to configure for the guest.
|
|
--netmask The netmask to use when configured with a static IP.
|
|
--ip The IP address to use when configured with a static IP.
|
|
|
|
General options:
|
|
--admins Specify which users should be setup as xen-shell admins.
|
|
--force Force the overwriting of an existing configuration file.
|
|
--initrd Specify the initial ramdisk for the guest.
|
|
--kernel Specify the kernel to use for the guest.
|
|
--memory Specify the memory to allocate for this guest.
|
|
--mac Specify the MAC address to use for the guest.
|
|
--template Specify an alternative template file to use.
|
|
|
|
NFS options:
|
|
--nfs_server Specify the NFS server to mount the root partition from.
|
|
--nfs_root Specify the path, upon the NFS server, to mount.
|
|
|
|
=cut
|
|
|
|
|
|
=head1 OPTIONS
|
|
|
|
=over 8
|
|
|
|
=item B<--help>
|
|
Show help information.
|
|
|
|
=item B<--hostname>
|
|
Specify the hostname to delete.
|
|
|
|
=item B<--manual>
|
|
Read the manual for this script.
|
|
|
|
=item B<--version>
|
|
Show the version number and exit.
|
|
|
|
|
|
=back
|
|
|
|
=cut
|
|
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
xen-create-nfs is a simple script which allows you to easily create
|
|
a single configuration file for a Xen guest which will mount its remote
|
|
filesystem over an NFS root.
|
|
|
|
It doesn't create any images to use for local storage, and it doesn't
|
|
support more than the minimal number of options to completement the
|
|
existing xen-create-image script, however it is hopefully useful.
|
|
|
|
=cut
|
|
|
|
|
|
=head1 REFERENCE
|
|
|
|
For more details on what you'll need to support NFS-root Xen guests
|
|
the following article, written by the author, might be useful:
|
|
|
|
http://www.debian-administration.org/articles/505
|
|
|
|
=cut
|
|
|
|
|
|
=head1 AUTHOR
|
|
|
|
Steve
|
|
--
|
|
http://www.steve.org.uk/
|
|
|
|
$Id: xen-create-nfs,v 1.6 2007-03-20 20:49:58 steve Exp $
|
|
|
|
=cut
|
|
|
|
|
|
=head1 LICENSE
|
|
|
|
Copyright (c) 2005-2007 by Steve Kemp. All rights reserved.
|
|
|
|
This module is free software;
|
|
you can redistribute it and/or modify it under
|
|
the same terms as Perl itself.
|
|
The LICENSE file contains the full text of the license.
|
|
|
|
|
|
=cut
|
|
|
|
|
|
use strict;
|
|
use English;
|
|
use Env;
|
|
use Getopt::Long;
|
|
use Pod::Usage;
|
|
use Text::Template;
|
|
|
|
|
|
|
|
#
|
|
# Configuration values read from the command line.
|
|
#
|
|
# We do not need to read any configuration file.
|
|
#
|
|
my %CONFIG;
|
|
|
|
#
|
|
# Default options
|
|
#
|
|
$CONFIG{'template'} = '/etc/xen-tools/xm-nfs.tmpl';
|
|
|
|
|
|
#
|
|
# Release number.
|
|
#
|
|
my $RELEASE = '3.2';
|
|
|
|
|
|
# store version number away.
|
|
$CONFIG{'xen_tools_version'} = $RELEASE;
|
|
|
|
|
|
#
|
|
# Read the global configuration file.
|
|
#
|
|
readConfigurationFile( "/etc/xen-tools/xen-tools.conf" );
|
|
|
|
|
|
#
|
|
# Parse the command line arguments.
|
|
#
|
|
parseCommandLineArguments();
|
|
|
|
|
|
#
|
|
# Validate our arguments.
|
|
#
|
|
testArguments();
|
|
|
|
|
|
#
|
|
# Create the image.
|
|
#
|
|
if ( -e "/etc/xen/$CONFIG{'hostname'}.cfg" )
|
|
{
|
|
die "Configuration file for $CONFIG{'hostname'} already exists"
|
|
unless( $CONFIG{'force'} );
|
|
}
|
|
|
|
#
|
|
# If we've been given any administrators then set them up.
|
|
#
|
|
if ( $CONFIG{'admins'} )
|
|
{
|
|
setupAdminUsers();
|
|
}
|
|
|
|
#
|
|
# Now create the NFS configuration file.
|
|
#
|
|
createNewConfigurationFile();
|
|
|
|
|
|
|
|
#
|
|
# All done.
|
|
#
|
|
exit;
|
|
|
|
|
|
|
|
=begin doc
|
|
|
|
Read the specified configuration file, and update our global configuration
|
|
hash with the values found in it.
|
|
|
|
=end doc
|
|
|
|
=cut
|
|
|
|
sub readConfigurationFile
|
|
{
|
|
my ($file) = ( @_ );
|
|
|
|
# Don't read the file if it doesn't exist.
|
|
return if ( ! -e $file );
|
|
|
|
|
|
my $line = "";
|
|
|
|
open( FILE, "<", $file ) or die "Cannot read file '$file' - $!";
|
|
|
|
while (defined($line = <FILE>) )
|
|
{
|
|
chomp $line;
|
|
if ($line =~ s/\\$//)
|
|
{
|
|
$line .= <FILE>;
|
|
redo unless eof(FILE);
|
|
}
|
|
|
|
# Skip lines beginning with comments
|
|
next if ( $line =~ /^([ \t]*)\#/ );
|
|
|
|
# Skip blank lines
|
|
next if ( length( $line ) < 1 );
|
|
|
|
# Strip trailing comments.
|
|
if ( $line =~ /(.*)\#(.*)/ )
|
|
{
|
|
$line = $1;
|
|
}
|
|
|
|
# Find variable settings
|
|
if ( $line =~ /([^=]+)=([^\n]+)/ )
|
|
{
|
|
my $key = $1;
|
|
my $val = $2;
|
|
|
|
# Strip leading and trailing whitespace.
|
|
$key =~ s/^\s+//;
|
|
$key =~ s/\s+$//;
|
|
$val =~ s/^\s+//;
|
|
$val =~ s/\s+$//;
|
|
|
|
# Store value.
|
|
$CONFIG{ $key } = $val;
|
|
}
|
|
}
|
|
|
|
close( FILE );
|
|
}
|
|
|
|
|
|
|
|
=begin doc
|
|
|
|
Parse the command line arguments this script was given.
|
|
|
|
=end doc
|
|
|
|
=cut
|
|
|
|
sub parseCommandLineArguments
|
|
{
|
|
my $HELP = 0;
|
|
my $MANUAL = 0;
|
|
my $VERSION = 0;
|
|
|
|
|
|
#
|
|
# Parse options.
|
|
#
|
|
GetOptions(
|
|
|
|
# Networking options
|
|
"dhcp", \$CONFIG{'dhcp'},
|
|
"gateway=s", \$CONFIG{'gateway'},
|
|
"broadcast=s", \$CONFIG{'broadcast'},
|
|
"ip=s", \$CONFIG{'ip'},
|
|
"netmask=s", \$CONFIG{'netmask'},
|
|
"hostname=s", \$CONFIG{'hostname'},
|
|
"memory=s", \$CONFIG{'memory'},
|
|
"mac=s", \$CONFIG{'mac'},
|
|
|
|
# NFS options.
|
|
"nfs_server=s", \$CONFIG{'nfs_server'},
|
|
"nfs_root=s", \$CONFIG{'nfs_root'},
|
|
|
|
# Misc. options
|
|
"admins=s", \$CONFIG{'admins'},
|
|
"kernel=s", \$CONFIG{'kernel'},
|
|
"initrd=s", \$CONFIG{'initrd'},
|
|
"force", \$CONFIG{'force'},
|
|
"template=s", \$CONFIG{'template'},
|
|
|
|
# Help options
|
|
"help", \$HELP,
|
|
"manual", \$MANUAL,
|
|
"verbose", \$CONFIG{'verbose'},
|
|
"version", \$VERSION
|
|
|
|
);
|
|
|
|
pod2usage(1) if $HELP;
|
|
pod2usage(-verbose => 2 ) if $MANUAL;
|
|
|
|
|
|
if ( $VERSION )
|
|
{
|
|
my $REVISION = '$Revision: 1.6 $';
|
|
if ( $REVISION =~ /1.([0-9.]+) / )
|
|
{
|
|
$REVISION = $1;
|
|
}
|
|
|
|
logprint( "xen-create-nfs release $RELEASE - CVS: $REVISION\n" );
|
|
exit;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
=begin doc
|
|
|
|
Test that our arguments make sense.
|
|
|
|
=end doc
|
|
|
|
=cut
|
|
|
|
sub testArguments
|
|
{
|
|
#
|
|
# Hostname is mandatory
|
|
#
|
|
die "No hostname" unless( $CONFIG{'hostname'} );
|
|
|
|
my @network = qw/ ip gateway netmask /;
|
|
|
|
#
|
|
# If DHCP then all the other options aren't needed
|
|
#
|
|
if ( $CONFIG{'dhcp'} )
|
|
{
|
|
foreach my $f ( @network )
|
|
{
|
|
delete( $CONFIG{ $f } );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
foreach my $f ( @network )
|
|
{
|
|
die "Missing --$f" unless( $CONFIG{$f} );
|
|
}
|
|
}
|
|
|
|
#
|
|
# We need an NFS server + root
|
|
#
|
|
die "Missing NFS server." unless( $CONFIG{'nfs_server'} );
|
|
die "Missing NFS root." unless( $CONFIG{'nfs_root'} );
|
|
|
|
|
|
# All OK.
|
|
}
|
|
|
|
|
|
|
|
|
|
=begin doc
|
|
|
|
This routine is designed to ensure that any users specified with
|
|
the --admins flag are setup as administrators of the new instance.
|
|
|
|
=end doc
|
|
|
|
=cut
|
|
|
|
sub setupAdminUsers
|
|
{
|
|
#
|
|
# If we're not root we can't modify users.
|
|
#
|
|
return if ( $EFFECTIVE_USER_ID != 0 );
|
|
|
|
#
|
|
# If we don't have a sudoers file then we'll also ignore this.
|
|
#
|
|
return if ( ! -e "/etc/sudoers" );
|
|
|
|
#
|
|
# Find the path to the xen-login-shell
|
|
#
|
|
my $shell = undef;
|
|
$shell = "/usr/bin/xen-login-shell" if ( -x "/usr/bin/xen-login-shell" );
|
|
$shell = "/usr/local/bin/xen-login-shell" if ( -x "/usr/bin/local/xen-login-shell" );
|
|
|
|
return if ( !defined( $shell ) );
|
|
|
|
|
|
#
|
|
# For each user make sure they exist, and setup the
|
|
# login shell for them.
|
|
#
|
|
foreach my $user ( split( /,/, $ENV{'admins'} ) )
|
|
{
|
|
# Strip leading and trailing whitespace.
|
|
$user =~ s/^\s+//;
|
|
$user =~ s/\s+$//;
|
|
|
|
# Ignore root
|
|
next if ( $user =~ /^root$/i );
|
|
|
|
# Does the user exist?
|
|
if ( getpwnam($user) )
|
|
{
|
|
# Change shell.
|
|
$CONFIG{'verbose'} && print "Changing shell for $user: $shell\n";
|
|
system( "chsh", "-s", $shell, $user );
|
|
}
|
|
else
|
|
{
|
|
# Add a new user.
|
|
$CONFIG{'verbose'} && print "Adding new user: $user\n";
|
|
system( "useradd", "-s", $shell, $user );
|
|
}
|
|
|
|
#
|
|
# Add the entry to /etc/sudoers.
|
|
#
|
|
open( SUDOERS, ">>", "/etc/sudoers" ) or warn "Failed to add user to sudoers file : $user - $!";
|
|
print SUDOERS "$user ALL = NOPASSWD: /usr/sbin/xm, /usr/bin/xen-create-image\n";
|
|
close( SUDOERS );
|
|
|
|
}
|
|
}
|
|
|
|
|
|
=begin doc
|
|
|
|
Create the Xen configuration file for our new Xen guest.
|
|
|
|
=end doc
|
|
|
|
=cut
|
|
|
|
sub createNewConfigurationFile
|
|
{
|
|
die "Template file missing: $CONFIG{'template'}" unless( -e $CONFIG{'template'} );
|
|
|
|
#
|
|
# Load the template.
|
|
#
|
|
my $template = new Text::Template( TYPE => 'FILE',
|
|
SOURCE => $CONFIG{'template'} );
|
|
|
|
my $result = $template->fill_in( HASH => \%CONFIG );
|
|
|
|
#
|
|
# The file we'll write to.
|
|
#
|
|
my $file = "/etc/xen/$CONFIG{'hostname'}.cfg";
|
|
|
|
#
|
|
# Output the configuration file.
|
|
#
|
|
open( FILE, ">", $file ) or die "Failed to write to $file - $!";
|
|
print FILE $result;
|
|
close( FILE );
|
|
}
|