On 03/30/2011 06:29 PM, Serge E. Hallyn wrote: > I've replaced most of my previous use of kvm and cloud instances for bug > investigations with lxc instances. To emulate my older workflows, I've > created lxc-clone. My diff against the current natty lxc package is > attached. I've written up how I use this at s3hh.wordpress.com. Briefly, > I have a single pristine container, with LVM rootfs, for each of lucid, > maverick, and natty. When I want a container, I > > lxc-clone -o natty -n n1 -s > lxc-start -n n1 > > which takes about 5 seconds altogether. Ruin n1 however I like, and > > lxc-destroy -l -n n1 > > when done. > > It needs fleshing out, but it's at the point where it does exactly what > I need. The next thing I'm likely to add will be btrfs snapshotting, > not sure when. > > Daniel, is this something you'd consider adding? I assume that if so, > then there are changes you'd like to make to the interface :)
Hi Serge, yes, it is an interesting feature, thanks for the patch. I think more configuration tweaking will be needed but this patch looks good for me. > === modified file 'configure.ac' > --- configure.ac 2011-03-10 07:25:34 +0000 > +++ configure.ac 2011-03-30 15:36:58 +0000 > @@ -156,6 +156,7 @@ > src/lxc/lxc-setuid > src/lxc/lxc-version > src/lxc/lxc-create > + src/lxc/lxc-clone > src/lxc/lxc-destroy > > ]) > > === modified file 'lxc.spec' It should be lxc.spec.in > --- lxc.spec 2011-03-10 07:25:34 +0000 > +++ lxc.spec 2011-03-30 15:36:58 +0000 > @@ -78,6 +78,7 @@ > %{_bindir}/* > %attr(4111,root,root) %{_bindir}/lxc-attach > %attr(4111,root,root) %{_bindir}/lxc-create > +%attr(4111,root,root) %{_bindir}/lxc-clone > %attr(4111,root,root) %{_bindir}/lxc-start > %attr(4111,root,root) %{_bindir}/lxc-netstat > %attr(4111,root,root) %{_bindir}/lxc-unshare > > === modified file 'src/lxc/Makefile.am' > --- src/lxc/Makefile.am 2011-03-10 07:25:34 +0000 > +++ src/lxc/Makefile.am 2011-03-30 15:36:58 +0000 > @@ -72,6 +72,7 @@ > lxc-setuid \ > lxc-version \ > lxc-create \ > + lxc-clone \ > lxc-destroy > > bin_PROGRAMS = \ > > === modified file 'src/lxc/Makefile.in' Makefile.in is generated. I suppose it is the diff command which integrated the configure and Makefile.in in the diff result. > === added file 'src/lxc/lxc-clone.in' > --- src/lxc/lxc-clone.in 1970-01-01 00:00:00 +0000 > +++ src/lxc/lxc-clone.in 2011-03-30 15:36:58 +0000 > @@ -0,0 +1,206 @@ > +#!/bin/bash > + > +# > +# lxc: linux Container library > + > +# Authors: > +# Serge Hallyn<serge.hal...@ubuntu.com> > +# Daniel Lezcano<daniel.lezc...@free.fr> > + > +# This library is free software; you can redistribute it and/or > +# modify it under the terms of the GNU Lesser General Public > +# License as published by the Free Software Foundation; either > +# version 2.1 of the License, or (at your option) any later version. > + > +# This library 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 > +# Lesser General Public License for more details. > + > +# You should have received a copy of the GNU Lesser General Public > +# License along with this library; if not, write to the Free Software > +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > + > +usage() { > + echo "usage: lxc-clone -o<orig> -n<new> [-s] [-h] [-L fssize] [-v > vgname]" > +} > + > +help() { > + usage > + echo > + echo "creates a lxc system object." > + echo > + echo "Options:" > + echo "orig : name of the original container" > + echo "new : name of the new container" > + echo "-s : make the new rootfs a snapshot of the original" > + echo "fssize : size if creating a new fs. By default, 2G" > + echo "vgname : lvm volume group name, lxc by default" > +} > + > +shortoptions='ho:n:sL:v:' > +longoptions='help,orig:,name:,snapshot,fssize,vgname' > +lxc_path=/var/lib/lxc > +bindir=/usr/bin > +snapshot=no > +lxc_size=2G > +lxc_vg=lxc > + > +getopt=$(getopt -o $shortoptions --longoptions $longoptions -- "$@") > +if [ $? != 0 ]; then > + usage > + exit 1; > +fi > + > +eval set -- "$getopt" > + > +while true; do > + case "$1" in > + -h|--help) > + help > + exit 1 > + ;; > + -s|--snapshot) > + shift > + snapshot=yes > + ;; > + -o|--orig) > + shift > + lxc_orig=$1 > + shift > + ;; > + -L|--fssize) > + shift > + lxc_size=$1 > + shift > + ;; > + -v|--vgname) > + shift > + lxc_vg=$1 > + shift > + ;; > + -n|--new) > + shift > + lxc_new=$1 > + shift > + ;; > + --) > + shift > + break;; > + *) > + echo $1 > + usage > + exit 1 > + ;; > + esac > +done > + > +if [ -z "$lxc_path" ]; then > + echo "no configuration path defined !" > + exit 1 > +fi > + > +if [ ! -r $lxc_path ]; then > + echo "configuration path '$lxc_path' not found" > + exit 1 > +fi > + > +if [ -z "$lxc_orig" ]; then > + echo "no original container name specified" > + usage > + exit 1 > +fi > + > +if [ -z "$lxc_new" ]; then > + echo "no new container name specified" > + usage > + exit 1 > +fi > + > +if [ "$(id -u)" != "0" ]; then > + echo "This command has to be run as root" > + exit 1 > +fi > + > +if [ ! -r $lxc_path ]; then > + echo "no configuration path defined !" > + exit 1 > +fi > + > +if [ ! -d "$lxc_path/$lxc_orig" ]; then > + echo "'$lxc_orig' does not exist" > + exit 1 > +fi > + > +if [ -d "$lxc_path/$lxc_new" ]; then > + echo "'$lxc_new' already exists" > + exit 1 > +fi > + > +trap "${bindir}/lxc-destroy -n $lxc_new; echo aborted; exit 1" SIGHUP SIGINT > SIGTERM > + > +mkdir -p $lxc_path/$lxc_new > + > +echo "Tweaking configuration" > +cp $lxc_path/$lxc_orig/config $lxc_path/$lxc_new/config > +sed -i '/lxc.utsname/d' $lxc_path/$lxc_new/config > +echo "lxc.utsname = $hostname">> $lxc_path/$lxc_new/config We should not assume lxc.utsname is in the configuration file in order to not write a hostname in all the cases. The user may want to let the container to setup itself the hostname. > + > +sed -i '/lxc.mount/d' $lxc_path/$lxc_new/config > +echo "lxc.mount = $lxc_path/$lxc_new/fstab">> $lxc_path/$lxc_new/config > + > +cp $lxc_path/$lxc_orig/fstab $lxc_path/$lxc_new/fstab > +sed -i "s@$lxc_path/$lxc_orig@$lxc_path/$lxc_new@" $lxc_path/$lxc_new/fstab Same comment. > +echo "Copying rootfs..." > +rootfs=$lxc_path/$lxc_new/rootfs > +# First figure out if the old is a device. For now we only support > +# lvm devices. > +mounted=0 > +sed -i '/lxc.rootfs/d' $lxc_path/$lxc_new/config > +oldroot=`grep lxc.rootfs $lxc_path/$lxc_orig/config | awk -F= '{ print $2 '}` > +if [ -b $oldroot ]; then > + # this is a device. If we don't want to snapshot, then mkfs, mount > + # and rsync. Trivial but not yet implemented > + if [ $snapshot == "no" ]; then > + echo "non-snapshot and non-lvm clone of block device not yet > implemented" > + exit 1 > + fi > + lvdisplay $oldroot> /dev/null 2>&1 > + if [ $? -ne 0 ]; then > + echo "non-snapshot and non-lvm clone of block device not yet > implemented" > + exit 1 > + fi > + # ok, create a snapshot of the lvm device > + lvcreate -s -L $lxc_size -n $lxc_new /dev/$lxc_vg/$lxc_orig || exit 1 > + echo "lxc.rootfs = /dev/$lxc_vg/$lxc_new">> $lxc_path/$lxc_new/config > + # and mount it so we can tweak it > + mkdir -p $lxc_path/$lxc_new/rootfs > + mount /dev/$lxc_vg/$lxc_new $rootfs || { echo "failed to mount new > rootfs"; exit 1; } > + mounted=1 > +else > + cp -a $lxc_path/$lxc_orig/rootfs $lxc_path/$lxc_new/rootfs || return 1 > + echo "lxc.rootfs = $rootfs">> $lxc_path/$lxc_new/config > +fi > + > +echo "Updating rootfs..." > +hostname=$lxc_new > + > +# so you can 'ssh $hostname.' or 'ssh $hostname.local' > +sed -i "s/send host-name.*$/send host-name $hostname/" > $rootfs/etc/dhcp/dhclient.conf > + > +# set the hostname > +cat<<EOF> $rootfs/etc/hostname > +$hostname > +EOF > +# set minimal hosts > +cat<<EOF> $rootfs/etc/hosts > +127.0.0.1 localhost $hostname > +EOF > + > +# if this was a block device, then umount it now > +if [ $mounted -eq 1 ]; then > + umount $rootfs > +fi > + > +echo "'$lxc_new' created" > > === modified file 'src/lxc/lxc-destroy.in' > --- src/lxc/lxc-destroy.in 2010-01-10 10:40:21 +0000 > +++ src/lxc/lxc-destroy.in 2011-03-29 23:00:34 +0000 > @@ -26,7 +26,8 @@ > # > > usage() { > - echo "usage: $0 -n<name>" > + echo "usage: $0 -n<name> [-l]" > + echo " if -l is specified, attempt to lvremove the rootfs device" > } > > if [ "$(id -u)" != "0" ]; then > @@ -34,9 +35,9 @@ > exit 1 > fi > > -shortoptions='n:' > -longoptions='name:' > -lxc_path=@LXCPATH@ > +shortoptions='n:l' > +longoptions='name:,lvm' > +lxc_path=/var/lib/lxc > > getopt=$(getopt -o $shortoptions --longoptions $longoptions -- "$@") > if [ $? != 0 ]; then > @@ -46,6 +47,8 @@ > > eval set -- "$getopt" > > +lvremove=0 > + > while true; do > case "$1" in > -n|--name) > @@ -53,6 +56,10 @@ > lxc_name=$1 > shift > ;; > + -l|--lvm) > + shift > + lvremove=1 > + ;; > --) > shift > break;; > @@ -75,5 +82,13 @@ > exit 1 > fi > > +if [ $lvremove -eq 1 ]; then > + rootdev=`grep lxc.rootfs $lxc_path/$lxc_name/config | awk -F= '{ print > $2 '}` > + # only makes sense if it is a blockdev or a symlink to one > + if [ -b $rootdev -o -h $rootdev ]; then > + lvremove $rootdev > + fi > +fi > + > # recursively remove the container to remove old container configuration > rm -rf --preserve-root $lxc_path/$lxc_name ------------------------------------------------------------------------------ Xperia(TM) PLAY It's a major breakthrough. An authentic gaming smartphone on the nation's most reliable network. And it wants your games. http://p.sf.net/sfu/verizon-sfdev _______________________________________________ Lxc-users mailing list Lxc-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/lxc-users