I wrote the following script to make identical clones of a Xen virtual machine template. The script will copy the disk image and edit the necessary files of the guest operating system such as /etc/hosts, /etc/sysconfig/network and /etc/sysconfig/network-scripts/ifcfg-eth0. It will replace the hostname and will generate a new MAC address both for the guest OS ifcfg-eth0 file and the guest configuration file which is located under /etc/xen on the host.
Usage:
./xenclone <disk images dir> <disk name> <clone name>
#!/bin/bash ############################################################################ # Copyright (C) 2009 Panagiotis Kritikakos <pkritika@epcc.ed.ac.uk> # # # # This program is free software: you can redistribute it and/or modify # # it under the terms of the GNU General Public License as published by # # the Free Software Foundation, either version 3 of the License, or # # (at your option) any later version. # # # # This program is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # GNU General Public License for more details. # # # # You should have received a copy of the GNU General Public License # # along with this program. If not, see <http://www.gnu.org/licenses/>. # ############################################################################ if [ $UID != "0" ]; then echo " You must be root to run the script or run it with sudo" exit 1; fi if [ $# -lt 3 ]; then echo " Usage: ./xenclone <disk images dir> <disk name> <clone name>" echo " The script assumes the guest being clone is a Red Hat based system" exit 1; fi DISKPATH=$1 DISK=$2 CLONE=$3 MOUNTDIR=`mktemp -d` if [ ! -e $DISKPATH/$DISK.img ]; then echo " Primary disk image can't be found." exit 1; fi clear TEMPF1=`mktemp` TEMPF2=`mktemp` TEMPF3=`mktemp` TEMPHOSTS=`mktemp` TEMPNETWORK=`mktemp` TEMPIFCFG=`mktemp` echo "Copying ${DISK} to ${CLONE}..." dd if=$DISKPATH/$DISK.img of=$DISKPATH/$CLONE.img echo "Mapping the image..." loopPart=`kpartx -l $DISKPATH/$CLONE.img | awk {'print $1'}` kpartx -a $DISKPATH/$CLONE.img echo "Mounting the image..." mount /dev/mapper/$loopPart $MOUNTDIR echo "Editing files and creating configuration file for ${CLONE}..." sed "s/$DISK/$CLONE/g" < $MOUNTDIR/etc/hosts > $TEMPHOSTS cp -f $TEMPHOSTS $MOUNTDIR/etc/hosts sed "s/$DISK/$CLONE/g" < $MOUNTDIR/etc/sysconfig/network > $TEMPNETWORK cp -f $TEMPNETWORK $MOUNTDIR/etc/sysconfig/network sed "s/$DISK/$CLONE/g" < /etc/xen/$DISK > $TEMPF1 olduuid=`grep uuid $TEMPF1 | awk {'print $3'} | sed s/'"'*'"'//g` newuuid=`uuidgen` sed "s/$olduuid/$newuuid/g" < $TEMPF1 > $TEMPF2 oldmac=`grep mac $TEMPF2 | sed s/vif.*mac=//g | sed s/,.*']'//g` newmac=`echo $RANDOM | openssl md5 | sed 's/\(..\)/\1:/g' | cut -b1-17` oldhwaddr=`grep HWADDR $MOUNTDIR/etc/sysconfig/network-scripts/ifcfg-eth0 \ | sed s/HWADDR.*=//g` sed "s/$oldmac/$newmac/g" < $TEMPF2 > $TEMPF3 cp -f $TEMPF3 /etc/xen/$CLONE sed "s/$oldhwaddr/$newmac/g" < $MOUNTDIR/etc/sysconfig/network-scripts/ifcfg-eth0 \ > $TEMPIFCFG cp -f $TEMPIFCFG $MOUNTDIR/etc/sysconfig/network-scripts/ifcfg-eth0 echo "Removing temporary files..." rm -f $TEMPF1 $TEMPF2 $TEMPF3 $TEMPHOSTS $TEMPNETWORK $TEMPIFCFG echo "Unmounting the image..." umount /dev/mapper/$loopPart echo "Unmapping the image..." kpartx -d $DISKPATH/$CLONE.img echo "Cloning of ${DISK} to ${CLONE} finished."
It’s really great the fact that bash provides us with a simple way to automate mundane, repetitive and error prone processes.
Since you ‘ve gone into trouble to prepend GPL to your script, which drives me to assume that you don’t consider it a quick hack, you may want to make a few changes, for completeness, security and elegance. Few ideas to start with:
* Make sure to inform the user that you assume a certain Linux distribution family. You aren’t going to find /etc/sysconfig on a Slackware or a Debian (and many, many others).
* Check if user has the correct permissions to execute all the script included commands (man 1 id)
* Use “getopts” to get the needed options: position depended options tend to be erroneous.
* Use mktemp(1) to create temporary files.
* Whenever something goes wrong, provide an error indicating exit status (instead of the implied, everything-is-fine 0.)
* $FOO=foo; echo ${FOO}bar
Thanks for the well pointed suggestions Michael. I’ve implemented some of those and updated the script.
As you’ve pointed out, the script is not targeted for wide Linux use. The reason for that is that in the environment is being used all the guests are running Red Hat based distributions.
And yes, it’s great that there’s the ability of combining various UNIX/Linux tools to make your life easier and more.. secure 🙂
the “mount /dev/mapper/$loopPart $MOUNTDIR” does not work for me. I am on RHEL5
Hi, what’s the error you’re getting?
The problem he’s having is likely related to this:
[root@vm2 vm]# kpartx -l /vm/gen1
loop0p1 : 0 208782 /dev/loop0 63
loop0p2 : 0 2104515 /dev/loop0 208845
loop0p3 : 0 39616290 /dev/loop0 2313360
You’re assuming there’s only one line of output coming back.
That’s right. One more input parameter can be added, which will be $4 in the current version of the script, and then you’ll need something like this:
partition=$4
loopPart=`kpartx -l $DISKPATH/$CLONE.img | grep p${partition} | awk {‘print $1’}`
This assumes that you know which is the root partition…
Pingback: Preparativi per i primi test con Oracle 11gR2 « Oracle and other
Hello
I found your script useful, but I noticed a problem with the MAC address creator. It looks like this could result in multicast addresses being generated, as there is no protection from using a “1” in the last bit of the first octet.
I’m currently using this python script, which also uses the official Xen OUI – this would make it easier to indentify a virtual vs. physical machine if there was a problem on the network. I found the script on the web, but do not know the author.
#! /usr/bin/python
# macgen.py script generates a MAC address for Xen guests
#
import random
mac = [ 0x00, 0x16, 0x3e,
random.randint(0x00, 0x7f),
random.randint(0x00, 0xff),
random.randint(0x00, 0xff) ]
print ‘:’.join(map(lambda x: “%02x” % x, mac))
Thanks
-e
Here are some more comments:
You could much get better performance on the “dd” copy by specifying a larger blocksize, say “bs=1M” or something like this.
You also assume a regular file for disk, but people should probably being using a LVM volume, i.e. “/dev/VolGroup00/lvxen1”.
I also added some logic to increment the VNC display number in the guest config file (i.e. vncdisplay=xx).
Thanks for these comments.
The assumption of a regular file for a disk image was made only because that’s what I was using at the time I needed the script. Thanks again!
Please do you have script to do live cloning of running vm?
No I don’t. I think you’d need something more than a script for live cloning, probably one of the tools that supports such operations, rather than a hacky bash script.
Where did you actually acquire the recommendations to create ““Clone
Xen virtual machine script | : | : vortex of false deceit : | :” eatwellbehealthy ?
Thanks for the post ,Jenni