[lxc-devel] [PATCH] add zfs support to lxc-create and lxc-destroy

Stéphane Graber stgraber at ubuntu.com
Fri Apr 26 07:59:53 UTC 2013


On 04/25/2013 10:18 PM, Serge Hallyn wrote:
> This is based on patch from Papp Tamas (thanks).  It also does some
> reorganizing of lxc-create to commonize some of the backingstore handling.
> 
> I played with it using:
> 
> 	sudo lvcreate -L 100G -n zfs vg0
> 	sudo zpool create lxc /dev/vg0/zfs
> 	sudo lxc-create -B zfs --zfsroot lxc -t ubuntu -n dir2
> 
> or you could
> 
> 	qemu-img create zfs.img 100G
> 	sudo qemu-nbd -c /dev/nbd0 zfs.img
> 	sudo zpool create lxc /dev/nbd0
> 	sudo lxc-create -B zfs --zfsroot lxc -t ubuntu -n dir2
> 
> I'll write the bdev.c handler and hook up lxc-clone next.
> 
> This also fixses a bug in the sed expression to extract the rootfs from
> container config, which prepended an extra '/' to the rootdev.  (That
> caused the zfs list entry not to match at destroy)
> 
> Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
> Cc: Papp Tamas <tompos at martos.bme.hu>

The only potential annoyance I can see is if we ever try to auto-detect
LVM as it's way more verbose than the other checks and will throw a
bunch of weird errors to the user who just wanted auto-detect.

But LVM currently isn't in the _unset case so that's fine.

Acked-by: Stéphane Graber <stgraber at ubuntu.com>

