1
0
mirror of synced 2026-01-11 23:42:56 +00:00
xen-tools.xen-tools/bin/xen-resize-guest
2021-10-24 02:23:35 +02:00

448 lines
8.1 KiB
Perl
Executable File

#!/usr/bin/perl -w
=encoding utf8
=head1 NAME
xen-resize-guest - Resize a loopback or LVM based xen guest.
=head1 SYNOPSIS
xen-resize-guest [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.
General Options:
--add Specify the amount of space to add, e.g. --add=1gb
--dir Specify the path to the loopback image root.
--force Force the resize to happen without a last-chance delay.
--hostname Specify the hostname of the guest to resize.
=head1 OPTIONS
=over 8
=item B<--add>
Specify the amount of storage to add to the primary disk.
=item B<--dir>
Specify the directory where the loopback files are based.
=item B<--force>
Don't pause for 10 seconds prior to commencing.
=item B<--help>
Show help information.
=item B<--hostname>
Specify the hostname to delete.
=item B<--lvm>
Specify the volume group to use.
=item B<--manual>
Read the manual for this script.
=item B<--version>
Show the version number and exit.
=back
=head1 DESCRIPTION
This tool will ease the resizing of Xen guests, whether they are based
upon loopback files or LVM partitions.
Whilst the process of resizing a guest is pretty simple it can be fiddly
to do the steps correctly in the right order:
1. Shutdown the guest.
2. Unmount the volume, if it is mounted.
3. Add to the space.
4. Check the filesystem.
5. Resize the filesystem.
6. Restart the guest.
More than once I've heard of users making mistakes and breaking their
filesystems; hence this tool.
=head1 AUTHORS
Steve Kemp, https://steve.fi/
Axel Beckert, https://axel.beckert.ch/
=head1 LICENSE
Copyright (c) 2005-2009 by Steve Kemp, (c) 2010 by The Xen-Tools
Development Team. 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;
use Xen::Tools::Common;
#
# Configuration values read from the command line, or configuration file.
#
my %CONFIG;
#
# Release number.
#
my $RELEASE = '4.9.1';
#
# Find xen toolstack command
#
$CONFIG{ 'xm' } = findXenToolstack();
#
# Read the global configuration file.
#
readConfigurationFile("/etc/xen-tools/xen-tools.conf", \%CONFIG);
#
# Parse the command line arguments.
#
parseCommandLineArguments();
#
# Validate our arguments.
#
testArguments();
#
# The path to the file, or device, to resize.
#
my $path = undef;
if ( $CONFIG{ 'dir' } )
{
#
# Make sure we can find the disk
#
$path =
$CONFIG{ 'dir' } . "/domains/" . $CONFIG{ 'hostname' } . "/disk.img";
if ( !-e $path )
{
print <<EOF;
The disk image for the guest domain $CONFIG{'hostname'} was not found
where we expected it to be:
$path
Please check and try again, or report this as a bug.
EOF
exit 1;
}
#
# Ensure the file is an ext3 filesystem.
#
my $type = `file $path`;
if ( $type !~ /ext3/ )
{
print "Filesystem type is not understood.\n";
print "We only handle ext3 right now!\n";
print "Aborting\n";
exit 1;
}
#
# OK we have the size, we have the image.
#
# Resize with DD
#
print "Preparing to resize image: $path\n";
#
# Allow panic
#
if ( !$CONFIG{ 'force' } )
{
foreach my $i ( 1 .. 10 )
{
my $delay = 10 - $i;
print "Sleeping for $delay seconds to allow cancel\n";
sleep 1;
}
}
print "DO NOT INTERRUPT\n";
my $cmd = "dd if=/dev/zero bs=1M count=$CONFIG{'add'}k >> $path";
system($cmd );
}
elsif ( $CONFIG{ 'lvm' } )
{
#
# Make sure we can find the disk
#
$path = "/dev/" . $CONFIG{ 'lvm' } . "/" . $CONFIG{ 'hostname' } . "-disk";
if ( !-e $path )
{
print <<EOF;
The disk image for the guest domain $CONFIG{'hostname'} was not found
where we expected it to be:
$path
Please check and try again, or report this as a bug.
EOF
exit 1;
}
#
# Ensure the file is an ext3 filesystem.
#
my $type = `head $path | file -`;
if ( $type !~ /ext3/ )
{
print "Filesystem type is not understood.\n";
print "We only handle ext3 right now!\n";
print "Aborting\n";
exit 1;
}
#
# OK we have the size, we have the image.
#
# Resize with DD
#
print "Preparing to resize image: $path\n";
#
# Allow panic
#
if ( !$CONFIG{ 'force' } )
{
foreach my $i ( 1 .. 10 )
{
my $delay = 10 - $i;
print "Sleeping for $delay seconds to allow cancel\n";
sleep 1;
}
}
print "DO NOT INTERRUPT\n";
my $cmd = "lvextend -L+$CONFIG{'add'}M $path";
system($cmd );
}
else
{
print "Unknown storage type. (Neither LVM nor loopback.)\n";
exit 1;
}
#
# Check filesystem.
#
print "Checking filesystem\n";
system("fsck.ext3 -f $path");
#
# Run ext3resize.
#
print "Resizing in place\n";
system("resize2fs $path");
#
# Job done.
#
print "All done\n";
exit 0;
=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;
#
# Local variables.
#
my %install;
#
# Parse options.
#
GetOptions(
# Misc. options
"add=s", \$CONFIG{ 'add' },
"dir=s", \$install{ 'dir' },
"lvm=s", \$install{ 'lvm' },
"hostname=s", \$CONFIG{ 'hostname' },
"force", \$CONFIG{ 'force' },
# Help options
"help", \$HELP,
"manual", \$MANUAL,
"verbose", \$CONFIG{ 'verbose' },
"version", \$VERSION
);
pod2usage(1) if $HELP;
pod2usage( -verbose => 2 ) if $MANUAL;
if ($VERSION)
{
print("xen-resize-guest release $RELEASE\n");
exit 1;
}
#
# Setup mutually exclusive options in such a way that
# they will allow the configuration values to be overridden by
# the command line.
#
if ( $install{ 'lvm' } )
{
$CONFIG{ 'lvm' } = $install{ 'lvm' };
$CONFIG{ 'dir' } = undef;
delete $CONFIG{ 'dir' };
}
if ( $install{ 'dir' } )
{
$CONFIG{ 'dir' } = $install{ 'dir' };
$CONFIG{ 'lvm' } = undef;
delete $CONFIG{ 'lvm' };
}
}
=begin doc
Test our arguments are complete.
=end doc
=cut
sub testArguments
{
#
# Make sure we received a hostname.
#
if ( !$CONFIG{ 'hostname' } )
{
print <<EOF;
A hostname is mandatory!
Please specify one with --hostname=some.host.name
EOF
exit 1;
}
#
# Make sure we received a size.
#
if ( !$CONFIG{ 'add' } )
{
print <<EOF;
Please specify a size to increase the guest by:
--add=1Gb -> Increase the size of the disk image by 1Gb.
--add=1 -> Increase the size of the disk image by 1Mb.
EOF
exit 1;
}
#
# Make sure the guest isn't running
#
if ( xenRunning( $CONFIG{ 'hostname' }, \%CONFIG ) )
{
print "The guest $CONFIG{'hostname'} appears to be running!\n";
exit 1;
}
#
# We should either have LVM *or* directory - not neither or both.
#
my $options = 0;
$options += 1
if ( defined( $CONFIG{ 'lvm' } ) && length( $CONFIG{ 'lvm' } ) );
$options += 1
if ( defined( $CONFIG{ 'dir' } ) && length( $CONFIG{ 'dir' } ) );
#
# Report
#
if ( $options == 0 )
{
print "Please specify one of --lvm or --dir\n";
exit 1;
}
if ( $options > 1 )
{
print "Please specify only one of --lvm or --dir - not both!\n";
exit 1;
}
#
# Convert from Gb -> Mb;
#
if ( $CONFIG{ 'add' } =~ /^([0-9.]+)Gb*$/i )
{
$CONFIG{ 'add' } = $1 * 1024;
}
if ( $CONFIG{ 'add' } =~ /^([0-9.]+)Mb*$/i )
{
$CONFIG{ 'add' } = $1;
}
}