Commit c159032d authored by Leigh B Stoller's avatar Leigh B Stoller

Couple of utility scripts to capture and restore XEN vms so that we

can move them elsewhere.

	capturevm.pl pcvmxxx-yy boss

will create a directory called boss and take imagezips of all the lvms
into that directory. A slightly modified xen config is written to the
directory. The XEN VM should not be running of course, and the easiest
way to stop it (without losing the disks) is:

	/usr/local/etc/emulab/vnodesetup -jh pcvmxxx-yy

Copy the directory someplace, and then run:

	restorevm.pl boss /path/to/above/stuff

which create new LVMs and then imageunzip the contents into them. A
slightly modified xen config file is then written to /var/tmp, which
can started with "xm create /var/tmp/boss.conf".

No rocket science here, but this was the easiest way to get all the
disks we create for XEN elabinelab, and since they can pretty big, we
want to use imagezip.
parent 2485b44d
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2011 University of Utah and the Flux Group.
# Copyright (c) 2000-2012 University of Utah and the Flux Group.
# All rights reserved.
#
......@@ -285,6 +285,8 @@ xen-install: dir-install
$(INSTALL) -m 755 $(SRCDIR)/vnodectl $(BINDIR)/
echo "xen" > $(ETCDIR)/genvmtype
$(INSTALL) -m 755 $(SRCDIR)/mkvnode.pl $(BINDIR)/mkvnode.pl
$(INSTALL) -m 755 $(SRCDIR)/restorevm.pl $(BINDIR)/restorevm.pl
$(INSTALL) -m 755 $(SRCDIR)/capturevm.pl $(BINDIR)/capturevm.pl
$(INSTALL) -m 755 $(SRCDIR)/xen/xend-config.sxp $(SYSETCDIR)/xen/
$(INSTALL) -m 755 xen/emulab-cnet $(SYSETCDIR)/xen/scripts/
......
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2009-2012 University of Utah and the Flux Group.
# All rights reserved.
#
use strict;
use Getopt::Std;
use English;
use Errno;
use Data::Dumper;
sub usage()
{
print "Usage: capturevm.pl [-d] vnodeid [role]\n" .
" -d Debug mode.\n".
" -i Info mode only\n";
exit(-1);
}
my $optlist = "di";
my $debug = 1;
my $infomode = 0;
my $VMPATH = "/var/emulab/vms/vminfo";
my $EXTRAFS = "/extrafs";
my $VGNAME = "xen-vg";
my $role;
#
# Turn off line buffering on output
#
$| = 1;
# Locals
my %xminfo = ();
# Protos
sub Fatal($);
sub CreateExtraFS();
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"d"})) {
$debug = 1;
}
if (defined($options{"i"})) {
$infomode = 1;
}
usage()
if (@ARGV < 1 || @ARGV > 2);
my $vnodeid = $ARGV[0];
$role = $ARGV[1] if (@ARGV == 2);
my $XMINFO = "$VMPATH/$vnodeid/xm.conf";
CreateExtraFS();
system("mkdir $EXTRAFS/$role")
if (defined($role) && ! -e "$EXTRAFS/$role");
#
# We need this file to figure out the disk info.
#
if (! -e "$XMINFO") {
Fatal("$XMINFO does not exist");
}
open(XM, $XMINFO)
or Fatal("Could not open $XMINFO: $!");
while (<XM>) {
if ($_ =~ /^([-\w]*)\s*=\s*(.*)$/) {
my $key = $1;
my $val = $2;
if ($val =~ /^'(.*)'$/) {
$val = $1;
}
$xminfo{$key} = "$val";
}
elsif ($_ =~ /^([-\w]*)\s*[\+\=]+\s*(.*)$/) {
my $key = $1;
my $val = $2;
if ($val =~ /^'(.*)'$/) {
$val = $1;
}
$xminfo{$key} .= $val;
}
}
close(XM);
# Filled in later.
$xminfo{"disksizes"} = "";
#
# Parse the disk info.
#
if (!exists($xminfo{'disk'})) {
Fatal("No disk info in config file!");
}
my $disklist = eval $xminfo{'disk'};
my %diskinfo = ();
foreach my $disk (@$disklist) {
if ($disk =~ /^phy:([^,]*)/) {
if (! -e $1) {
Fatal("$disk does not exist")
}
$diskinfo{$1} = {"spec" => $disk};
}
else {
Fatal("Cannot parse disk: $disk");
}
}
foreach my $device (keys(%diskinfo)) {
my $spec = $diskinfo{$device}->{"spec"};
my $dev;
my $filename;
if ($spec =~ /,(sd\w+),/) {
$dev = $1;
}
else {
fatal("Could not parse $spec");
}
$filename = $dev;
$filename = "$role/$filename"
if (defined($role));
#
# Figure out the size of the LVM.
#
my $lv_size = `lvs -o lv_size --noheadings --units g $device`;
fatal("Could not get lvsize for $device")
if ($?);
chomp($lv_size);
$lv_size =~ s/^\s+//;
$lv_size =~ s/\s+$//;
#
# We store the size in the xminfo so we can write out a new one.
# The sizes are for building the lvms later.
#
$xminfo{"disksizes"} .= ","
if ($xminfo{"disksizes"} ne "");
$xminfo{"disksizes"} .= "$dev:$lv_size";
#
# Do not need to do anything.
#
if ($device =~ /swap/) {
next;
}
print "Working on $device.\n";
print "Size is $lv_size. Writing to $EXTRAFS/$filename\n";
#
# The root FS is a single partition image, while the aux disks
# have a real MBR in them.
#
my $opts = "";
if (! ($device =~ /disk/)) {
$opts = "-b -f";
}
if ($infomode) {
system("imagezip -i $opts $device");
}
else {
system("imagezip -o $opts $device $EXTRAFS/$filename");
}
}
#
# Write out the config file.
#
if ($infomode) {
print Dumper(\%xminfo);
}
else {
#
# Before we write it out, need to munge the vif spec since there is
# no need for the script. Use just the default.
#
$xminfo{"vif"} =~ s/,\s*script=[^\']*//g;
$XMINFO = (defined($role) ? "$EXTRAFS/$role/xm.conf" : "$EXTRAFS/xm.conf");
open(XM, ">$XMINFO")
or fatal("Could not open $XMINFO: $!");
foreach my $key (keys(%xminfo)) {
my $val = $xminfo{$key};
if ($val =~ /^\[/) {
print XM "$key = $val\n";
}
else {
print XM "$key = '$val'\n";
}
}
close(XM);
}
exit(0);
#
# Create an extra FS using an LVM.
#
sub CreateExtraFS()
{
return
if (-e $EXTRAFS);
system("mkdir $EXTRAFS") == 0
or fatal("mkdir($EXTRAFS) failed");
system("/usr/sbin/lvcreate -n extrafs -L 50G $VGNAME") == 0
or fatal("lvcreate failed");
system("mke2fs -j /dev/$VGNAME/extrafs") == 0
or fatal("mke2fs failed");
system("mount /dev/$VGNAME/extrafs $EXTRAFS") == 0
or fatal("mount failed");
}
sub Fatal($)
{
my ($msg) = @_;
die("*** $0:\n".
" $msg\n");
}
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2009-2012 University of Utah and the Flux Group.
# All rights reserved.
#
use strict;
use Getopt::Std;
use English;
use Errno;
use Data::Dumper;
sub usage()
{
print "Usage: restorevm.pl [-d] vnodeid path\n" .
" -d Debug mode.\n".
" -i Info mode only\n";
exit(-1);
}
my $optlist = "di";
my $debug = 1;
my $infomode = 0;
my $VMPATH = "/var/xen/configs";
my $VGNAME = "xen-vg";
#
# Turn off line buffering on output
#
$| = 1;
# Locals
my %xminfo = ();
# Protos
sub Fatal($);
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"d"})) {
$debug = 1;
}
if (defined($options{"i"})) {
$infomode = 1;
}
usage()
if (@ARGV != 2);
my $vnodeid = $ARGV[0];
my $path = $ARGV[1];
my $XMINFO = "$path/xm.conf";
#
# We need this file to figure out the disk info.
#
if (! -e "$XMINFO") {
Fatal("$XMINFO does not exist");
}
open(XM, $XMINFO)
or Fatal("Could not open $XMINFO: $!");
while (<XM>) {
if ($_ =~ /^([-\w]*)\s*=\s*(.*)$/) {
my $key = $1;
my $val = $2;
if ($val =~ /^'(.*)'$/) {
$val = $1;
}
$xminfo{$key} = "$val";
}
elsif ($_ =~ /^([-\w]*)\s*[\+\=]+\s*(.*)$/) {
my $key = $1;
my $val = $2;
if ($val =~ /^'(.*)'$/) {
$val = $1;
}
$xminfo{$key} .= $val;
}
}
close(XM);
#
# Parse the disk info.
#
if (!exists($xminfo{'disk'})) {
Fatal("No disk info in config file!");
}
my $disklist = eval $xminfo{'disk'};
my %diskinfo = ();
my %disksize = ();
foreach my $disk (@$disklist) {
if ($disk =~ /^phy:([^,]*)/) {
if (! -e $1) {
Fatal("$disk does not exist")
}
$diskinfo{$1} = $disk;
}
else {
Fatal("Cannot parse disk: $disk");
}
}
#
# And the size info.
#
foreach my $spec (split(',', $xminfo{'disksizes'})) {
my ($dev,$size) = split(':', $spec);
$disksize{$dev} = $size;
}
print Dumper(\%disksize);
foreach my $physinfo (keys(%diskinfo)) {
my $spec = $diskinfo{$physinfo};
my $dev;
my $filename;
if ($spec =~ /,(sd\w+),/) {
$dev = $1;
}
else {
fatal("Could not parse $spec");
}
#
# Figure out the size of the LVM.
#
my $lvmsize = $disksize{$dev};
Fatal("Could not get lvsize for $dev")
if (!defined($lvmsize));
#
# Form a new lvmname and create the LVM using the size.
#
my $lvmname = "${vnodeid}.${dev}";
my $device = "/dev/$VGNAME/$lvmname";
if (! -e $device) {
if (!$infomode) {
system("/usr/sbin/lvcreate -n $lvmname -L $lvmsize $VGNAME") == 0
or fatal("Could not create lvm for $lvmname");
}
}
# Rewrite the diskinfo path for new xm.conf
delete($diskinfo{$physinfo});
$diskinfo{$device} = "phy:$device,$dev,w";
#
# For swap, just need to mark it as a linux swap partition.
#
if ($spec =~ /swap/) {
#
# Mark it as a linux swap partition.
#
if (system("echo ',,S' | sfdisk $device -N0")) {
fatal("Could not mark $device as linux swap");
}
next;
}
$filename = "$path/$dev";
Fatal("$filename does not exist")
if (! -e $filename);
print "Working on $filename.\n";
print "Size is $lvmsize. Writing to $device\n";
#
# The root FS is a single partition image, while the aux disks
# have a real MBR in them.
#
my $opts = "-W 256";
if ($infomode) {
system("imagedump $filename");
}
else {
system("imageunzip -o $opts $filename $device");
}
}
#
# Write out the config file.
#
delete($xminfo{"disksizes"});
$xminfo{"name"} = $vnodeid;
$xminfo{"memory"} = "512";
$xminfo{"disk"} = "[" . join(",", map {"'$_'" } values(%diskinfo)) . "]";
if ($infomode) {
print Dumper(\%xminfo);
}
else {
#
# Before we write it out, need to munge the vif spec since there is
# no need for the script. Use just the default.
#
$XMINFO = "/var/tmp/${vnodeid}.conf";
print "Writing new xen config to $XMINFO\n";
open(XM, ">$XMINFO")
or fatal("Could not open $XMINFO: $!");
foreach my $key (keys(%xminfo)) {
my $val = $xminfo{$key};
if ($val =~ /^\[/) {
print XM "$key = $val\n";
}
else {
print XM "$key = '$val'\n";
}
}
close(XM);
}
exit(0);
sub Fatal($)
{
my ($msg) = @_;
die("*** $0:\n".
" $msg\n");
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment