#!/bin/bash # # lxc: linux Container library # Authors: # Daniel Lezcano # 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: $(basename $0) -n NAME [-f CONFIG_FILE] [-t TEMPLATE] [FS_OPTIONS] --" >&2 echo " [TEMPLATE_OPTIONS]" >&2 echo >&2 echo "where FS_OPTIONS is one of:" >&2 echo " -B none" >&2 echo " -B lvm [--lvname LV_NAME] [--vgname VG_NAME] [--fstype FS_TYPE]" >&2 echo " [--fssize FS_SIZE]" >&2 echo " -B btrfs" >&2 } help() { usage echo >&2 echo "Create a new container on the system." >&2 echo >&2 echo "Options:" >&2 echo " -n NAME specify the name of the container" >&2 echo " -f CONFIG_FILE use an existing configuration file" >&2 echo " -t TEMPLATE use an accessible template script" >&2 echo " -B BACKING_STORE alter the container backing store (default: none)" >&2 echo " --lvname LV_NAME specify the LVM logical volume name" >&2 echo " (default: container name)" >&2 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 >&2 if [ -z $lxc_template ]; then echo "To see template-specific options, specify a template. For example:" >&2 echo " $(basename $0) -t ubuntu -h" >&2 exit 0 fi type ${templatedir}/lxc-$lxc_template 2>/dev/null if [ $? -eq 0 ]; then echo >&2 echo "Template-specific options (TEMPLATE_OPTIONS):" >&2 ${templatedir}/lxc-$lxc_template -h fi } shortoptions='hn:f:t:B:' longoptions='help,name:,config:,template:,backingstore:,fstype:,lvname:,vgname:,fssize:' lxc_path=@LXCPATH@ bindir=@BINDIR@ templatedir=@LXCTEMPLATEDIR@ backingstore=_unset fstype=ext4 fssize=500M vgname=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 ;; -n|--name) shift lxc_name=$1 shift ;; -f|--config) shift lxc_config=$1 shift ;; -t|--template) shift lxc_template=$1 shift ;; -B|--backingstore) shift backingstore=$1 shift ;; --lvname) shift lvname=$1 shift ;; --vgname) shift vgname=$1 shift ;; --fstype) shift fstype=$1 shift ;; --fssize) shift fssize=$1 shift ;; --) shift break;; *) usage exit 1 ;; esac done # If -h or --help was passed into the container, we'll want to cleanup # afterward wantedhelp=0 for var in "$@" do if [ "$var" = "-h" -o "$var" = "--help" ]; then help exit 1 fi done if [ -z "$lxc_path" ]; then echo "$(basename $0): no configuration path defined" >&2 exit 1 fi if [ ! -r $lxc_path ]; then echo "$(basename $0): configuration path '$lxc_path' not found" >&2 exit 1 fi if [ -z "$lxc_name" ]; then echo "$(basename $0): no container name specified" >&2 usage exit 1 fi if [ -z "$lvname" ]; then lvname="$lxc_name" fi if [ "$(id -u)" != "0" ]; then echo "$(basename $0): must be run as root" >&2 exit 1 fi case "$backingstore" in lvm|none|btrfs|_unset) :;; *) echo "$(basename $0): '$backingstore' is not known (try 'none', 'lvm', 'btrfs')" >&2 usage exit 1 ;; esac if [ -d "$lxc_path/$lxc_name" ]; then echo "$(basename $0): '$lxc_name' already exists" >&2 exit 1 fi rootfs="$lxc_path/$lxc_name/rootfs" if [ "$backingstore" = "_unset" -o "$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 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 fi ${bindir}/lxc-destroy -n $lxc_name echo "$(basename $0): aborted" >&2 exit 1 } trap cleanup HUP INT TERM mkdir -p $lxc_path/$lxc_name if [ -z "$lxc_config" ]; then touch $lxc_path/$lxc_name/config else if [ ! -r "$lxc_config" ]; then echo "$(basename $0): '$lxc_config' configuration file not found" >&2 exit 1 fi cp $lxc_config $lxc_path/$lxc_name/config fi # Create the fs as needed if [ $backingstore = "lvm" ]; then [ -d "$rootfs" ] || mkdir $rootfs lvcreate -L $fssize -n $lvname $vgname || exit 1 udevadm settle mkfs -t $fstype $rootdev || exit 1 mount -t $fstype $rootdev $rootfs fi if [ ! -z $lxc_template ]; then type ${templatedir}/lxc-$lxc_template 2>/dev/null if [ $? -ne 0 ]; then echo "$(basename $0): unknown template '$lxc_template'" >&2 cleanup fi if [ -z "$lxc_config" ]; then echo "Note: Usually the template option is called with a configuration" echo "file option too, mostly to configure the network." echo "For more information look at lxc.conf (5)" echo fi ${templatedir}/lxc-$lxc_template --path=$lxc_path/$lxc_name --name=$lxc_name $* if [ $? -ne 0 ]; then echo "$(basename $0): failed to execute template '$lxc_template'" >&2 cleanup fi echo "'$lxc_template' template installed" fi if [ $backingstore = "lvm" ]; then echo "Unmounting LVM" umount $rootfs # TODO: make the templates set this right from the start? sed -i '/lxc.rootfs/d' $lxc_path/$lxc_name/config echo "lxc.rootfs = $rootdev" >> $lxc_path/$lxc_name/config fi echo "'$lxc_name' created"