Document the fact that we are now using pure Semantic Versioning including trailing zeros. Also update debian/changelog and NEWS.markdown for previous pull request. Also remove erroneously added eol tag for Ubuntu Jammy again as it is an LTS release.
440 lines
9.3 KiB
Perl
Executable File
440 lines
9.3 KiB
Perl
Executable File
#!/usr/bin/perl -w
|
|
|
|
=encoding utf8
|
|
|
|
=head1 NAME
|
|
|
|
xen-update-image - Update the software installed upon offline Xen images.
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
xen-update-image [options] imageName1 imageName2 .. imageNameN
|
|
|
|
Help Options:
|
|
--help Show this scripts help information.
|
|
--manual Read this scripts manual.
|
|
--version Show the version number and exit.
|
|
|
|
General Options:
|
|
--dir Specify the directory which contains the image(s).
|
|
--lvm Specify the LVM volume group which contains the image(s).
|
|
--evms Specify the EVMS container which contains the image(s).
|
|
|
|
|
|
=head1 OPTIONS
|
|
|
|
=over 8
|
|
|
|
=item B<--dir>
|
|
Specify the directory which contains the image(s).
|
|
|
|
=item B<--evms>
|
|
Specify the EVMS container which contains the image(s).
|
|
|
|
=item B<--help>
|
|
Show the script help.
|
|
|
|
=item B<--lvm>
|
|
Specify the LVM volume group which contains the image(s).
|
|
|
|
=item B<--manual>
|
|
Read the manual.
|
|
|
|
=item B<--version>
|
|
Show the version number and exit.
|
|
|
|
=back
|
|
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
xen-update-image is a simple script which allows you to update
|
|
a Xen image of Debian which has been created with xen-create-image.
|
|
|
|
It does this by mounting the image inside a temporary directory
|
|
then running:
|
|
|
|
apt-get update
|
|
|
|
apt-get upgrade
|
|
|
|
NOTE If the image is already running within Xen this will cause
|
|
corruption otherwise it will allow you to update your image without
|
|
booting it.
|
|
|
|
|
|
=head1 EXAMPLES
|
|
|
|
The following assumes there are two images which are not currently
|
|
running. The images are called 'test.my.flat', and 'x11.my.flat'.
|
|
|
|
Updating both images can be accomplished by executing:
|
|
|
|
xen-update-images --dir=/home/xen test.my.flat x11.my.flat
|
|
|
|
|
|
=head1 AUTHORS
|
|
|
|
Steve Kemp, https://steve.fi/
|
|
Axel Beckert, https://axel.beckert.ch/
|
|
Stéphane Jourdois
|
|
|
|
|
|
=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 File::Temp qw/ tempdir /;
|
|
use File::Copy qw/ mv cp /;
|
|
use Getopt::Long;
|
|
use Pod::Usage;
|
|
use Xen::Tools::Common;
|
|
|
|
|
|
#
|
|
# Configuration options, initially read from the configuration file
|
|
# but may be overridden by the command line.
|
|
#
|
|
# Command line flags *always* take precedence over the configuration file.
|
|
#
|
|
my %CONFIG;
|
|
|
|
#
|
|
# Release number.
|
|
#
|
|
my $RELEASE = '4.10.0';
|
|
|
|
|
|
#
|
|
# Find xen toolstack command
|
|
#
|
|
$CONFIG{ 'xm' } = findXenToolstack();
|
|
|
|
|
|
#
|
|
# Read configuration file if it exists.
|
|
#
|
|
if ( -e "/etc/xen-tools/xen-tools.conf" )
|
|
{
|
|
readConfigurationFile("/etc/xen-tools/xen-tools.conf", \%CONFIG);
|
|
}
|
|
|
|
|
|
#
|
|
# Parse command line arguments, these override the values from the
|
|
# configuration file.
|
|
#
|
|
parseCommandLineArguments();
|
|
|
|
|
|
#
|
|
# Test that our arguments are sane.
|
|
#
|
|
checkArguments();
|
|
|
|
|
|
#
|
|
# Abort if non-root user.
|
|
#
|
|
if ( $EFFECTIVE_USER_ID != 0 )
|
|
{
|
|
print <<EOROOT;
|
|
|
|
This script is not running with root privileges.
|
|
|
|
root privileges are required to successfully mount the disk image(s).
|
|
|
|
EOROOT
|
|
|
|
exit;
|
|
}
|
|
|
|
|
|
|
|
#
|
|
# Loop over the supplied arguments, and attempt to update each image.
|
|
#
|
|
while ( my $name = shift )
|
|
{
|
|
if ( !xenRunning($name, \%CONFIG) )
|
|
{
|
|
updateXenImage($name);
|
|
}
|
|
else
|
|
{
|
|
print "Skipping xen guest '$name' - it appears to be running.\n";
|
|
}
|
|
}
|
|
|
|
|
|
#
|
|
# All done.
|
|
#
|
|
exit;
|
|
|
|
|
|
|
|
=begin doc
|
|
|
|
Mount the primary disk image, so that we're ready to update it.
|
|
|
|
=end doc
|
|
|
|
=cut
|
|
|
|
sub updateXenImage
|
|
{
|
|
my ($name) = (@_);
|
|
|
|
#
|
|
# Create a temporary directory, and prepare to mount the
|
|
# image there.
|
|
#
|
|
my $tmp = tempdir( CLEANUP => 1 );
|
|
my $img = '';
|
|
my $mount_cmd = '';
|
|
|
|
#
|
|
# If we're dealing with loopback images find the main one,
|
|
# and mount it.
|
|
#
|
|
if ( $CONFIG{ 'dir' } )
|
|
{
|
|
|
|
# The loopback image.
|
|
$img = $CONFIG{ 'dir' } . "/domains/" . $name . "/disk.img";
|
|
|
|
if ( !-e $img )
|
|
{
|
|
print "Disk image '$img' for host '$name' not found\n";
|
|
return;
|
|
}
|
|
|
|
$mount_cmd = "mount -t auto -o loop $img $tmp";
|
|
}
|
|
elsif ( $CONFIG{ 'lvm' } )
|
|
{
|
|
|
|
# The LVM volume
|
|
$img = "/dev/" . $CONFIG{ 'lvm' } . "/$name-disk";
|
|
|
|
# make sure it exists.
|
|
if ( !-e $img )
|
|
{
|
|
print "Logical volume '$img' for host '$name' not found\n";
|
|
return;
|
|
}
|
|
|
|
$mount_cmd = "mount -t auto $img $tmp";
|
|
}
|
|
elsif ( $CONFIG{ 'evms' } )
|
|
{
|
|
|
|
# The EVMS volume -- note, unlike LVM, you don't need the
|
|
# $CONFIG{'evms'} to see it and mount the
|
|
# volume. $CONFIG{'evms'} is only used for manipulating the
|
|
# underlying object. Still, I don't want to mess with the
|
|
# parse code and make it confusing - otherwise --evms takes an
|
|
# argument everywhere but here, which will confuse users. The
|
|
# better solution is to make it so that --evms can take a
|
|
# following container, but doesn't require it. For the
|
|
# moment, it is better to leave it as it is, take a container,
|
|
# and then ignore it.
|
|
|
|
# The best way to do it is to just read it out of the
|
|
# configuration file, tell the user what you got and where you
|
|
# got it from, and not bother the user with picking --dir or
|
|
# --lvm or --evms at all, but infer it from the config file's
|
|
# disk = parameter. xen-delete-image might work the same way,
|
|
# but it could be *slightly* more dangerous in the context of
|
|
# deleting.
|
|
$img = "/dev/evms/$name-disk";
|
|
|
|
# make sure it exists.
|
|
if ( !-e $img )
|
|
{
|
|
print "EVMS volume '$img' for host '$name' not found\n";
|
|
return;
|
|
}
|
|
|
|
$mount_cmd = "mount -t auto $img $tmp";
|
|
}
|
|
else
|
|
{
|
|
die "Can't happen?\n";
|
|
}
|
|
|
|
#
|
|
# Mount the image.
|
|
#
|
|
`$mount_cmd`;
|
|
|
|
#
|
|
# Make sure this is a Debian image.
|
|
#
|
|
if ( ( -e $tmp . "/usr/bin/apt-get" ) &&
|
|
( -x $tmp . "/usr/bin/apt-get" ) )
|
|
{
|
|
#
|
|
# Copy dom0's resolv.conf to domU
|
|
#
|
|
mv("$tmp/etc/resolv.conf", "$tmp/etc/resolv.conf.old") if -f "$tmp/etc/resolv.conf";
|
|
cp("/etc/resolv.conf", "$tmp/etc/resolv.conf");
|
|
|
|
#
|
|
# Now run the update command.
|
|
#
|
|
system("chroot $tmp /usr/bin/apt-get update");
|
|
|
|
|
|
#
|
|
# Now upgrade
|
|
#
|
|
system(
|
|
"DEBIAN_FRONTEND=noninteractive chroot $tmp /usr/bin/apt-get upgrade --yes"
|
|
);
|
|
|
|
#
|
|
# Restore domU's resolv.conf if needed
|
|
#
|
|
if (-f "$tmp/etc/resolv.conf") {
|
|
mv("$tmp/etc/resolv.conf.old", "$tmp/etc/resolv.conf");
|
|
} else {
|
|
unlink "$tmp/etc/resolv.conf";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
print "Xen image $name is not a Debian GNU/Linux image. Skipping\n";
|
|
}
|
|
|
|
|
|
#
|
|
# Unmount
|
|
#
|
|
`umount -l $tmp`;
|
|
`umount $tmp 2>/dev/null >/dev/null`;
|
|
|
|
}
|
|
|
|
|
|
|
|
=begin doc
|
|
|
|
Parse the arguments specified upon the command line.
|
|
|
|
=end doc
|
|
|
|
=cut
|
|
|
|
sub parseCommandLineArguments
|
|
{
|
|
my $HELP = 0;
|
|
my $MANUAL = 0;
|
|
my $VERSION = 0;
|
|
|
|
#
|
|
# We record the installation method here because we want
|
|
# to ensure that we allow the method supplied upon the command line
|
|
# to overwrite the one we might have ready read from the configuration
|
|
# file.
|
|
#
|
|
my %install;
|
|
$install{ 'evms' } = undef;
|
|
$install{ 'dir' } = undef;
|
|
$install{ 'lvm' } = undef;
|
|
|
|
# Parse options.
|
|
#
|
|
GetOptions( "dir=s", \$install{ 'dir' },
|
|
"lvm=s", \$install{ 'lvm' },
|
|
"evms=s", \$install{ 'evms' },
|
|
"help", \$HELP,
|
|
"manual", \$MANUAL,
|
|
"version", \$VERSION );
|
|
|
|
#
|
|
# Now make ensure that the command line setting of '--lvm', '--evms', '--zpool'
|
|
# and '--dir=x' override anything specified in the configuration file.
|
|
#
|
|
if ( $install{ 'dir' } )
|
|
{
|
|
$CONFIG{ 'dir' } = $install{ 'dir' };
|
|
$CONFIG{ 'evms' } = undef;
|
|
$CONFIG{ 'lvm' } = undef;
|
|
$CONFIG{ 'zpool' } = undef;
|
|
}
|
|
if ( $install{ 'evms' } )
|
|
{
|
|
$CONFIG{ 'dir' } = undef;
|
|
$CONFIG{ 'evms' } = $install{ 'evms' };
|
|
$CONFIG{ 'lvm' } = undef;
|
|
$CONFIG{ 'zpool' } = undef;
|
|
}
|
|
if ( $install{ 'lvm' } )
|
|
{
|
|
$CONFIG{ 'dir' } = undef;
|
|
$CONFIG{ 'evms' } = undef;
|
|
$CONFIG{ 'lvm' } = $install{ 'lvm' };
|
|
$CONFIG{ 'zpool' } = undef;
|
|
}
|
|
|
|
pod2usage(1) if $HELP;
|
|
pod2usage( -verbose => 2 ) if $MANUAL;
|
|
|
|
if ($VERSION)
|
|
{
|
|
print "xen-update-image release $RELEASE\n";
|
|
exit;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
=begin doc
|
|
|
|
Test that the options we received from the command line, or our
|
|
configuration file, make sense.
|
|
|
|
=end doc
|
|
|
|
=cut
|
|
|
|
sub checkArguments
|
|
{
|
|
|
|
#
|
|
# Make sure we got one and only one installation method.
|
|
#
|
|
my $count = 0;
|
|
foreach my $type (qw/dir lvm evms/)
|
|
{
|
|
$count += 1 if defined( $CONFIG{ $type } );
|
|
}
|
|
|
|
#
|
|
# Show a decent error for when either zero or more than one options
|
|
# were selected.
|
|
#
|
|
if ( $count != 1 )
|
|
{
|
|
print "Please select one and only one of the installation methods:\n";
|
|
print " --dir\n";
|
|
print " --evms\n";
|
|
print " --lvm\n";
|
|
exit;
|
|
}
|
|
}
|