> ---
>  src/lxc/lxc-create.in  |  167 ++++++++++++++++++++++++++++++++----------------
>  src/lxc/lxc-destroy.in |   13 +++-
>  2 files changed, 124 insertions(+), 56 deletions(-)
> 
> diff --git a/src/lxc/lxc-create.in b/src/lxc/lxc-create.in
> index fbb566f..3367a89 100644
> --- a/src/lxc/lxc-create.in
> +++ b/src/lxc/lxc-create.in
> @@ -22,6 +22,59 @@
>  
>  . @DATADIR@/lxc/lxc.functions
>  
> +verify_btrfs() {
> +    if which btrfs >/dev/null 2>&1 && \
> +        btrfs filesystem df "$lxc_path/" >/dev/null 2>&1; then
> +        echo "btrfs"
> +    else
> +        echo "no"
> +    fi
> +}
> +
> +verify_zfs() {
> +    if which zfs >/dev/null 2>&1 && zfs get all "$zfs_root" >/dev/null 2>&1; then
> +        echo zfs
> +    else
> +        echo no
> +    fi
> +}
> +
> +verify_lvm() {
> +    which vgscan > /dev/null 2>&1
> +    if [ $? -ne 0 ]; then
> +        echo "vgscan not found (is lvm2 installed?)" >&2
> +        echo no
> +        return
> +    fi
> +
> +    grep -q "\<$fstype\>" /proc/filesystems
> +    if [ $? -ne 0 ]; then
> +        echo "$fstype is not listed in /proc/filesystems" >&2
> +        echo no
> +        return
> +    fi
> +
> +    vgscan | grep -q "Found volume group \"$vgname\""
> +    if [ $? -ne 0 ]; then
> +        echo "could not find volume group \"$vgname\"" >&2
> +        echo no
> +        return
> +    fi
> +
> +    echo lvm
> +}
> +
> +# if no backingstore is specified, auto-detect if $lxc_path is btrfs or zfs
> +detect_backingstore() {
> +    if [ `verify_btrfs` = "btrfs" ]; then
> +        echo btrfs
> +    elif [ `verify_zfs` = "zfs" ]; then
> +        echo zfs
> +    else
> +        echo none
> +    fi
> +}
> +
>  usage() {
>      echo "usage: $(basename $0) -n NAME [-f CONFIG_FILE] [-t TEMPLATE] [FS_OPTIONS] --" >&2
>      echo "         [-P lxcpath] [TEMPLATE_OPTIONS]" >&2
> @@ -32,6 +85,7 @@ usage() {
>      echo "  -B lvm [--lvname LV_NAME] [--vgname VG_NAME] [--fstype FS_TYPE]" >&2
>      echo "    [--fssize FS_SIZE]" >&2
>      echo "  -B btrfs" >&2
> +    echo "  -B zfs [--zfsroot PATH]" >&2
>  }
>  
>  help() {
> @@ -51,6 +105,7 @@ help() {
>      echo "  --vgname VG_NAME   specify the LVM volume group name (default: lxc)" >&2
>      echo "  --fstype FS_TYPE   specify the filesystem type (default: ext4)" >&2
>      echo "  --fssize FS_SIZE   specify the filesystem size (default: 500M)" >&2
> +    echo "  --zfsroot PATH     specify the zfs path for lxcpath (default: tank/lxc)" >&2
>      echo >&2
>      if [ -z "$lxc_template" ]; then
>          echo "To see template-specific options, specify a template. For example:" >&2
> @@ -140,6 +195,11 @@ while [ $# -gt 0 ]; do
>              fssize=$1
>              shift
>              ;;
> +        --zfsroot)
> +            optarg_check $opt "$1"
> +            zfs_root=$1
> +            shift
> +            ;;
>          --)
>              break;;
>          -?)
> @@ -187,6 +247,10 @@ if [ -z "$lvname" ]; then
>      lvname="$lxc_name"
>  fi
>  
> +if [ -z "$zfs_root" ]; then
> +    zfs_root="tank/lxc"
> +fi
> +
>  if [ "$(id -u)" != "0" ]; then
>     echo "$(basename $0): must be run as root" >&2
>     exit 1
> @@ -196,10 +260,39 @@ if [ -n "$custom_rootfs" ] && [ "$backingstore" != "dir" ]; then
>     echo "--dir is only valid with -B dir"
>  fi
>  
> +# detect / verify backing store
>  case "$backingstore" in
> -    dir|lvm|none|btrfs|_unset) :;;
> +    btrfs)
> +        if [ `verify_btrfs` != 'btrfs' ]; then
> +            echo "missing 'btrfs' command or $lxc_path is not btrfs" >&2
> +            exit 1
> +        fi
> +        ;;
> +    zfs)
> +        if [ `verify_zfs` != 'zfs' ]; then
> +            echo "missing 'zfs' command or $zfs_root is not zfs" >&2
> +            exit 1
> +        fi
> +        ;;
> +    lvm)
> +        if [ `verify_lvm` != 'lvm' ]; then
> +            echo "system is missing 'lvm' support, or VG does not exist." >&2
> +            exit 1
> +        fi
> +        rootdev=/dev/$vgname/$lvname
> +        lvdisplay $rootdev > /dev/null 2>&1
> +        if [ $? -eq 0 ]; then
> +            echo "LV $rootdev already exists" >&2
> +            exit 1
> +        fi
> +        ;;
> +    _unset)
> +        backingstore=`detect_backingstore`
> +        ;;
> +    dir|lvm|none)
> +        :;;
>      *)
> -        echo "$(basename $0): '$backingstore' is not known (try 'none', 'dir', 'lvm', 'btrfs')" >&2
> +        echo "$(basename $0): '$backingstore' is not known (try 'none', 'dir', 'lvm', 'btrfs', 'zfs')" >&2
>          usage
>          exit 1
>          ;;
> @@ -212,61 +305,14 @@ fi
>  
>  rootfs="$lxc_path/$lxc_name/rootfs"
>  
> -if [ "$backingstore" = "_unset" ] || [ "$backingstore" = "btrfs" ]; then
> -# if no backing store was given, then see if btrfs would work
> -    if which btrfs >/dev/null 2>&1 && \
> -        btrfs filesystem df "$lxc_path/" >/dev/null 2>&1; then
> -        backingstore="btrfs"
> -    else
> -        if [ "$backingstore" = "btrfs" ]; then
> -            echo "$(basename $0): missing 'btrfs' command or $lxc_path is not btrfs" >&2
> -            exit 1;
> -        fi
> -        backingstore="none"
> -    fi
> -fi
> -
> -if [ "$backingstore" = "lvm" ]; then
> -    which vgscan > /dev/null 2>&1
> -    if [ $? -ne 0 ]; then
> -        echo "$(basename $0): vgscan not found (is lvm2 installed?)" >&2
> -        exit 1
> -    fi
> -
> -    grep -q "\<$fstype\>" /proc/filesystems
> -    if [ $? -ne 0 ]; then
> -        echo "$(basename $0): $fstype is not listed in /proc/filesystems" >&2
> -        exit 1
> -    fi
> -
> -    vgscan | grep -q "Found volume group \"$vgname\""
> -    if [ $? -ne 0 ]; then
> -        echo "$(basename $0): could not find volume group \"$vgname\"" >&2
> -        exit 1
> -    fi
> -
> -    rootdev=/dev/$vgname/$lvname
> -    lvdisplay $rootdev > /dev/null 2>&1
> -    if [ $? -eq 0 ]; then
> -        echo "$(basename $0): backing store already exists: $rootdev" >&2
> -        echo "please delete it (using \"lvremove $rootdev\") and try again" >&2
> -        exit 1
> -    fi
> -
> -elif [ "$backingstore" = "btrfs" ]; then
> -    mkdir "$lxc_path/$lxc_name"
> -    if ! out=$(btrfs subvolume create "$rootfs" 2>&1); then
> -        echo "$(basename $0): failed to create subvolume in $rootfs: $out" >&2
> -        exit 1;
> -    fi
> -fi
> -
>  cleanup() {
>      if [ "$backingstore" = "lvm" ]; then
> -        umount $rootfs
> -        lvremove -f $rootdev
> +        umount -l $rootfs || true
> +        lvremove -f $rootdev || true
>      elif [ "$backingstore" = "btrfs" ]; then
> -        btrfs subvolume delete "$rootfs"
> +        btrfs subvolume delete "$rootfs" || true
> +    elif [ "$backingstore" = "zfs" ]; then
> +        zfs destroy "$zfs_root/$lxc_name" || true
>      fi
>  
>      ${bindir}/lxc-destroy -n $lxc_name
> @@ -276,7 +322,18 @@ cleanup() {
>  
>  trap cleanup HUP INT TERM
>  
> -mkdir -p $lxc_path/$lxc_name
> +# set up container dir per backing store
> +if [ "$backingstore" = "zfs" ]; then
> +    zfs create -omountpoint=$lxc_path/$lxc_name/rootfs "$zfs_root/$lxc_name"
> +elif [ "$backingstore" = "btrfs" ]; then
> +    mkdir "$lxc_path/$lxc_name"
> +    if ! out=$(btrfs subvolume create "$rootfs" 2>&1); then
> +        echo "$(basename $0): failed to create subvolume in $rootfs: $out" >&2
> +        exit 1;
> +    fi
> +else
> +    mkdir -p $lxc_path/$lxc_name
> +fi
>  
>  if [ -z "$lxc_config" ]; then
>      lxc_config="@SYSCONFDIR@/lxc/default.conf"
> diff --git a/src/lxc/lxc-destroy.in b/src/lxc/lxc-destroy.in
> index 6514085..fc164c2 100644
> --- a/src/lxc/lxc-destroy.in
> +++ b/src/lxc/lxc-destroy.in
> @@ -46,6 +46,15 @@ usage_err() {
>      exit 1
>  }
>  
> +verify_zfs() {
> +    path=$1
> +    if which zfs >/dev/null 2>&1 && zfs list | grep -q $path; then
> +        echo zfs
> +    else
> +        echo no
> +    fi
> +}
> +
>  optarg_check() {
>      if [ -z "$2" ]; then
>          usage_err "option '$1' requires an argument"
> @@ -123,7 +132,7 @@ fi
>  # Deduce the type of rootfs
>  # If LVM partition, destroy it. For btrfs, we delete the subvolue. If anything
>  # else, ignore it. We'll support deletion of others later.
> -rootdev=`grep lxc.rootfs $lxc_path/$lxc_name/config 2>/dev/null | sed -e 's/^[^/]*/\//'`
> +rootdev=`grep lxc.rootfs $lxc_path/$lxc_name/config 2>/dev/null | sed -e 's/^[^/]*//'`
>  if [ -n "$rootdev" ]; then
>      if [ -b "$rootdev" -o -h "$rootdev" ]; then
>          lvdisplay $rootdev > /dev/null 2>&1
> @@ -131,6 +140,8 @@ if [ -n "$rootdev" ]; then
>              echo "removing backing store: $rootdev"
>              lvremove -f $rootdev
>          fi
> +    elif [ `verify_zfs $rootdev` = "zfs" ]; then
> +        zfs destroy $(zfs list | grep $rootdev | awk '{ print $1 }')
>      elif [ -h "$rootdev" -o -d "$rootdev" ]; then
>          if which btrfs >/dev/null 2>&1 &&
>             btrfs subvolume list "$rootdev" >/dev/null 2>&1; then
> 


-- 
Stéphane Graber
Ubuntu developer
http://www.ubuntu.com

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 901 bytes
Desc: OpenPGP digital signature
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20130426/7c98dd66/attachment.pgp>


More information about the lxc-devel mailing list