--- /dev/null
+#!/bin/bash
+
+#
+# lxc: linux Container library
+
+# Authors:
+# Daniel Lezcano <daniel.lezcano@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
+
+install_busybox()
+{
+ rootfs=$1
+ name=$2
+ res=0
+ tree="\
+$rootfs/selinux \
+$rootfs/dev \
+$rootfs/home \
+$rootfs/root \
+$rootfs/etc \
+$rootfs/etc/init.d \
+$rootfs/bin \
+$rootfs/sbin \
+$rootfs/proc \
+$rootfs/mnt \
+$rootfs/tmp \
+$rootfs/var/log \
+$rootfs/usr/share/udhcpc \
+$rootfs/dev/pts \
+$rootfs/dev/shm \
+$rootfs/lib \
+$rootfs/usr/lib \
+$rootfs/lib64 \
+$rootfs/usr/lib64"
+
+ mkdir -p $tree || return 1
+ chmod 755 $tree || return 1
+
+ pushd $rootfs/dev > /dev/null || return 1
+
+ # minimal devices needed for busybox
+ mknod tty c 5 0 || res=1
+ mknod console c 5 1 || res=1
+ chmod 666 tty console || res=1
+ mknod tty0 c 4 0 || res=1
+ mknod tty1 c 4 0 || res=1
+ mknod tty5 c 4 0 || res=1
+ chmod 666 tty0 || res=1
+ mknod ram0 b 1 0 || res=1
+ chmod 600 ram0 || res=1
+ mknod null c 1 3 || res=1
+ chmod 666 null || res=1
+
+ popd > /dev/null
+
+ # root user defined
+ cat <<EOF >> $rootfs/etc/passwd
+root:x:0:0:root:/root:/bin/sh
+EOF
+
+ cat <<EOF >> $rootfs/etc/group
+root:x:0:root
+EOF
+
+ # mount everything
+ cat <<EOF >> $rootfs/etc/init.d/rcS
+#!/bin/sh
+/bin/syslogd
+/bin/mount -a
+/bin/udhcpc
+EOF
+
+ # executable
+ chmod 744 $rootfs/etc/init.d/rcS || return 1
+
+ # mount points
+ cat <<EOF >> $rootfs/etc/fstab
+proc /proc proc defaults 0 0
+shm /dev/shm tmpfs defaults 0 0
+EOF
+
+ # writable and readable for other
+ chmod 644 $rootfs/etc/fstab || return 1
+
+ # launch rcS first then make a console available
+ # and propose a shell on the tty, the last one is
+ # not needed
+ cat <<EOF >> $rootfs/etc/inittab
+::sysinit:/etc/init.d/rcS
+tty1::respawn:/bin/getty -L tty1 115200 vt100
+console::askfirst:/bin/sh
+EOF
+ # writable and readable for other
+ chmod 644 $rootfs/etc/inittab || return 1
+
+ cat <<EOF >> $rootfs/usr/share/udhcpc/default.script
+#!/bin/sh
+
+case "\$1" in
+ deconfig)
+ ip addr flush dev \$interface
+ ;;
+
+ renew|bound)
+
+ # flush all the routes
+ if [ -n "\$router" ]; then
+ ip route del default 2> /dev/null
+ fi
+
+ # check broadcast
+ if [ -n "\$broadcast" ]; then
+ broadcast="broadcast \$broadcast"
+ fi
+
+ # add a new ip address
+ ip addr add \$ip/\$mask \$broadcast dev \$interface
+
+ if [ -n "\$router" ]; then
+ ip route add default via \$router dev \$interface
+ fi
+
+ [ -n "\$domain" ] && echo search \$domain > /etc/resolv.conf
+ for i in \$dns ; do
+ echo nameserver \$i >> /etc/resolv.conf
+ done
+ ;;
+esac
+exit 0
+EOF
+
+ chmod 744 $rootfs/usr/share/udhcpc/default.script
+
+ return $res
+}
+
+configure_busybox()
+{
+ rootfs=$1
+
+ functions="\
+ [ [[ addgroup adduser adjtimex ar arp arping ash awk basename \
+ brctl bunzip2 bzcat bzip2 cal cat catv chattr chgrp chmod \
+ chown chpasswd chpst chroot chrt chvt cksum clear cmp comm \
+ cp cpio crond crontab cryptpw cut date dc dd deallocvt \
+ delgroup deluser df dhcprelay diff dirname dmesg dnsd dos2unix \
+ du dumpkmap dumpleases echo ed egrep eject env envdir envuidgid \
+ ether-wake expand expr fakeidentd false fbset fdformat fdisk \
+ fetchmail fgrep find findfs fold free freeramdisk fsck \
+ fsck.minix ftpget ftpput fuser getopt getty grep gunzip gzip \
+ halt hdparm head hexdump hostid hostname httpd hwclock id \
+ ifconfig ifdown ifenslave ifup inetd init insmod install ip \
+ ipaddr ipcalc ipcrm ipcs iplink iproute iprule iptunnel \
+ kbd_mode kill killall killall5 klogd last length less linux32 \
+ linux64 linuxrc ln loadfont loadkmap logger login logname \
+ logread losetup lpd lpq lpr ls lsattr lsmod lzmacat makedevs \
+ md5sum mdev mesg microcom mkdir mkfifo mkfs.minix mknod mkswap \
+ mktemp modprobe more mount mountpoint msh mt mv nameif nc \
+ netstat nice nmeter nohup nslookup od openvt passwd patch \
+ pgrep pidof ping ping6 pipe_progress pivot_root pkill poweroff \
+ printenv printf ps pscan pwd raidautorun rdate readahead \
+ readlink readprofile realpath reboot renice reset resize rm \
+ rmdir rmmod route rpm rpm2cpio run-parts runlevel runsv \
+ runsvdir rx script sed sendmail seq setarch setconsole \
+ setkeycodes setlogcons setsid setuidgid sh sha1sum slattach \
+ sleep softlimit sort split start-stop-daemon stat strings \
+ stty su sulogin sum sv svlogd swapoff swapon switch_root \
+ sync sysctl syslogd tac tail tar taskset tcpsvd tee telnet \
+ telnetd test tftp tftpd time top touch tr traceroute \
+ true tty ttysize udhcpc udhcpd udpsvd umount uname uncompress \
+ unexpand uniq unix2dos unlzma unzip uptime usleep uudecode \
+ uuencode vconfig vi vlock watch watchdog wc wget which \
+ who whoami xargs yes zcat zcip"
+
+ type busybox >/dev/null
+
+ if [ $? -ne 0 ]; then
+ echo "busybox executable is not accessible"
+ return 1
+ fi
+
+ file $(which busybox) | grep -q "statically linked"
+ if [ $? -ne 0 ]; then
+ echo "warning : busybox is not statically linked."
+ echo "warning : The template script may not correctly"
+ echo "warning : setup the container environment."
+ fi
+
+ # copy busybox in the rootfs
+ cp $(which busybox) $rootfs/bin
+ if [ $? -ne 0 ]; then
+ echo "failed to copy busybox in the rootfs"
+ return 1
+ fi
+
+ # do hardlink to busybox for the different commands
+ for i in $functions; do ln $rootfs/bin/busybox $rootfs/bin/$i; done
+
+ # relink /sbin/init
+ ln $rootfs/bin/busybox $rootfs/sbin/init
+
+ # passwd exec must be setuid
+ chmod +s $rootfs/bin/passwd
+ touch $rootfs/etc/shadow
+ chroot $rootfs /bin/passwd -d root
+
+ echo "No password for 'root', please change !"
+
+ return 0
+}
+
+copy_configuration()
+{
+ path=$1
+ rootfs=$2
+ name=$3
+
+cat <<EOF >> $path/config
+lxc.utsname = $name
+lxc.tty = 1
+lxc.pts = 1
+lxc.rootfs = $rootfs
+# uncomment the next line to run the container unconfined:
+#lxc.aa_profile = unconfined
+EOF
+
+if [ -d "$rootfs/lib" ]; then
+cat <<EOF >> $path/config
+lxc.mount.entry=/lib $rootfs/lib none ro,bind 0 0
+lxc.mount.entry=/usr/lib $rootfs/usr/lib none ro,bind 0 0
+EOF
+fi
+
+if [ -d "/lib64" ] && [ -d "$rootfs/lib64" ]; then
+cat <<EOF >> $path/config
+lxc.mount.entry=/lib64 $rootfs/lib64 none ro,bind 0 0
+EOF
+fi
+
+if [ -d "/usr/lib64" ] && [ -d "$rootfs/usr/lib64" ]; then
+cat <<EOF >> $path/config
+lxc.mount.entry=/usr/lib64 $rootfs/usr/lib64 none ro,bind 0 0
+EOF
+fi
+}
+
+usage()
+{
+ cat <<EOF
+$1 -h|--help -p|--path=<path>
+EOF
+ return 0
+}
+
+options=$(getopt -o hp:n: -l help,path:,name: -- "$@")
+if [ $? -ne 0 ]; then
+ usage $(basename $0)
+ exit 1
+fi
+eval set -- "$options"
+
+while true
+do
+ case "$1" in
+ -h|--help) usage $0 && exit 0;;
+ -p|--path) path=$2; shift 2;;
+ -n|--name) name=$2; shift 2;;
+ --) shift 1; break ;;
+ *) break ;;
+ esac
+done
+
+if [ "$(id -u)" != "0" ]; then
+ echo "This script should be run as 'root'"
+ exit 1
+fi
+
+if [ -z "$path" ]; then
+ echo "'path' parameter is required"
+ exit 1
+fi
+
+rootfs=$path/rootfs
+
+install_busybox $rootfs $name
+if [ $? -ne 0 ]; then
+ echo "failed to install busybox's rootfs"
+ exit 1
+fi
+
+configure_busybox $rootfs
+if [ $? -ne 0 ]; then
+ echo "failed to configure busybox template"
+ exit 1
+fi
+
+copy_configuration $path $rootfs $name
+if [ $? -ne 0 ]; then
+ echo "failed to write configuration file"
+ exit 1
+fi
--- /dev/null
+#!/bin/bash
+
+#
+# lxc: linux Container library
+
+# Authors:
+# Daniel Lezcano <daniel.lezcano@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
+
+SUITE=${SUITE:-squeeze}
+MIRROR=${MIRROR:-http://cdn.debian.net/debian}
+
+configure_debian()
+{
+ rootfs=$1
+ hostname=$2
+
+ # squeeze only has /dev/tty and /dev/tty0 by default,
+ # therefore creating missing device nodes for tty1-4.
+ for tty in $(seq 1 4); do
+ if [ ! -e $rootfs/dev/tty$tty ]; then
+ mknod $rootfs/dev/tty$tty c 4 $tty
+ fi
+ done
+
+ # configure the inittab
+ cat <<EOF > $rootfs/etc/inittab
+id:2:initdefault:
+si::sysinit:/etc/init.d/rcS
+l0:0:wait:/etc/init.d/rc 0
+l1:1:wait:/etc/init.d/rc 1
+l2:2:wait:/etc/init.d/rc 2
+l3:3:wait:/etc/init.d/rc 3
+l4:4:wait:/etc/init.d/rc 4
+l5:5:wait:/etc/init.d/rc 5
+l6:6:wait:/etc/init.d/rc 6
+# Normally not reached, but fallthrough in case of emergency.
+z6:6:respawn:/sbin/sulogin
+1:2345:respawn:/sbin/getty 38400 console
+c1:12345:respawn:/sbin/getty 38400 tty1 linux
+c2:12345:respawn:/sbin/getty 38400 tty2 linux
+c3:12345:respawn:/sbin/getty 38400 tty3 linux
+c4:12345:respawn:/sbin/getty 38400 tty4 linux
+EOF
+
+ # disable selinux in debian
+ mkdir -p $rootfs/selinux
+ echo 0 > $rootfs/selinux/enforce
+
+ # configure the network using the dhcp
+ cat <<EOF > $rootfs/etc/network/interfaces
+auto lo
+iface lo inet loopback
+
+auto eth0
+iface eth0 inet dhcp
+EOF
+
+ # set the hostname
+ cat <<EOF > $rootfs/etc/hostname
+$hostname
+EOF
+
+ # reconfigure some services
+ LANG="${LANG:-en_US.UTF-8}"
+
+ locale="$LANG $(echo $LANG | cut -d. -f2)"
+ chroot $rootfs echo "locales locales/default_environment_locale select $LANG" | chroot $rootfs sh -c "LANG=C debconf-set-selections"
+ chroot $rootfs echo "locales locales/default_environment_locale seen true" | chroot $rootfs sh -c "LANG=C debconf-set-selections"
+ chroot $rootfs echo "locales locales/locales_to_be_generated seen true" | chroot $rootfs sh -c "LANG=C debconf-set-selections"
+ chroot $rootfs sed -i -e "0,/^[# ]*$locale *$/ s/^[# ]*$locale *$/$locale/" /etc/locale.gen
+ chroot $rootfs sh -c "LANG=C dpkg-reconfigure locales -f noninteractive"
+
+ # remove pointless services in a container
+ chroot $rootfs /usr/sbin/update-rc.d -f checkroot.sh remove # S
+ chroot $rootfs /usr/sbin/update-rc.d checkroot.sh stop 09 S .
+
+ chroot $rootfs /usr/sbin/update-rc.d -f umountfs remove # 0 6
+ chroot $rootfs /usr/sbin/update-rc.d umountfs start 09 0 6 .
+
+ chroot $rootfs /usr/sbin/update-rc.d -f umountroot remove # 0 6
+ chroot $rootfs /usr/sbin/update-rc.d umountroot start 10 0 6 .
+
+ # The following initscripts don't provide an empty start or stop block.
+ # To prevent them being enabled on upgrades, we leave a start link on
+ # runlevel 3.
+ chroot $rootfs /usr/sbin/update-rc.d -f hwclock.sh remove # S 0 6
+ chroot $rootfs /usr/sbin/update-rc.d hwclock.sh start 10 3 .
+
+ chroot $rootfs /usr/sbin/update-rc.d -f hwclockfirst.sh remove # S
+ chroot $rootfs /usr/sbin/update-rc.d hwclockfirst start 08 3 .
+
+ chroot $rootfs /usr/sbin/update-rc.d -f module-init-tools remove # S
+ chroot $rootfs /usr/sbin/update-rc.d module-init-tools start 10 3 .
+
+ echo "root:root" | chroot $rootfs chpasswd
+ echo "Root password is 'root', please change !"
+
+ return 0
+}
+
+download_debian()
+{
+ packages=\
+ifupdown,\
+locales,\
+libui-dialog-perl,\
+dialog,\
+dhcp3-client,\
+netbase,\
+net-tools,\
+iproute,\
+openssh-server
+
+ cache=$1
+ arch=$2
+
+ # check the mini debian was not already downloaded
+ mkdir -p "$cache/partial-$SUITE-$arch"
+ if [ $? -ne 0 ]; then
+ echo "Failed to create '$cache/partial-$SUITE-$arch' directory"
+ return 1
+ fi
+
+ # download a mini debian into a cache
+ echo "Downloading debian minimal ..."
+ debootstrap --verbose --variant=minbase --arch=$arch \
+ --include=$packages \
+ "$SUITE" "$cache/partial-$SUITE-$arch" $MIRROR
+ if [ $? -ne 0 ]; then
+ echo "Failed to download the rootfs, aborting."
+ return 1
+ fi
+
+ mv "$1/partial-$SUITE-$arch" "$1/rootfs-$SUITE-$arch"
+ echo "Download complete."
+
+ return 0
+}
+
+copy_debian()
+{
+ cache=$1
+ arch=$2
+ rootfs=$3
+
+ # make a local copy of the minidebian
+ echo -n "Copying rootfs to $rootfs..."
+ mkdir -p $rootfs
+ rsync -a "$cache/rootfs-$SUITE-$arch"/ $rootfs/ || return 1
+ return 0
+}
+
+install_debian()
+{
+ cache="/var/cache/lxc/debian"
+ rootfs=$1
+ mkdir -p /var/lock/subsys/
+ (
+ flock -x 200
+ if [ $? -ne 0 ]; then
+ echo "Cache repository is busy."
+ return 1
+ fi
+
+ # Code taken from debootstrap
+ if [ -x /usr/bin/dpkg ] && /usr/bin/dpkg --print-architecture >/dev/null 2>&1; then
+ arch=`/usr/bin/dpkg --print-architecture`
+ elif type udpkg >/dev/null 2>&1 && udpkg --print-architecture >/dev/null 2>&1; then
+ arch=`/usr/bin/udpkg --print-architecture`
+ else
+ arch=$(arch)
+ case $arch in
+ 686) arch="i386";;
+ x86_64) arch="amd64";;
+ ppc) arch="powerpc";;
+ esac
+ fi
+
+ echo "Checking cache download in $cache/rootfs-$SUITE-$arch ... "
+ if [ ! -e "$cache/rootfs-$SUITE-$arch" ]; then
+ download_debian $cache $arch
+ if [ $? -ne 0 ]; then
+ echo "Failed to download 'debian base'"
+ return 1
+ fi
+ fi
+
+ copy_debian $cache $arch $rootfs
+ if [ $? -ne 0 ]; then
+ echo "Failed to copy rootfs"
+ return 1
+ fi
+
+ return 0
+
+ ) 200>/var/lock/subsys/lxc
+
+ return $?
+}
+
+copy_configuration()
+{
+ path=$1
+ rootfs=$2
+ name=$3
+
+ cat >> $path/config << EOF
+# $path/config
+
+## Container
+lxc.utsname = $name
+lxc.rootfs = $rootfs
+lxc.tty = 4
+lxc.pts = 1024
+#lxc.console = /var/log/lxc/$name.console
+
+## Capabilities
+lxc.cap.drop = sys_admin
+
+# uncomment the next line to run the container unconfined:
+#lxc.aa_profile = unconfined
+
+## Devices
+#lxc.cgroup.devices.allow = a
+lxc.cgroup.devices.deny = a
+# /dev/null
+lxc.cgroup.devices.allow = c 1:3 rwm
+# /dev/zero
+lxc.cgroup.devices.allow = c 1:5 rwm
+# /dev/tty[1-4] consoles
+lxc.cgroup.devices.allow = c 5:1 rwm
+lxc.cgroup.devices.allow = c 5:0 rwm
+lxc.cgroup.devices.allow = c 4:0 rwm
+lxc.cgroup.devices.allow = c 4:1 rwm
+# /dev/{,u}random
+lxc.cgroup.devices.allow = c 1:9 rwm
+lxc.cgroup.devices.allow = c 1:8 rwm
+lxc.cgroup.devices.allow = c 136:* rwm
+lxc.cgroup.devices.allow = c 5:2 rwm
+# /dev/rtc
+lxc.cgroup.devices.allow = c 254:0 rwm
+
+## Limits
+#lxc.cgroup.cpu.shares = 1024
+#lxc.cgroup.cpuset.cpus = 0
+#lxc.cgroup.memory.limit_in_bytes = 256M
+#lxc.cgroup.memory.memsw.limit_in_bytes = 1G
+
+## Filesystem
+lxc.mount.entry = proc proc proc nodev,noexec,nosuid 0 0
+lxc.mount.entry = sysfs sys sysfs defaults,ro 0 0
+#lxc.mount.entry = /srv/$name srv/$name none defaults,bind 0 0
+EOF
+
+ if [ $? -ne 0 ]; then
+ echo "Failed to add configuration"
+ return 1
+ fi
+
+ return 0
+}
+
+clean()
+{
+ cache="/var/cache/lxc/debian"
+
+ if [ ! -e $cache ]; then
+ exit 0
+ fi
+
+ # lock, so we won't purge while someone is creating a repository
+ (
+ flock -x 200
+ if [ $? != 0 ]; then
+ echo "Cache repository is busy."
+ exit 1
+ fi
+
+ echo -n "Purging the download cache..."
+ rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1
+ exit 0
+
+ ) 200>/var/lock/subsys/lxc
+}
+
+usage()
+{
+ cat <<EOF
+$1 -h|--help -p|--path=<path> --clean
+EOF
+ return 0
+}
+
+options=$(getopt -o hp:n:c -l help,path:,name:,clean -- "$@")
+if [ $? -ne 0 ]; then
+ usage $(basename $0)
+ exit 1
+fi
+eval set -- "$options"
+
+while true
+do
+ case "$1" in
+ -h|--help) usage $0 && exit 0;;
+ -p|--path) path=$2; shift 2;;
+ -n|--name) name=$2; shift 2;;
+ -c|--clean) clean=$2; shift 2;;
+ --) shift 1; break ;;
+ *) break ;;
+ esac
+done
+
+if [ ! -z "$clean" -a -z "$path" ]; then
+ clean || exit 1
+ exit 0
+fi
+
+type debootstrap
+if [ $? -ne 0 ]; then
+ echo "'debootstrap' command is missing"
+ exit 1
+fi
+
+if [ -z "$path" ]; then
+ echo "'path' parameter is required"
+ exit 1
+fi
+
+if [ "$(id -u)" != "0" ]; then
+ echo "This script should be run as 'root'"
+ exit 1
+fi
+
+rootfs=$path/rootfs
+
+install_debian $rootfs
+if [ $? -ne 0 ]; then
+ echo "failed to install debian"
+ exit 1
+fi
+
+configure_debian $rootfs $name
+if [ $? -ne 0 ]; then
+ echo "failed to configure debian for a container"
+ exit 1
+fi
+
+copy_configuration $path $rootfs
+if [ $? -ne 0 ]; then
+ echo "failed write configuration file"
+ exit 1
+fi
+
+if [ ! -z $clean ]; then
+ clean || exit 1
+ exit 0
+fi
--- /dev/null
+#!/bin/bash
+
+#
+# template script for generating fedora container for LXC
+#
+
+#
+# lxc: linux Container library
+
+# Authors:
+# Daniel Lezcano <daniel.lezcano@free.fr>
+# Ramez Hanna <rhanna@informatiq.org>
+
+# 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
+
+#Configurations
+arch=$(arch)
+cache_base=/var/cache/lxc/fedora/$arch
+default_path=/var/lib/lxc
+root_password=root
+
+# is this fedora?
+[ -f /etc/fedora-release ] && is_fedora=true
+
+if [ "$arch" = "i686" ]; then
+ arch=i386
+fi
+
+configure_fedora()
+{
+
+ # disable selinux in fedora
+ mkdir -p $rootfs_path/selinux
+ echo 0 > $rootfs_path/selinux/enforce
+
+ # configure the network using the dhcp
+ cat <<EOF > ${rootfs_path}/etc/sysconfig/network-scripts/ifcfg-eth0
+DEVICE=eth0
+BOOTPROTO=dhcp
+ONBOOT=yes
+HOSTNAME=${name}
+NM_CONTROLLED=no
+TYPE=Ethernet
+MTU=${MTU}
+EOF
+
+ # set the hostname
+ cat <<EOF > ${rootfs_path}/etc/sysconfig/network
+NETWORKING=yes
+HOSTNAME=${name}
+EOF
+
+ # set minimal hosts
+ cat <<EOF > $rootfs_path/etc/hosts
+127.0.0.1 localhost $name
+EOF
+
+ sed -i 's|.sbin.start_udev||' ${rootfs_path}/etc/rc.sysinit
+ sed -i 's|.sbin.start_udev||' ${rootfs_path}/etc/rc.d/rc.sysinit
+ # don't mount devpts, for pete's sake
+ sed -i 's/^.*dev.pts.*$/#\0/' ${rootfs_path}/etc/rc.sysinit
+ sed -i 's/^.*dev.pts.*$/#\0/' ${rootfs_path}/etc/rc.d/rc.sysinit
+
+ chroot ${rootfs_path} chkconfig udev-post off
+ chroot ${rootfs_path} chkconfig network on
+
+ dev_path="${rootfs_path}/dev"
+ rm -rf $dev_path
+ mkdir -p $dev_path
+ mknod -m 666 ${dev_path}/null c 1 3
+ mknod -m 666 ${dev_path}/zero c 1 5
+ mknod -m 666 ${dev_path}/random c 1 8
+ mknod -m 666 ${dev_path}/urandom c 1 9
+ mkdir -m 755 ${dev_path}/pts
+ mkdir -m 1777 ${dev_path}/shm
+ mknod -m 666 ${dev_path}/tty c 5 0
+ mknod -m 666 ${dev_path}/tty0 c 4 0
+ mknod -m 666 ${dev_path}/tty1 c 4 1
+ mknod -m 666 ${dev_path}/tty2 c 4 2
+ mknod -m 666 ${dev_path}/tty3 c 4 3
+ mknod -m 666 ${dev_path}/tty4 c 4 4
+ mknod -m 600 ${dev_path}/console c 5 1
+ mknod -m 666 ${dev_path}/full c 1 7
+ mknod -m 600 ${dev_path}/initctl p
+ mknod -m 666 ${dev_path}/ptmx c 5 2
+
+ echo "setting root passwd to $root_password"
+ echo "root:$root_password" | chroot $rootfs_path chpasswd
+
+ # specifying this in the initial packages doesn't always work.
+ echo "installing fedora-release package"
+ chroot ${rootfs_path} yum --releasever=${release} -y install fedora-release
+
+ # silence some needless startup errors
+ touch ${rootfs_path}/etc/fstab
+
+ # give us a console on /dev/console
+ sed -i 's/ACTIVE_CONSOLES=.*$/ACTIVE_CONSOLES="\/dev\/console \/dev\/tty[1-4]"/' \
+ ${rootfs_path}/etc/sysconfig/init
+
+ return 0
+}
+
+download_fedora()
+{
+
+ # check the mini fedora was not already downloaded
+ INSTALL_ROOT=$cache/partial
+ mkdir -p $INSTALL_ROOT
+ if [ $? -ne 0 ]; then
+ echo "Failed to create '$INSTALL_ROOT' directory"
+ return 1
+ fi
+
+ # download a mini fedora into a cache
+ echo "Downloading fedora minimal ..."
+ YUM="yum --installroot $INSTALL_ROOT -y --nogpgcheck"
+ PKG_LIST="yum initscripts passwd rsyslog vim-minimal dhclient chkconfig rootfiles policycoreutils fedora-release"
+ MIRRORLIST_URL="http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-$release&arch=$arch"
+
+ DOWNLOAD_OK=no
+ for trynumber in 1 2 3; do
+ [ $trynumber != 1 ] && echo "Trying again..."
+ MIRROR_URL=$(curl -s -S -f "$MIRRORLIST_URL" | head -n2 | tail -n1)
+ if [ $? -ne 0 ] || [ -z "$MIRROR_URL" ]; then
+ echo "Failed to get a mirror"
+ continue
+ fi
+ RELEASE_URL="$MIRROR_URL/Packages/fedora-release-$release-1.noarch.rpm"
+ echo "Fetching from $RELEASE_URL"
+ curl -f "$RELEASE_URL" > $INSTALL_ROOT/fedora-release-$release.noarch.rpm
+ if [ $? -ne 0 ]; then
+ echo "Failed to download fedora release rpm"
+ continue
+ fi
+ DOWNLOAD_OK=yes
+ break
+ done
+ if [ $DOWNLOAD_OK != yes ]; then
+ echo "Aborting"
+ return 1
+ fi
+
+ mkdir -p $INSTALL_ROOT/var/lib/rpm
+ rpm --root $INSTALL_ROOT --initdb
+ rpm --root $INSTALL_ROOT -ivh $INSTALL_ROOT/fedora-release-$release.noarch.rpm
+ $YUM install $PKG_LIST
+
+ if [ $? -ne 0 ]; then
+ echo "Failed to download the rootfs, aborting."
+ return 1
+ fi
+
+ mv "$INSTALL_ROOT" "$cache/rootfs"
+ echo "Download complete."
+
+ return 0
+}
+
+copy_fedora()
+{
+
+ # make a local copy of the minifedora
+ echo -n "Copying rootfs to $rootfs_path ..."
+ #cp -a $cache/rootfs-$arch $rootfs_path || return 1
+ # i prefer rsync (no reason really)
+ mkdir -p $rootfs_path
+ rsync -a $cache/rootfs/ $rootfs_path/
+ return 0
+}
+
+update_fedora()
+{
+ chroot $cache/rootfs yum -y update
+}
+
+install_fedora()
+{
+ mkdir -p /var/lock/subsys/
+ (
+ flock -x 200
+ if [ $? -ne 0 ]; then
+ echo "Cache repository is busy."
+ return 1
+ fi
+
+ echo "Checking cache download in $cache/rootfs ... "
+ if [ ! -e "$cache/rootfs" ]; then
+ download_fedora
+ if [ $? -ne 0 ]; then
+ echo "Failed to download 'fedora base'"
+ return 1
+ fi
+ else
+ echo "Cache found. Updating..."
+ update_fedora
+ if [ $? -ne 0 ]; then
+ echo "Failed to update 'fedora base', continuing with last known good cache"
+ else
+ echo "Update finished"
+ fi
+ fi
+
+ echo "Copy $cache/rootfs to $rootfs_path ... "
+ copy_fedora
+ if [ $? -ne 0 ]; then
+ echo "Failed to copy rootfs"
+ return 1
+ fi
+
+ return 0
+
+ ) 200>/var/lock/subsys/lxc
+
+ return $?
+}
+
+copy_configuration()
+{
+
+ mkdir -p $config_path
+ cat <<EOF >> $config_path/config
+lxc.utsname = $name
+lxc.tty = 4
+lxc.pts = 1024
+lxc.rootfs = $rootfs_path
+lxc.mount = $config_path/fstab
+
+# uncomment the next line to run the container unconfined:
+#lxc.aa_profile = unconfined
+
+#cgroups
+lxc.cgroup.devices.deny = a
+# /dev/null and zero
+lxc.cgroup.devices.allow = c 1:3 rwm
+lxc.cgroup.devices.allow = c 1:5 rwm
+# consoles
+lxc.cgroup.devices.allow = c 5:1 rwm
+lxc.cgroup.devices.allow = c 5:0 rwm
+lxc.cgroup.devices.allow = c 4:0 rwm
+lxc.cgroup.devices.allow = c 4:1 rwm
+# /dev/{,u}random
+lxc.cgroup.devices.allow = c 1:9 rwm
+lxc.cgroup.devices.allow = c 1:8 rwm
+lxc.cgroup.devices.allow = c 136:* rwm
+lxc.cgroup.devices.allow = c 5:2 rwm
+# rtc
+lxc.cgroup.devices.allow = c 254:0 rwm
+EOF
+
+ cat <<EOF > $config_path/fstab
+proc proc proc nodev,noexec,nosuid 0 0
+sysfs sys sysfs defaults 0 0
+EOF
+ if [ $? -ne 0 ]; then
+ echo "Failed to add configuration"
+ return 1
+ fi
+
+ return 0
+}
+
+clean()
+{
+
+ if [ ! -e $cache ]; then
+ exit 0
+ fi
+
+ # lock, so we won't purge while someone is creating a repository
+ (
+ flock -x 200
+ if [ $? != 0 ]; then
+ echo "Cache repository is busy."
+ exit 1
+ fi
+
+ echo -n "Purging the download cache for Fedora-$release..."
+ rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1
+ exit 0
+
+ ) 200>/var/lock/subsys/lxc
+}
+
+usage()
+{
+ cat <<EOF
+usage:
+ $1 -n|--name=<container_name>
+ [-p|--path=<path>] [-c|--clean] [-R|--release=<Fedora_release>] [-A|--arch=<arch of the container>]
+ [-h|--help]
+Mandatory args:
+ -n,--name container name, used to as an identifier for that container from now on
+Optional args:
+ -p,--path path to where the container rootfs will be created, defaults to /var/lib/lxc. The container config will go under /var/lib/lxc in that case
+ -c,--clean clean the cache
+ -R,--release Fedora release for the new container. if the host is Fedora, then it will defaultto the host's release.
+ -A,--arch NOT USED YET. Define what arch the container will be [i686,x86_64]
+ -h,--help print this help
+EOF
+ return 0
+}
+
+options=$(getopt -o hp:n:cR: -l help,path:,name:,clean,release: -- "$@")
+if [ $? -ne 0 ]; then
+ usage $(basename $0)
+ exit 1
+fi
+eval set -- "$options"
+
+while true
+do
+ case "$1" in
+ -h|--help) usage $0 && exit 0;;
+ -p|--path) path=$2; shift 2;;
+ -n|--name) name=$2; shift 2;;
+ -c|--clean) clean=$2; shift 2;;
+ -R|--release) release=$2; shift 2;;
+ --) shift 1; break ;;
+ *) break ;;
+ esac
+done
+
+if [ ! -z "$clean" -a -z "$path" ]; then
+ clean || exit 1
+ exit 0
+fi
+
+needed_pkgs=""
+type yum >/dev/null 2>&1
+if [ $? -ne 0 ]; then
+ needed_pkgs="yum $needed_pkgs"
+fi
+
+type curl >/dev/null 2>&1
+if [ $? -ne 0 ]; then
+ needed_pkgs="curl $needed_pkgs"
+fi
+
+if [ -n "$needed_pkgs" ]; then
+ echo "Missing commands: $needed_pkgs"
+ echo "Please install these using \"sudo apt-get install $needed_pkgs\""
+ exit 1
+fi
+
+if [ -z "$path" ]; then
+ path=$default_path
+fi
+
+if [ -z "$release" ]; then
+ if [ "$is_fedora" ]; then
+ release=$(cat /etc/fedora-release |awk '/^Fedora/ {print $3}')
+ else
+ echo "This is not a fedora host and release missing, defaulting to 14. use -R|--release to specify release"
+ release=14
+ fi
+fi
+
+if [ "$(id -u)" != "0" ]; then
+ echo "This script should be run as 'root'"
+ exit 1
+fi
+
+
+rootfs_path=$path/rootfs
+config_path=$default_path/$name
+cache=$cache_base/$release
+
+revert()
+{
+ echo "Interrupted, so cleaning up"
+ lxc-destroy -n $name
+ # maybe was interrupted before copy config
+ rm -rf $path/$name
+ rm -rf $default_path/$name
+ echo "exiting..."
+ exit 1
+}
+
+trap revert SIGHUP SIGINT SIGTERM
+
+copy_configuration
+if [ $? -ne 0 ]; then
+ echo "failed write configuration file"
+ exit 1
+fi
+
+install_fedora
+if [ $? -ne 0 ]; then
+ echo "failed to install fedora"
+ exit 1
+fi
+
+configure_fedora
+if [ $? -ne 0 ]; then
+ echo "failed to configure fedora for a container"
+ exit 1
+fi
+
+
+if [ ! -z $clean ]; then
+ clean || exit 1
+ exit 0
+fi
+echo "container rootfs and config created"
--- /dev/null
+#!/bin/bash
+
+#
+# template script for generating suse container for LXC
+#
+
+#
+# lxc: linux Container library
+
+# Authors:
+# Daniel Lezcano <daniel.lezcano@free.fr>
+# Frederic Crozat <fcrozat@suse.com>
+
+# 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
+
+DISTRO=11.4
+
+configure_opensuse()
+{
+ rootfs=$1
+ hostname=$2
+
+ # set network as static, but everything is done by LXC outside the container
+ cat <<EOF > $rootfs/etc/sysconfig/network/ifcfg-eth0
+STARTMODE='auto'
+BOOTPROTO='static'
+EOF
+
+ # set default route
+ IP=$(/sbin/ip route | awk '/default/ { print $3 }')
+ echo "default $IP - -" > $rootfs/etc/sysconfig/network/routes
+
+ # create empty fstab
+ touch $rootfs/etc/fstab
+
+ # create minimal /dev
+ mknod -m 666 $rootfs/dev/random c 1 8
+ mknod -m 666 $rootfs/dev/urandom c 1 9
+ mkdir -m 755 $rootfs/dev/pts
+ mkdir -m 1777 $rootfs/dev/shm
+ mknod -m 666 $rootfs/dev/tty c 5 0
+ mknod -m 600 $rootfs/dev/console c 5 1
+ mknod -m 666 $rootfs/dev/tty0 c 4 0
+ mknod -m 666 $rootfs/dev/tty1 c 4 1
+ mknod -m 666 $rootfs/dev/tty2 c 4 2
+ mknod -m 666 $rootfs/dev/tty3 c 4 3
+ mknod -m 666 $rootfs/dev/tty4 c 4 4
+ ln -s null $rootfs/dev/tty10
+ mknod -m 666 $rootfs/dev/full c 1 7
+ mknod -m 666 $rootfs/dev/ptmx c 5 2
+ ln -s /proc/self/fd $rootfs/dev/fd
+ ln -s /proc/kcore $rootfs/dev/core
+ mkdir -m 755 $rootfs/dev/mapper
+ mknod -m 600 $rootfs/dev/mapper/control c 10 60
+ mkdir -m 755 $rootfs/dev/net
+ mknod -m 666 $rootfs/dev/net/tun c 10 200
+
+ # set the hostname
+ cat <<EOF > $rootfs/etc/HOSTNAME
+$hostname
+EOF
+
+ # do not use hostname from HOSTNAME variable
+ cat <<EOF >> $rootfs/etc/sysconfig/cron
+unset HOSTNAME
+EOF
+
+ # set minimal hosts
+ cat <<EOF > $rootfs/etc/hosts
+127.0.0.1 localhost $hostname
+EOF
+
+ # disable various services
+ # disable yast->bootloader in container
+ cat <<EOF > $rootfs/etc/sysconfig/bootloader
+LOADER_TYPE=none
+LOADER_LOCATION=none
+EOF
+
+ # cut down inittab
+ cat <<EOF > $rootfs/etc/inittab
+id:3:initdefault:
+si::bootwait:/etc/init.d/boot
+l0:0:wait:/etc/init.d/rc 0
+l1:1:wait:/etc/init.d/rc 1
+l2:2:wait:/etc/init.d/rc 2
+l3:3:wait:/etc/init.d/rc 3
+l6:6:wait:/etc/init.d/rc 6
+ls:S:wait:/etc/init.d/rc S
+~~:S:respawn:/sbin/sulogin
+p6::ctrlaltdel:/sbin/init 6
+p0::powerfail:/sbin/init 0
+cons:2345:respawn:/sbin/mingetty --noclear console screen
+c1:2345:respawn:/sbin/mingetty --noclear tty1 screen
+EOF
+
+ # patch boot script, no longer needed in openSUSE 12.1 / SLE11-SP2
+ patch --quiet -d $rootfs/etc/init.d/ << EOF
+--- boot.orig 2011-05-26 16:03:07.000000000 +0200
++++ boot 2011-05-26 16:03:19.000000000 +0200
+@@ -98,12 +98,12 @@
+ echo "***************************************************************"
+ /sbin/halt -f
+ fi
+- echo -n "Mounting devtmpfs at /dev"
+- mount -n -t devtmpfs -o mode=0755 devtmpfs /dev
+- rc_status -v -r
++# echo -n "Mounting devtmpfs at /dev"
++# mount -n -t devtmpfs -o mode=0755 devtmpfs /dev
++# rc_status -v -r
+ fi
+
+-cp -axT --remove-destination /lib/udev/devices /dev
++#cp -axT --remove-destination /lib/udev/devices /dev
+
+ if test -d /sys/kernel/debug -a "$HAVE_DEBUGFS" = "1" ; then
+ mount -n -t debugfs debugfs /sys/kernel/debug > /dev/null 2>&1
+EOF
+ cat <<EOF >> $rootfs/etc/sysconfig/boot
+# disable root fsck
+ROOTFS_FSCK="0"
+ROOTFS_BLKDEV="/dev/null"
+EOF
+
+
+ # remove pointless services in a container
+ insserv -r -f -p $rootfs/etc/init.d boot.udev boot.udev_retry boot.md boot.lvm boot.loadmodules boot.device-mapper boot.clock boot.swap boot.klog
+
+ echo "Please change root-password !"
+ echo "root:root" | chroot $rootfs chpasswd
+
+ return 0
+}
+
+download_opensuse()
+{
+ cache=$1
+ arch=$2
+
+ # check the mini opensuse was not already downloaded
+ mkdir -p "$cache/partial-$arch"
+
+ if [ $? -ne 0 ]; then
+ echo "Failed to create '$cache/partial-$arch' directory"
+ return 1
+ fi
+
+ # download a mini opensuse into a cache
+ echo "Downloading opensuse minimal ..."
+ mkdir -p "$cache/partial-$arch/dev"
+ mknod -m 666 $cache/partial-$arch/dev/null c 1 3
+ mknod -m 666 $cache/partial-$arch/dev/zero c 1 5
+ zypper --quiet --root $cache/partial-$arch --non-interactive ar http://download.opensuse.org/distribution/$DISTRO/repo/oss/ repo-oss
+ zypper --quiet --root $cache/partial-$arch --non-interactive ar http://download.opensuse.org/update/$DISTRO/ update
+ zypper --quiet --root $cache/partial-$arch --non-interactive --gpg-auto-import-keys in --auto-agree-with-licenses -t pattern base
+ zypper --quiet --root $cache/partial-$arch --non-interactive --gpg-auto-import-keys in +lxc -kbd -patterns-openSUSE-base
+ if [ $? -ne 0 ]; then
+ echo "Failed to download the rootfs, aborting."
+ return 1
+ fi
+
+ mv "$1/partial-$arch" "$1/rootfs-$arch"
+ echo "Download complete."
+
+ return 0
+}
+
+copy_opensuse()
+{
+ cache=$1
+ arch=$2
+ rootfs=$3
+
+ # make a local copy of the mini opensuse
+ echo -n "Copying rootfs to $rootfs ..."
+ mkdir -p $rootfs
+ rsync -a $cache/rootfs-$arch/ $rootfs/ || return 1
+ return 0
+}
+
+install_opensuse()
+{
+ cache="/var/cache/lxc/opensuse"
+ rootfs=$1
+ mkdir -p /var/lock/subsys/
+ (
+ flock -x 200
+ if [ $? -ne 0 ]; then
+ echo "Cache repository is busy."
+ return 1
+ fi
+
+ arch=$(arch)
+
+ echo "Checking cache download in $cache/rootfs-$arch ... "
+ if [ ! -e "$cache/rootfs-$arch" ]; then
+ download_opensuse $cache $arch
+ if [ $? -ne 0 ]; then
+ echo "Failed to download 'opensuse base'"
+ return 1
+ fi
+ fi
+
+ echo "Copy $cache/rootfs-$arch to $rootfs ... "
+ copy_opensuse $cache $arch $rootfs
+ if [ $? -ne 0 ]; then
+ echo "Failed to copy rootfs"
+ return 1
+ fi
+
+ return 0
+
+ ) 200>/var/lock/subsys/lxc
+
+ return $?
+}
+
+copy_configuration()
+{
+ path=$1
+ rootfs=$2
+ name=$3
+
+ cat <<EOF >> $path/config
+lxc.utsname = $name
+
+lxc.tty = 4
+lxc.pts = 1024
+lxc.rootfs = $rootfs
+lxc.mount = $path/fstab
+# uncomment the next line to run the container unconfined:
+#lxc.aa_profile = unconfined
+
+lxc.cgroup.devices.deny = a
+# /dev/null and zero
+lxc.cgroup.devices.allow = c 1:3 rwm
+lxc.cgroup.devices.allow = c 1:5 rwm
+# consoles
+lxc.cgroup.devices.allow = c 5:1 rwm
+lxc.cgroup.devices.allow = c 5:0 rwm
+lxc.cgroup.devices.allow = c 4:0 rwm
+lxc.cgroup.devices.allow = c 4:1 rwm
+# /dev/{,u}random
+lxc.cgroup.devices.allow = c 1:9 rwm
+lxc.cgroup.devices.allow = c 1:8 rwm
+lxc.cgroup.devices.allow = c 136:* rwm
+lxc.cgroup.devices.allow = c 5:2 rwm
+# rtc
+lxc.cgroup.devices.allow = c 254:0 rwm
+EOF
+
+ cat <<EOF > $path/fstab
+proc proc proc nodev,noexec,nosuid 0 0
+sysfs sys sysfs defaults 0 0
+EOF
+
+ if [ $? -ne 0 ]; then
+ echo "Failed to add configuration"
+ return 1
+ fi
+
+ return 0
+}
+
+clean()
+{
+ cache="/var/cache/lxc/opensuse"
+
+ if [ ! -e $cache ]; then
+ exit 0
+ fi
+
+ # lock, so we won't purge while someone is creating a repository
+ (
+ flock -x 200
+ if [ $? != 0 ]; then
+ echo "Cache repository is busy."
+ exit 1
+ fi
+
+ echo -n "Purging the download cache..."
+ rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1
+ exit 0
+
+ ) 200>/var/lock/subsys/lxc
+}
+
+usage()
+{
+ cat <<EOF
+$1 -h|--help -p|--path=<path> --clean
+EOF
+ return 0
+}
+
+options=$(getopt -o hp:n:c -l help,path:,name:,clean -- "$@")
+if [ $? -ne 0 ]; then
+ usage $(basename $0)
+ exit 1
+fi
+eval set -- "$options"
+
+while true
+do
+ case "$1" in
+ -h|--help) usage $0 && exit 0;;
+ -p|--path) path=$2; shift 2;;
+ -n|--name) name=$2; shift 2;;
+ -c|--clean) clean=$2; shift 2;;
+ --) shift 1; break ;;
+ *) break ;;
+ esac
+done
+
+if [ ! -z "$clean" -a -z "$path" ]; then
+ clean || exit 1
+ exit 0
+fi
+
+type zypper > /dev/null
+if [ $? -ne 0 ]; then
+ echo "'zypper' command is missing"
+ exit 1
+fi
+
+if [ -z "$path" ]; then
+ echo "'path' parameter is required"
+ exit 1
+fi
+
+if [ "$(id -u)" != "0" ]; then
+ echo "This script should be run as 'root'"
+ exit 1
+fi
+
+rootfs=$path/rootfs
+
+install_opensuse $rootfs
+if [ $? -ne 0 ]; then
+ echo "failed to install opensuse"
+ exit 1
+fi
+
+configure_opensuse $rootfs $name
+if [ $? -ne 0 ]; then
+ echo "failed to configure opensuse for a container"
+ exit 1
+fi
+
+copy_configuration $path $rootfs $name
+if [ $? -ne 0 ]; then
+ echo "failed write configuration file"
+ exit 1
+fi
+
+if [ ! -z $clean ]; then
+ clean || exit 1
+ exit 0
+fi
--- /dev/null
+#!/bin/bash
+
+#
+# lxc: linux Container library
+
+# Authors:
+# Daniel Lezcano <daniel.lezcano@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
+
+install_sshd()
+{
+ rootfs=$1
+
+ tree="\
+$rootfs/var/run/sshd \
+$rootfs/var/empty/sshd \
+$rootfs/var/lib/empty/sshd \
+$rootfs/etc/ssh \
+$rootfs/dev/shm \
+$rootfs/run/shm \
+$rootfs/proc \
+$rootfs/bin \
+$rootfs/sbin \
+$rootfs/usr \
+$rootfs/tmp \
+$rootfs/home \
+$rootfs/root \
+$rootfs/lib \
+$rootfs/lib64"
+
+ mkdir -p $tree
+ if [ $? -ne 0 ]; then
+ return 1
+ fi
+
+ return 0
+}
+
+configure_sshd()
+{
+ rootfs=$1
+
+ cat <<EOF > $rootfs/etc/passwd
+root:x:0:0:root:/root:/bin/bash
+sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
+EOF
+
+ cat <<EOF > $rootfs/etc/group
+root:x:0:root
+sshd:x:74:
+EOF
+
+ssh-keygen -t rsa -f $rootfs/etc/ssh/ssh_host_rsa_key
+ssh-keygen -t dsa -f $rootfs/etc/ssh/ssh_host_dsa_key
+
+ # by default setup root password with no password
+ cat <<EOF > $rootfs/etc/ssh/sshd_config
+Port 22
+Protocol 2
+HostKey /etc/ssh/ssh_host_rsa_key
+HostKey /etc/ssh/ssh_host_dsa_key
+UsePrivilegeSeparation yes
+KeyRegenerationInterval 3600
+ServerKeyBits 768
+SyslogFacility AUTH
+LogLevel INFO
+LoginGraceTime 120
+PermitRootLogin yes
+StrictModes yes
+RSAAuthentication yes
+PubkeyAuthentication yes
+IgnoreRhosts yes
+RhostsRSAAuthentication no
+HostbasedAuthentication no
+PermitEmptyPasswords yes
+ChallengeResponseAuthentication no
+EOF
+
+ if [ -n "$auth_key" -a -f "$auth_key" ]; then
+ u_path="/root/.ssh"
+ root_u_path="$rootfs/$u_path"
+ mkdir -p $root_u_path
+ cp $auth_key "$root_u_path/authorized_keys"
+ chown -R 0:0 "$rootfs/$u_path"
+ chmod 700 "$rootfs/$u_path"
+
+ echo "Inserted SSH public key from $auth_key into /home/ubuntu/.ssh/authorized_keys"
+ fi
+
+ return 0
+}
+
+copy_configuration()
+{
+ path=$1
+ rootfs=$2
+ name=$3
+
+ cat <<EOF >> $path/config
+lxc.utsname = $name
+lxc.pts = 1024
+lxc.rootfs = $rootfs
+# uncomment the next line to run the container unconfined:
+#lxc.aa_profile = unconfined
+lxc.mount.entry=/dev dev none ro,bind 0 0
+lxc.mount.entry=/lib lib none ro,bind 0 0
+lxc.mount.entry=/bin bin none ro,bind 0 0
+lxc.mount.entry=/usr usr none ro,bind 0 0
+lxc.mount.entry=/sbin sbin none ro,bind 0 0
+lxc.mount.entry=tmpfs var/run/sshd tmpfs mode=0644 0 0
+lxc.mount.entry=/usr/lib/lxc/templates/lxc-sshd sbin/init none bind 0 0
+lxc.mount.entry=proc proc proc nodev,noexec,nosuid 0 0
+EOF
+
+ # if no .ipv4 section in config, then have the container run dhcp
+ grep -q "^lxc.network.ipv4" $path/config || touch $rootfs/run-dhcp
+
+ if [ "$(uname -m)" = "x86_64" ]; then
+ cat <<EOF >> $path/config
+lxc.mount.entry=/lib64 lib64 none ro,bind 0 0
+EOF
+ fi
+}
+
+usage()
+{
+ cat <<EOF
+$1 -h|--help -p|--path=<path>
+EOF
+ return 0
+}
+
+options=$(getopt -o hp:n:S: -l help,path:,name:,auth-key: -- "$@")
+if [ $? -ne 0 ]; then
+ usage $(basename $0)
+ exit 1
+fi
+eval set -- "$options"
+
+while true
+do
+ case "$1" in
+ -h|--help) usage $0 && exit 0;;
+ -p|--path) path=$2; shift 2;;
+ -n|--name) name=$2; shift 2;;
+ -S|--auth-key) auth_key=$2; shift 2;;
+ --) shift 1; break ;;
+ *) break ;;
+ esac
+done
+
+if [ "$(id -u)" != "0" ]; then
+ echo "This script should be run as 'root'"
+ exit 1
+fi
+
+if [ $0 == "/sbin/init" ]; then
+
+ type /usr/lib/lxc/lxc-init
+ if [ $? -ne 0 ]; then
+ echo "'lxc-init is not accessible on the system"
+ exit 1
+ fi
+
+ type sshd
+ if [ $? -ne 0 ]; then
+ echo "'sshd' is not accessible on the system "
+ exit 1
+ fi
+
+ # run dhcp?
+ if [ -f /run-dhcp ]; then
+ type dhclient
+ if [ $? -ne 0 ]; then
+ echo "can't find dhclient"
+ exit 1
+ fi
+ touch /etc/fstab
+ rm -f /dhclient.conf
+ cat > /dhclient.conf << EOF
+send host-name "<hostname>";
+EOF
+ ifconfig eth0 up
+ dhclient eth0 -cf /dhclient.conf
+ fi
+
+ exec /usr/lib/lxc/lxc-init -- /usr/sbin/sshd
+ exit 1
+fi
+
+if [ -z "$path" ]; then
+ echo "'path' parameter is required"
+ exit 1
+fi
+
+rootfs=$path/rootfs
+
+install_sshd $rootfs
+if [ $? -ne 0 ]; then
+ echo "failed to install sshd's rootfs"
+ exit 1
+fi
+
+configure_sshd $rootfs
+if [ $? -ne 0 ]; then
+ echo "failed to configure sshd template"
+ exit 1
+fi
+
+copy_configuration $path $rootfs $name
+if [ $? -ne 0 ]; then
+ echo "failed to write configuration file"
+ exit 1
+fi
--- /dev/null
+#!/bin/bash
+
+#
+# template script for generating ubuntu container for LXC
+#
+# This script consolidates and extends the existing lxc ubuntu scripts
+#
+
+# Copyright © 2011 Serge Hallyn <serge.hallyn@canonical.com>
+# Copyright © 2010 Wilhelm Meier
+# Author: Wilhelm Meier <wilhelm.meier@fh-kl.de>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2, as
+# published by the Free Software Foundation.
+
+# 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, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+
+set -e
+
+if [ -r /etc/default/lxc ]; then
+ . /etc/default/lxc
+fi
+
+configure_ubuntu()
+{
+ rootfs=$1
+ hostname=$2
+ release=$3
+
+ # configure the network using the dhcp
+ cat <<EOF > $rootfs/etc/network/interfaces
+# This file describes the network interfaces available on your system
+# and how to activate them. For more information, see interfaces(5).
+
+# The loopback network interface
+auto lo
+iface lo inet loopback
+
+auto eth0
+iface eth0 inet dhcp
+EOF
+
+ # set the hostname
+ cat <<EOF > $rootfs/etc/hostname
+$hostname
+EOF
+ # set minimal hosts
+ cat <<EOF > $rootfs/etc/hosts
+127.0.0.1 localhost
+127.0.1.1 $hostname
+
+# The following lines are desirable for IPv6 capable hosts
+::1 ip6-localhost ip6-loopback
+fe00::0 ip6-localnet
+ff00::0 ip6-mcastprefix
+ff02::1 ip6-allnodes
+ff02::2 ip6-allrouters
+EOF
+
+ if [ ! -f $rootfs/etc/init/container-detect.conf ]; then
+ # suppress log level output for udev
+ sed -i "s/=\"err\"/=0/" $rootfs/etc/udev/udev.conf
+
+ # remove jobs for consoles 5 and 6 since we only create 4 consoles in
+ # this template
+ rm -f $rootfs/etc/init/tty{5,6}.conf
+ fi
+
+ if [ -z "$bindhome" ]; then
+ chroot $rootfs useradd --create-home -s /bin/bash ubuntu
+ echo "ubuntu:ubuntu" | chroot $rootfs chpasswd
+ fi
+
+ return 0
+}
+
+# finish setting up the user in the container by injecting ssh key and
+# adding sudo group membership.
+# passed-in user is either 'ubuntu' or the user to bind in from host.
+finalize_user()
+{
+ user=$1
+
+ sudo_version=$(chroot $rootfs dpkg-query -W -f='${Version}' sudo)
+
+ if chroot $rootfs dpkg --compare-versions $sudo_version gt "1.8.3p1-1"; then
+ groups="sudo"
+ else
+ groups="sudo admin"
+ fi
+
+ for group in $groups; do
+ chroot $rootfs groupadd --system $group >/dev/null 2>&1 || true
+ chroot $rootfs adduser ${user} $group >/dev/null 2>&1 || true
+ done
+
+ if [ -n "$auth_key" -a -f "$auth_key" ]; then
+ u_path="/home/${user}/.ssh"
+ root_u_path="$rootfs/$u_path"
+
+ mkdir -p $root_u_path
+ cp $auth_key "$root_u_path/authorized_keys"
+ chroot $rootfs chown -R ${user}: "$u_path"
+
+ echo "Inserted SSH public key from $auth_key into /home/${user}/.ssh/authorized_keys"
+ fi
+ return 0
+}
+
+write_sourceslist()
+{
+ # $1 => path to the rootfs
+ # $2 => architecture we want to add
+ # $3 => whether to use the multi-arch syntax or not
+
+ case $2 in
+ amd64|i386)
+ MIRROR=${MIRROR:-http://archive.ubuntu.com/ubuntu}
+ SECURITY_MIRROR=${SECURITY_MIRROR:-http://security.ubuntu.com/ubuntu}
+ ;;
+ *)
+ MIRROR=${MIRROR:-http://ports.ubuntu.com/ubuntu-ports}
+ SECURITY_MIRROR=${SECURITY_MIRROR:-http://ports.ubuntu.com/ubuntu-ports}
+ ;;
+ esac
+ if [ -n "$3" ]; then
+ cat >> "$1/etc/apt/sources.list" << EOF
+deb [arch=$2] $MIRROR ${release} main restricted universe multiverse
+deb [arch=$2] $MIRROR ${release}-updates main restricted universe multiverse
+deb [arch=$2] $SECURITY_MIRROR ${release}-security main restricted universe multiverse
+EOF
+ else
+ cat >> "$1/etc/apt/sources.list" << EOF
+deb $MIRROR ${release} main restricted universe multiverse
+deb $MIRROR ${release}-updates main restricted universe multiverse
+deb $SECURITY_MIRROR ${release}-security main restricted universe multiverse
+EOF
+ fi
+}
+
+download_ubuntu()
+{
+ cache=$1
+ arch=$2
+ release=$3
+
+ packages=vim,ssh
+ echo "installing packages: $packages"
+
+ # check the mini ubuntu was not already downloaded
+ mkdir -p "$cache/partial-$arch"
+ if [ $? -ne 0 ]; then
+ echo "Failed to create '$cache/partial-$arch' directory"
+ return 1
+ fi
+
+ # download a mini ubuntu into a cache
+ echo "Downloading ubuntu $release minimal ..."
+ if [ -n "$(which qemu-debootstrap)" ]; then
+ qemu-debootstrap --verbose --components=main,universe --arch=$arch --include=$packages $release $cache/partial-$arch $MIRROR
+ else
+ debootstrap --verbose --components=main,universe --arch=$arch --include=$packages $release $cache/partial-$arch $MIRROR
+ fi
+
+ if [ $? -ne 0 ]; then
+ echo "Failed to download the rootfs, aborting."
+ return 1
+ fi
+
+ # Serge isn't sure whether we should avoid doing this when
+ # $release == `distro-info -d`
+ echo "Installing updates"
+ > $cache/partial-$arch/etc/apt/sources.list
+ write_sourceslist $cache/partial-$arch/ $arch
+
+ chroot "$1/partial-${arch}" apt-get update
+ if [ $? -ne 0 ]; then
+ echo "Failed to update the apt cache"
+ return 1
+ fi
+ cat > "$1/partial-${arch}"/usr/sbin/policy-rc.d << EOF
+#!/bin/sh
+exit 101
+EOF
+ chmod +x "$1/partial-${arch}"/usr/sbin/policy-rc.d
+
+ lxc-unshare -s MOUNT -- chroot "$1/partial-${arch}" apt-get dist-upgrade -y
+ ret=$?
+ rm -f "$1/partial-${arch}"/usr/sbin/policy-rc.d
+
+ if [ $ret -ne 0 ]; then
+ echo "Failed to upgrade the cache"
+ return 1
+ fi
+
+ mv "$1/partial-$arch" "$1/rootfs-$arch"
+ echo "Download complete"
+ return 0
+}
+
+copy_ubuntu()
+{
+ cache=$1
+ arch=$2
+ rootfs=$3
+
+ # make a local copy of the miniubuntu
+ echo "Copying rootfs to $rootfs ..."
+ mkdir -p $rootfs
+ rsync -a $cache/rootfs-$arch/ $rootfs/ || return 1
+ return 0
+}
+
+install_ubuntu()
+{
+ rootfs=$1
+ release=$2
+ flushcache=$3
+ cache="/var/cache/lxc/$release"
+ mkdir -p /var/lock/subsys/
+
+ (
+ flock -x 200
+ if [ $? -ne 0 ]; then
+ echo "Cache repository is busy."
+ return 1
+ fi
+
+
+ if [ $flushcache -eq 1 ]; then
+ echo "Flushing cache..."
+ rm -rf "$cache/partial-$arch"
+ rm -rf "$cache/rootfs-$arch"
+ fi
+
+ echo "Checking cache download in $cache/rootfs-$arch ... "
+ if [ ! -e "$cache/rootfs-$arch" ]; then
+ download_ubuntu $cache $arch $release
+ if [ $? -ne 0 ]; then
+ echo "Failed to download 'ubuntu $release base'"
+ return 1
+ fi
+ fi
+
+ echo "Copy $cache/rootfs-$arch to $rootfs ... "
+ copy_ubuntu $cache $arch $rootfs
+ if [ $? -ne 0 ]; then
+ echo "Failed to copy rootfs"
+ return 1
+ fi
+
+ return 0
+
+ ) 200>/var/lock/subsys/lxc
+
+ return $?
+}
+
+copy_configuration()
+{
+ path=$1
+ rootfs=$2
+ name=$3
+ arch=$4
+ release=$5
+
+ if [ $arch = "i386" ]; then
+ arch="i686"
+ fi
+
+ ttydir=""
+ if [ -f $rootfs/etc/init/container-detect.conf ]; then
+ ttydir=" lxc"
+ fi
+
+ # if there is exactly one veth network entry, make sure it has an
+ # associated hwaddr.
+ nics=`grep -e '^lxc\.network\.type[ \t]*=[ \t]*veth' $path/config | wc -l`
+ if [ $nics -eq 1 ]; then
+ grep -q "^lxc.network.hwaddr" $path/config || cat <<EOF >> $path/config
+lxc.network.hwaddr = 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')
+EOF
+ fi
+
+ cat <<EOF >> $path/config
+lxc.utsname = $name
+
+lxc.devttydir =$ttydir
+lxc.tty = 4
+lxc.pts = 1024
+lxc.rootfs = $rootfs
+lxc.mount = $path/fstab
+lxc.arch = $arch
+lxc.cap.drop = sys_module mac_admin
+lxc.pivotdir = lxc_putold
+
+# uncomment the next line to run the container unconfined:
+#lxc.aa_profile = unconfined
+
+lxc.cgroup.devices.deny = a
+# Allow any mknod (but not using the node)
+lxc.cgroup.devices.allow = c *:* m
+lxc.cgroup.devices.allow = b *:* m
+# /dev/null and zero
+lxc.cgroup.devices.allow = c 1:3 rwm
+lxc.cgroup.devices.allow = c 1:5 rwm
+# consoles
+lxc.cgroup.devices.allow = c 5:1 rwm
+lxc.cgroup.devices.allow = c 5:0 rwm
+#lxc.cgroup.devices.allow = c 4:0 rwm
+#lxc.cgroup.devices.allow = c 4:1 rwm
+# /dev/{,u}random
+lxc.cgroup.devices.allow = c 1:9 rwm
+lxc.cgroup.devices.allow = c 1:8 rwm
+lxc.cgroup.devices.allow = c 136:* rwm
+lxc.cgroup.devices.allow = c 5:2 rwm
+# rtc
+lxc.cgroup.devices.allow = c 254:0 rwm
+#fuse
+lxc.cgroup.devices.allow = c 10:229 rwm
+#tun
+lxc.cgroup.devices.allow = c 10:200 rwm
+#full
+lxc.cgroup.devices.allow = c 1:7 rwm
+#hpet
+lxc.cgroup.devices.allow = c 10:228 rwm
+#kvm
+lxc.cgroup.devices.allow = c 10:232 rwm
+EOF
+
+ cat <<EOF > $path/fstab
+proc proc proc nodev,noexec,nosuid 0 0
+sysfs sys sysfs defaults 0 0
+EOF
+
+ if [ $? -ne 0 ]; then
+ echo "Failed to add configuration"
+ return 1
+ fi
+
+ return 0
+}
+
+trim()
+{
+ rootfs=$1
+ release=$2
+
+ # provide the lxc service
+ cat <<EOF > $rootfs/etc/init/lxc.conf
+# fake some events needed for correct startup other services
+
+description "Container Upstart"
+
+start on startup
+
+script
+ rm -rf /var/run/*.pid
+ rm -rf /var/run/network/*
+ /sbin/initctl emit stopped JOB=udevtrigger --no-wait
+ /sbin/initctl emit started JOB=udev --no-wait
+end script
+EOF
+
+ # fix buggus runlevel with sshd
+ cat <<EOF > $rootfs/etc/init/ssh.conf
+# ssh - OpenBSD Secure Shell server
+#
+# The OpenSSH server provides secure shell access to the system.
+
+description "OpenSSH server"
+
+start on filesystem
+stop on runlevel [!2345]
+
+expect fork
+respawn
+respawn limit 10 5
+umask 022
+# replaces SSHD_OOM_ADJUST in /etc/default/ssh
+oom never
+
+pre-start script
+ test -x /usr/sbin/sshd || { stop; exit 0; }
+ test -e /etc/ssh/sshd_not_to_be_run && { stop; exit 0; }
+ test -c /dev/null || { stop; exit 0; }
+
+ mkdir -p -m0755 /var/run/sshd
+end script
+
+# if you used to set SSHD_OPTS in /etc/default/ssh, you can change the
+# 'exec' line here instead
+exec /usr/sbin/sshd
+EOF
+
+ cat <<EOF > $rootfs/etc/init/console.conf
+# console - getty
+#
+# This service maintains a console on tty1 from the point the system is
+# started until it is shut down again.
+
+start on stopped rc RUNLEVEL=[2345]
+stop on runlevel [!2345]
+
+respawn
+exec /sbin/getty -8 38400 /dev/console
+EOF
+
+ cat <<EOF > $rootfs/lib/init/fstab
+# /lib/init/fstab: cleared out for bare-bones lxc
+EOF
+
+ # reconfigure some services
+ if [ -z "$LANG" ]; then
+ chroot $rootfs locale-gen en_US.UTF-8
+ chroot $rootfs update-locale LANG=en_US.UTF-8
+ else
+ chroot $rootfs locale-gen $LANG
+ chroot $rootfs update-locale LANG=$LANG
+ fi
+
+ # remove pointless services in a container
+ chroot $rootfs /usr/sbin/update-rc.d -f ondemand remove
+
+ chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls u*.conf); do mv $f $f.orig; done'
+ chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls tty[2-9].conf); do mv $f $f.orig; done'
+ chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls plymouth*.conf); do mv $f $f.orig; done'
+ chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls hwclock*.conf); do mv $f $f.orig; done'
+ chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls module*.conf); do mv $f $f.orig; done'
+
+ # if this isn't lucid, then we need to twiddle the network upstart bits :(
+ if [ $release != "lucid" ]; then
+ sed -i 's/^.*emission handled.*$/echo Emitting lo/' $rootfs/etc/network/if-up.d/upstart
+ fi
+}
+
+post_process()
+{
+ rootfs=$1
+ release=$2
+ trim_container=$3
+
+ if [ $trim_container -eq 1 ]; then
+ trim $rootfs $release
+ elif [ ! -f $rootfs/etc/init/container-detect.conf ]; then
+ # Make sure we have a working resolv.conf
+ cresolvonf="${rootfs}/etc/resolv.conf"
+ mv $cresolvonf ${cresolvonf}.lxcbak
+ cat /etc/resolv.conf > ${cresolvonf}
+
+ # for lucid, if not trimming, then add the ubuntu-virt
+ # ppa and install lxcguest
+ if [ $release = "lucid" ]; then
+ chroot $rootfs apt-get install --force-yes -y python-software-properties
+ chroot $rootfs add-apt-repository ppa:ubuntu-virt/ppa
+ fi
+
+ chroot $rootfs apt-get update
+ chroot $rootfs apt-get install --force-yes -y lxcguest
+
+ # Restore old resolv.conf
+ rm -f ${cresolvonf}
+ mv ${cresolvonf}.lxcbak ${cresolvonf}
+ fi
+
+ # If the container isn't running a native architecture, setup multiarch
+ if [ -x "$(ls -1 ${rootfs}/usr/bin/qemu-*-static 2>/dev/null)" ]; then
+ dpkg_version=$(chroot $rootfs dpkg-query -W -f='${Version}' dpkg)
+ if chroot $rootfs dpkg --compare-versions $dpkg_version ge "1.16.2"; then
+ chroot $rootfs dpkg --add-architecture ${hostarch}
+ else
+ mkdir -p ${rootfs}/etc/dpkg/dpkg.cfg.d
+ echo "foreign-architecture ${hostarch}" > ${rootfs}/etc/dpkg/dpkg.cfg.d/lxc-multiarch
+ fi
+
+ # Save existing value of MIRROR and SECURITY_MIRROR
+ DEFAULT_MIRROR=$MIRROR
+ DEFAULT_SECURITY_MIRROR=$SECURITY_MIRROR
+
+ # Write a new sources.list containing both native and multiarch entries
+ > ${rootfs}/etc/apt/sources.list
+ write_sourceslist $rootfs $arch "native"
+
+ MIRROR=$DEFAULT_MIRROR
+ SECURITY_MIRROR=$DEFAULT_SECURITY_MIRROR
+ write_sourceslist $rootfs $hostarch "multiarch"
+
+ # Finally update the lists and install upstart using the host architecture
+ chroot $rootfs apt-get update
+ chroot $rootfs apt-get install --force-yes -y --no-install-recommends upstart:${hostarch} mountall:${hostarch} iproute:${hostarch} isc-dhcp-client:${hostarch}
+ fi
+
+ # rmdir /dev/shm for containers that have /run/shm
+ # I'm afraid of doing rm -rf $rootfs/dev/shm, in case it did
+ # get bind mounted to the host's /run/shm. So try to rmdir
+ # it, and in case that fails move it out of the way.
+ if [ ! -L $rootfs/dev/shm ] && [ -d $rootfs/run/shm ] && [ -e $rootfs/dev/shm ]; then
+ mv $rootfs/dev/shm $rootfs/dev/shm.bak
+ ln -s /run/shm $rootfs/dev/shm
+ fi
+}
+
+do_bindhome()
+{
+ rootfs=$1
+ user=$2
+
+ # copy /etc/passwd, /etc/shadow, and /etc/group entries into container
+ pwd=`getent passwd $user` || { echo "Failed to copy password entry for $user"; false; }
+ echo $pwd >> $rootfs/etc/passwd
+
+ # make sure user's shell exists in the container
+ shell=`echo $pwd | cut -d: -f 7`
+ if [ ! -x $rootfs/$shell ]; then
+ echo "shell $shell for user $user was not found in the container."
+ pkg=`dpkg -S $(readlink -m $shell) | cut -d ':' -f1`
+ echo "Installing $pkg"
+ chroot $rootfs apt-get --force-yes -y install $pkg
+ fi
+
+ shad=`getent shadow $user`
+ echo "$shad" >> $rootfs/etc/shadow
+
+ # bind-mount the user's path into the container's /home
+ h=`getent passwd $user | cut -d: -f 6`
+ mkdir -p $rootfs/$h
+
+ # use relative path in container
+ h2=${h#/}
+ while [ ${h2:0:1} = "/" ]; do
+ h2=${h2#/}
+ done
+ echo "$h $h2 none bind 0 0" >> $path/fstab
+
+ # Make sure the group exists in container
+ grp=`echo $pwd | cut -d: -f 4` # group number for $user
+ grpe=`getent group $grp` || return 0 # if host doesn't define grp, ignore in container
+ chroot $rootfs getent group "$grpe" || echo "$grpe" >> $rootfs/etc/group
+}
+
+usage()
+{
+ cat <<EOF
+$1 -h|--help [-a|--arch] [-b|--bindhome <user>] [--trim] [-d|--debug]
+ [-F | --flush-cache] [-r|--release <release>] [ -S | --auth-key <keyfile>]
+release: the ubuntu release (e.g. precise): defaults to host release on ubuntu, otherwise uses latest LTS
+trim: make a minimal (faster, but not upgrade-safe) container
+bindhome: bind <user>'s home into the container
+ The ubuntu user will not be created, and <user> will have
+ sudo access.
+arch: the container architecture (e.g. amd64): defaults to host arch
+auth-key: SSH Public key file to inject into container
+EOF
+ return 0
+}
+
+options=$(getopt -o a:b:hp:r:xn:FS:d -l arch:,bindhome:,help,path:,release:,trim,name:,flush-cache,auth-key:,debug -- "$@")
+if [ $? -ne 0 ]; then
+ usage $(basename $0)
+ exit 1
+fi
+eval set -- "$options"
+
+release=precise # Default to the last Ubuntu LTS release for non-Ubuntu systems
+if [ -f /etc/lsb-release ]; then
+ . /etc/lsb-release
+ if [ "$DISTRIB_ID" = "Ubuntu" ]; then
+ release=$DISTRIB_CODENAME
+ fi
+fi
+
+bindhome=
+arch=$(arch)
+
+# Code taken from debootstrap
+if [ -x /usr/bin/dpkg ] && /usr/bin/dpkg --print-architecture >/dev/null 2>&1; then
+ arch=`/usr/bin/dpkg --print-architecture`
+elif type udpkg >/dev/null 2>&1 && udpkg --print-architecture >/dev/null 2>&1; then
+ arch=`/usr/bin/udpkg --print-architecture`
+else
+ arch=$(arch)
+ if [ "$arch" = "i686" ]; then
+ arch="i386"
+ elif [ "$arch" = "x86_64" ]; then
+ arch="amd64"
+ elif [ "$arch" = "armv7l" ]; then
+ arch="armel"
+ fi
+fi
+
+debug=0
+trim_container=0
+hostarch=$arch
+flushcache=0
+while true
+do
+ case "$1" in
+ -h|--help) usage $0 && exit 0;;
+ -p|--path) path=$2; shift 2;;
+ -n|--name) name=$2; shift 2;;
+ -F|--flush-cache) flushcache=1; shift 1;;
+ -r|--release) release=$2; shift 2;;
+ -b|--bindhome) bindhome=$2; shift 2;;
+ -a|--arch) arch=$2; shift 2;;
+ -x|--trim) trim_container=1; shift 1;;
+ -S|--auth-key) auth_key=$2; shift 2;;
+ -d|--debug) debug=1; shift 1;;
+ --) shift 1; break ;;
+ *) break ;;
+ esac
+done
+
+if [ $debug -eq 1 ]; then
+ set -x
+fi
+
+if [ -n "$bindhome" ]; then
+ pwd=`getent passwd $bindhome`
+ if [ $? -ne 0 ]; then
+ echo "Error: no password entry found for $bindhome"
+ exit 1
+ fi
+fi
+
+
+if [ "$arch" == "i686" ]; then
+ arch=i386
+fi
+
+if [ $hostarch = "i386" -a $arch = "amd64" ]; then
+ echo "can't create amd64 container on i386"
+ exit 1
+fi
+
+type debootstrap
+if [ $? -ne 0 ]; then
+ echo "'debootstrap' command is missing"
+ exit 1
+fi
+
+if [ -z "$path" ]; then
+ echo "'path' parameter is required"
+ exit 1
+fi
+
+if [ "$(id -u)" != "0" ]; then
+ echo "This script should be run as 'root'"
+ exit 1
+fi
+
+rootfs=$path/rootfs
+
+install_ubuntu $rootfs $release $flushcache
+if [ $? -ne 0 ]; then
+ echo "failed to install ubuntu $release"
+ exit 1
+fi
+
+configure_ubuntu $rootfs $name $release
+if [ $? -ne 0 ]; then
+ echo "failed to configure ubuntu $release for a container"
+ exit 1
+fi
+
+copy_configuration $path $rootfs $name $arch $release
+if [ $? -ne 0 ]; then
+ echo "failed write configuration file"
+ exit 1
+fi
+
+post_process $rootfs $release $trim_container
+
+if [ -n "$bindhome" ]; then
+ do_bindhome $rootfs $bindhome
+ finalize_user $bindhome
+else
+ finalize_user ubuntu
+fi
+
+echo ""
+echo "##"
+echo "# The default user is 'ubuntu' with password 'ubuntu'!"
+echo "# Use the 'sudo' command to run tasks as root in the container."
+echo "##"
+echo ""
--- /dev/null
+#!/bin/bash
+
+# template script for generating ubuntu container for LXC based on released cloud
+# images
+#
+# Copyright © 2012 Serge Hallyn <serge.hallyn@canonical.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2, as
+# published by the Free Software Foundation.
+
+# 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, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+
+set -e
+
+if [ -r /etc/default/lxc ]; then
+ . /etc/default/lxc
+fi
+
+copy_configuration()
+{
+ path=$1
+ rootfs=$2
+ name=$3
+ arch=$4
+ release=$5
+
+ if [ $arch = "i386" ]; then
+ arch="i686"
+ fi
+
+ # if there is exactly one veth network entry, make sure it has an
+ # associated hwaddr.
+ nics=`grep -e '^lxc\.network\.type[ \t]*=[ \t]*veth' $path/config | wc -l`
+ if [ $nics -eq 1 ]; then
+ grep -q "^lxc.network.hwaddr" $path/config || cat <<EOF >> $path/config
+lxc.network.hwaddr = 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')
+EOF
+ fi
+
+ cat <<EOF >> $path/config
+lxc.utsname = $name
+
+lxc.tty = 4
+lxc.pts = 1024
+lxc.rootfs = $rootfs
+lxc.mount = $path/fstab
+lxc.arch = $arch
+lxc.cap.drop = sys_module mac_admin
+lxc.pivotdir = lxc_putold
+
+# uncomment the next line to run the container unconfined:
+#lxc.aa_profile = unconfined
+
+lxc.cgroup.devices.deny = a
+# Allow any mknod (but not using the node)
+lxc.cgroup.devices.allow = c *:* m
+lxc.cgroup.devices.allow = b *:* m
+# /dev/null and zero
+lxc.cgroup.devices.allow = c 1:3 rwm
+lxc.cgroup.devices.allow = c 1:5 rwm
+# consoles
+lxc.cgroup.devices.allow = c 5:1 rwm
+lxc.cgroup.devices.allow = c 5:0 rwm
+#lxc.cgroup.devices.allow = c 4:0 rwm
+#lxc.cgroup.devices.allow = c 4:1 rwm
+# /dev/{,u}random
+lxc.cgroup.devices.allow = c 1:9 rwm
+lxc.cgroup.devices.allow = c 1:8 rwm
+lxc.cgroup.devices.allow = c 136:* rwm
+lxc.cgroup.devices.allow = c 5:2 rwm
+# rtc
+lxc.cgroup.devices.allow = c 254:0 rwm
+#fuse
+lxc.cgroup.devices.allow = c 10:229 rwm
+#tun
+lxc.cgroup.devices.allow = c 10:200 rwm
+#full
+lxc.cgroup.devices.allow = c 1:7 rwm
+#hpet
+lxc.cgroup.devices.allow = c 10:228 rwm
+#kvm
+lxc.cgroup.devices.allow = c 10:232 rwm
+EOF
+
+ cat <<EOF > $path/fstab
+proc proc proc nodev,noexec,nosuid 0 0
+sysfs sys sysfs defaults 0 0
+EOF
+
+ # rmdir /dev/shm for containers that have /run/shm
+ # I'm afraid of doing rm -rf $rootfs/dev/shm, in case it did
+ # get bind mounted to the host's /run/shm. So try to rmdir
+ # it, and in case that fails move it out of the way.
+ if [ ! -L $rootfs/dev/shm ] && [ -d $rootfs/run/shm ] && [ -e $rootfs/dev/shm ]; then
+ mv $rootfs/dev/shm $rootfs/dev/shm.bak
+ ln -s /run/shm $rootfs/dev/shm
+ fi
+
+ return 0
+}
+
+usage()
+{
+ cat <<EOF
+LXC Container configuration for Ubuntu Cloud images.
+
+Generic Options
+[ -r | --release <release> ]: Release name of container, defaults to host
+[ -a | --arch ]: Arhcitecture of container, defaults to host arcitecture
+[ -C | --cloud ]: Configure container for use with meta-data service, defaults to no
+[ -T | --tarball ]: Location of tarball
+[ -d | --debug ]: Run with 'set -x' to debug errors
+[ -s | --stream]: Use specified stream rather than 'released'
+
+Options, mutually exclusive of "-C" and "--cloud":
+ [ -i | --hostid ]: HostID for cloud-init, defaults to random string
+ [ -u | --userdata ]: Cloud-init user-data file to configure container on start
+ [ -S | --auth-key ]: SSH Public key file to inject into container
+ [ -L | --nolocales ]: Do not copy host's locales into container
+
+EOF
+ return 0
+}
+
+options=$(getopt -o a:hp:r:n:Fi:CLS:T:ds: -l arch:,help,path:,release:,name:,flush-cache,hostid:,auth-key:,cloud,no_locales,tarball:,debug,stream:,userdata: -- "$@")
+if [ $? -ne 0 ]; then
+ usage $(basename $0)
+ exit 1
+fi
+eval set -- "$options"
+
+release=lucid
+if [ -f /etc/lsb-release ]; then
+ . /etc/lsb-release
+ case "$DISTRIB_CODENAME" in
+ lucid|maverick|natty|oneiric|precise)
+ release=$DISTRIB_CODENAME
+ ;;
+ esac
+fi
+
+arch=$(arch)
+
+# Code taken from debootstrap
+if [ -x /usr/bin/dpkg ] && /usr/bin/dpkg --print-architecture >/dev/null 2>&1; then
+ arch=`/usr/bin/dpkg --print-architecture`
+elif type udpkg >/dev/null 2>&1 && udpkg --print-architecture >/dev/null 2>&1; then
+ arch=`/usr/bin/udpkg --print-architecture`
+else
+ arch=$(arch)
+ if [ "$arch" = "i686" ]; then
+ arch="i386"
+ elif [ "$arch" = "x86_64" ]; then
+ arch="amd64"
+ elif [ "$arch" = "armv7l" ]; then
+ # note: arm images don't exist before oneiric; are called armhf in
+ # precise; and are not supported by the query, so we don't actually
+ # support them yet (see check later on). When Query2 is available,
+ # we'll use that to enable arm images.
+ arch="armel"
+ fi
+fi
+
+debug=0
+hostarch=$arch
+cloud=0
+locales=1
+flushcache=0
+stream="released"
+while true
+do
+ case "$1" in
+ -h|--help) usage $0 && exit 0;;
+ -p|--path) path=$2; shift 2;;
+ -n|--name) name=$2; shift 2;;
+ -F|--flush-cache) flushcache=1; shift 1;;
+ -r|--release) release=$2; shift 2;;
+ -a|--arch) arch=$2; shift 2;;
+ -i|--hostid) host_id=$2; shift 2;;
+ -u|--userdata) userdata=$2; shift 2;;
+ -C|--cloud) cloud=1; shift 1;;
+ -S|--auth-key) auth_key=$2; shift 2;;
+ -L|--no_locales) locales=0; shift 2;;
+ -T|--tarball) tarball=$2; shift 2;;
+ -d|--debug) debug=1; shift 1;;
+ -s|--stream) stream=$2; shift 2;;
+ --) shift 1; break ;;
+ *) break ;;
+ esac
+done
+
+if [ $debug -eq 1 ]; then
+ set -x
+fi
+
+if [ "$arch" == "i686" ]; then
+ arch=i386
+fi
+
+if [ $hostarch = "i386" -a $arch = "amd64" ]; then
+ echo "can't create amd64 container on i386"
+ exit 1
+fi
+
+if [ $arch != "i386" -a $arch != "amd64" ]; then
+ echo "Only i386 and amd64 are supported by the ubuntu cloud template."
+ exit 1
+fi
+
+if [ "$stream" != "daily" -a "$stream" != "released" ]; then
+ echo "Only 'daily' and 'released' streams are supported"
+ exit 1
+fi
+
+if [ -n "$userdata" -a ! -f "$userdata" ]; then
+ echo "Userdata does not exist"
+ exit 1
+fi
+
+if [ -z "$path" ]; then
+ echo "'path' parameter is required"
+ exit 1
+fi
+
+if [ "$(id -u)" != "0" ]; then
+ echo "This script should be run as 'root'"
+ exit 1
+fi
+
+rootfs=$path/rootfs
+
+type ubuntu-cloudimg-query
+type wget
+
+# determine the url, tarball, and directory names
+# download if needed
+cache="/var/cache/lxc/cloud-$release"
+
+mkdir -p $cache
+
+if [ -n "$tarball" ]; then
+ url2="$tarball"
+else
+ url1=`ubuntu-cloudimg-query $release $stream $arch --format "%{url}\n"`
+ url2=`echo $url1 | sed -e 's/.tar.gz/-root\0/'`
+fi
+
+filename=`basename $url2`
+
+buildcleanup()
+{
+ cd $rootfs
+ umount -l $cache/$xdir || true
+ rm -rf $cache
+}
+
+# if the release doesn't have a *-rootfs.tar.gz, then create one from the
+# cloudimg.tar.gz by extracting the .img, mounting it loopback, and creating
+# a tarball from the mounted image.
+build_root_tgz()
+{
+ url=$1
+ filename=$2
+
+ xdir=`mktemp -d -p .`
+ tarname=`basename $url`
+ imgname="$release-*-cloudimg-$arch.img"
+ trap buildcleanup EXIT
+ if [ $flushcache -eq 1 -o ! -f $cache/$tarname ]; then
+ rm -f $tarname
+ echo "Downloading cloud image from $url"
+ wget $url || { echo "Couldn't find cloud image $url."; exit 1; }
+ fi
+ echo "Creating new cached cloud image rootfs"
+ tar --wildcards -zxf $tarname $imgname
+ mount -o loop $imgname $xdir
+ (cd $xdir; tar zcf ../$filename .)
+ umount $xdir
+ rm -f $tarname $imgname
+ rmdir $xdir
+ echo "New cloud image cache created"
+ trap EXIT
+}
+
+mkdir -p /var/lock/subsys/
+(
+ flock -x 200
+
+ cd $cache
+ if [ $flushcache -eq 1 ]; then
+ echo "Clearing the cached images"
+ rm -f $filename
+ fi
+
+ if [ ! -f $filename ]; then
+ wget $url2 || build_root_tgz $url1 $filename
+ fi
+
+ echo "Extracting container rootfs"
+ mkdir -p $rootfs
+ cd $rootfs
+ tar -zxf $cache/$filename
+
+
+ if [ $cloud -eq 0 ]; then
+ echo "Configuring for running outside of a cloud environment"
+ echo "If you want to configure for a cloud evironment, please use '-- -C' to create the container"
+
+ seed_d=$rootfs/var/lib/cloud/seed/nocloud-net
+ rhostid=$(uuidgen | cut -c -8)
+ host_id=${hostid:-$rhostid}
+ mkdir -p $seed_d
+
+ cat > "$seed_d/meta-data" <<EOF
+instance_id: lxc-$host_id
+EOF
+
+ rm $rootfs/etc/hostname
+
+ if [ $locales -eq 1 ]; then
+ cp /usr/lib/locale/locale-archive $rootfs/usr/lib/locale/locale-archive
+ fi
+
+
+ if [ -n "$auth_key" -a -f "$auth_key" ]; then
+ u_path="/home/ubuntu/.ssh"
+ root_u_path="$rootfs/$u_path"
+ mkdir -p $root_u_path
+ cp $auth_key "$root_u_path/authorized_keys"
+ chroot $rootfs chown -R ubuntu: "$u_path"
+
+ echo "Inserted SSH public key from $auth_key into /home/ubuntu/.ssh/authorized_keys"
+ fi
+
+ if [ -f "$userdata" ]; then
+ echo "Using custom user-data"
+ cp $userdata $seed_d/user-data
+ else
+
+ if [ -z "$MIRROR" ]; then
+ MIRROR="http://archive.ubuntu.com/ubuntu"
+ fi
+
+ cat > "$seed_d/user-data" <<EOF
+#cloud-config
+output: {all: '| tee -a /var/log/cloud-init-output.log'}
+apt-mirror: $MIRROR
+manage_etc_hosts: localhost
+locale: $(/usr/bin/locale | awk -F= '/LANG=/ {print$NF}')
+EOF
+ fi
+
+ chroot $rootfs /usr/sbin/usermod -U ubuntu
+ echo "ubuntu:ubuntu" | chroot $rootfs chpasswd
+ echo "Please login as user ubuntu with password ubuntu."
+
+ else
+
+ echo "Configured for running in a cloud environment."
+ echo "If you do not have a meta-data service, this container will likely be useless."
+
+ fi
+
+) 200>/var/lock/subsys/lxc-ubucloud
+
+copy_configuration $path $rootfs $name $arch $release
+
+echo "Container $name created."
+exit 0