diff --git a/boxes/build-ubuntu-box.sh b/boxes/build-ubuntu-box.sh index 1e3a90f..1e3e902 100755 --- a/boxes/build-ubuntu-box.sh +++ b/boxes/build-ubuntu-box.sh @@ -7,6 +7,8 @@ # TODO: * Add support for flushing cache and specifying a custom base Ubuntu lxc # template instead of system's built in # * Embed vagrant public key +# * Add date to metadata.json +# * Ensure it is in sync with master ################################################################################## # 1 - Create the base container diff --git a/boxes/common/lxc-template b/boxes/common/lxc-template deleted file mode 100755 index 9e53be4..0000000 --- a/boxes/common/lxc-template +++ /dev/null @@ -1,229 +0,0 @@ -#!/bin/bash - -# This is a modified version of /usr/share/lxc/templates/lxc-ubuntu -# that comes with Ubuntu 13.04 changed to suit vagrant-lxc needs - -# -# template script for generating ubuntu container for LXC -# -# This script consolidates and extends the existing lxc ubuntu scripts -# - -# Copyright © 2011 Serge Hallyn -# Copyright © 2010 Wilhelm Meier -# Author: Wilhelm Meier -# -# 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 - -extract_rootfs() -{ - tarball=$1 - arch=$2 - rootfs=$3 - - echo "Extracting $tarball ..." - mkdir -p $(dirname $rootfs) - (cd `dirname $rootfs` && tar xfz $tarball) - return 0 -} - -install_ubuntu() -{ - rootfs=$1 - release=$2 - tarball=$3 - mkdir -p /var/lock/subsys/ - - ( - flock -x 200 - if [ $? -ne 0 ]; then - echo "Cache repository is busy." - return 1 - fi - - extract_rootfs $tarball $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 - - grep -q "^lxc.rootfs" $path/config 2>/dev/null || echo "lxc.rootfs = $rootfs" >> $path/config - - # 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 || sed -i -e "/^lxc\.network\.type[ \t]*=[ \t]*veth/a lxc.network.hwaddr = 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')" $path/config - fi - - if [ $? -ne 0 ]; then - echo "Failed to add configuration" - return 1 - fi - - return 0 -} - -post_process() -{ - rootfs=$1 - - # 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 -} - -usage() -{ - cat <] [ -S | --auth-key ] -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 -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:C -l arch:,help,path:,release:,trim,name:,flush-cache,auth-key:,debug:,tarball: -- "$@") -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 - -arch=$(uname -m) - -# 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=$(uname -m) - 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 -while true -do - case "$1" in - -h|--help) usage $0 && exit 0;; - -p|--path) path=$2; shift 2;; - -n|--name) name=$2; shift 2;; - -T|--tarball) tarball=$2; shift 2;; - -r|--release) release=$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 [ "$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 [ -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 - -# detect rootfs -config="$path/config" -if grep -q '^lxc.rootfs' $config 2>/dev/null ; then - rootfs=`grep 'lxc.rootfs =' $config | awk -F= '{ print $2 }'` -else - rootfs=$path/rootfs -fi - -install_ubuntu $rootfs $release $tarball -if [ $? -ne 0 ]; then - echo "failed to install ubuntu $release" - exit 1 -fi - -copy_configuration $path $rootfs $name $arch -if [ $? -ne 0 ]; then - echo "failed write configuration file" - exit 1 -fi - -post_process $rootfs $release $trim_container - -echo "" -echo "##" -echo "# The default user is 'vagrant' with password 'vagrant'!" -echo "# Use the 'sudo' command to run tasks as root in the container." -echo "##" -echo "" diff --git a/boxes/templates/ubuntu b/boxes/templates/ubuntu deleted file mode 100755 index 59e7841..0000000 --- a/boxes/templates/ubuntu +++ /dev/null @@ -1,811 +0,0 @@ -#!/bin/bash - -# Based on https://github.com/lxc/lxc/blob/188e0ab60bda276c688ad15877c6d6402081c6c9/templates/lxc-ubuntu.in - -# -# template script for generating ubuntu container for LXC -# -# This script consolidates and extends the existing lxc ubuntu scripts -# - -# Copyright © 2011 Serge Hallyn -# Copyright © 2010 Wilhelm Meier -# Author: Wilhelm Meier -# -# 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., 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 < $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 < $rootfs/etc/hostname -$hostname -EOF - # set minimal hosts - cat < $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 - - # make sure we have the current locale defined in the container - if [ -z "$LANG" ] || echo $LANG | grep -E -q "^C(\..+)*$"; 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 - - # generate new SSH keys - if [ -x $rootfs/var/lib/dpkg/info/openssh-server.postinst ]; then - cat > $rootfs/usr/sbin/policy-rc.d << EOF -#!/bin/sh -exit 101 -EOF - chmod +x $rootfs/usr/sbin/policy-rc.d - - rm -f $rootfs/etc/ssh/ssh_host_*key* - mv $rootfs/etc/init/ssh.conf $rootfs/etc/init/ssh.conf.disabled - DPKG_MAINTSCRIPT_PACKAGE=openssh DPKG_MAINTSCRIPT_NAME=postinst chroot $rootfs /var/lib/dpkg/info/openssh-server.postinst configure - mv $rootfs/etc/init/ssh.conf.disabled $rootfs/etc/init/ssh.conf - - rm -f $rootfs/usr/sbin/policy-rc.d - 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 - - chroot $rootfs getent passwd $user || chroot $rootfs adduser --disabled-password --gecos "" $user - - 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 -} - -# -# Choose proxies for container -# http_proxy will be used by debootstrap on the host. -# APT_PROXY will be used to set /etc/apt/apt.conf.d/70proxy in the container. -# -choose_container_proxy() -{ - local rootfs=$1 - local arch=$2 - - if [ -z "$HTTP_PROXY" ]; then - HTTP_PROXY="none" - fi - case "$HTTP_PROXY" in - none) - APT_PROXY= - ;; - apt) - RES=`apt-config shell APT_PROXY Acquire::http::Proxy` - eval $RES - [ -z "$APT_PROXY" ] || export http_proxy=$APT_PROXY - ;; - *) - APT_PROXY=$HTTP_PROXY - export http_proxy=$HTTP_PROXY - ;; - esac -} - -write_sourceslist() -{ - # $1 => path to the rootfs - # $2 => architecture we want to add - # $3 => whether to use the multi-arch syntax or not - - if [ -n "$APT_PROXY" ]; then - mkdir -p $rootfs/etc/apt/apt.conf.d - cat > $rootfs/etc/apt/apt.conf.d/70proxy << EOF -Acquire::http::Proxy "$APT_PROXY" ; -EOF - fi - - 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 -} - -cleanup() -{ - rm -rf $cache/partial-$arch - rm -rf $cache/rootfs-$arch -} - -suggest_flush() -{ - echo "Container upgrade failed. The container cache may be out of date," - echo "in which case flushing the case (see -F in the hep output) may help." -} - -download_ubuntu() -{ - cache=$1 - arch=$2 - release=$3 - - packages=vim,ssh - - # Try to guess a list of langpacks to install - langpacks="language-pack-en" - - if which dpkg >/dev/null 2>&1; then - langpacks=`(echo $langpacks && - dpkg -l | grep -E "^ii language-pack-[a-z]* " | - cut -d ' ' -f3) | sort -u` - fi - packages="$packages,$(echo $langpacks | sed 's/ /,/g')" - - - echo "installing packages: $packages" - - trap cleanup EXIT SIGHUP SIGINT SIGTERM - # 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 - - choose_container_proxy $cache/partial-$arch/ $arch - # 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 || { suggest_flush; false; } - rm -f "$1/partial-${arch}"/usr/sbin/policy-rc.d - - chroot "$1/partial-${arch}" apt-get clean - - mv "$1/partial-$arch" "$1/rootfs-$arch" - trap EXIT - trap SIGINT - trap SIGTERM - trap SIGHUP - 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 -Ha $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-ubuntu - - 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 || sed -i -e "/^lxc\.network\.type[ \t]*=[ \t]*veth/a lxc.network.hwaddr = 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')" $path/config - fi - - grep -q "^lxc.rootfs" $path/config 2>/dev/null || echo "lxc.rootfs = $rootfs" >> $path/config - cat <> $path/config -lxc.mount = $path/fstab -lxc.pivotdir = lxc_putold - -lxc.devttydir =$ttydir -lxc.tty = 4 -lxc.pts = 1024 - -lxc.utsname = $name -lxc.arch = $arch -lxc.cap.drop = sys_module mac_admin mac_override sys_time - -# When using LXC with apparmor, uncomment the next line to run unconfined: -#lxc.aa_profile = unconfined - -# To support container nesting on an Ubuntu host, uncomment next two lines: -#lxc.aa_profile = lxc-container-default-with-nesting -#lxc.hook.mount = /usr/share/lxc/hooks/mountcgroups - -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 -# /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 rm -# 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 < $path/fstab -proc proc proc nodev,noexec,nosuid 0 0 -sysfs sys sysfs defaults 0 0 -/sys/fs/fuse/connections sys/fs/fuse/connections none bind 0 0 -/sys/kernel/debug sys/kernel/debug none bind 0 0 -/sys/kernel/security sys/kernel/security none bind 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 < $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 < $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 < $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 < $rootfs/lib/init/fstab -# /lib/init/fstab: cleared out for bare-bones lxc -EOF - - # remove pointless services in a container - chroot $rootfs /usr/sbin/update-rc.d -f ondemand remove - chroot $rootfs /usr/sbin/update-rc.d -f checkroot-bootclean.sh remove - chroot $rootfs /usr/sbin/update-rc.d -f mountall-bootclean.sh remove - chroot $rootfs /usr/sbin/update-rc.d -f mountnfs-bootclean.sh 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 update - 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 <] [--trim] [-d|--debug] - [-F | --flush-cache] [-r|--release ] [ -S | --auth-key ] - [--rootfs ] -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 's home into the container - The ubuntu user will not be created, and 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,rootfs: -- "$@") -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= - -# 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 which udpkg >/dev/null 2>&1 && udpkg --print-architecture >/dev/null 2>&1; then - arch=`/usr/bin/udpkg --print-architecture` -else - arch=$(uname -m) - if [ "$arch" = "i686" ]; then - arch="i386" - elif [ "$arch" = "x86_64" ]; then - arch="amd64" - elif [ "$arch" = "armv7l" ]; then - arch="armhf" - fi -fi - -debug=0 -trim_container=0 -hostarch=$arch -flushcache=0 -while true -do - case "$1" in - -h|--help) usage $0 && exit 0;; - --rootfs) rootfs=$2; shift 2;; - -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 $arch container on $hostarch" - exit 1 -fi - -if [ $hostarch = "armhf" -o $hostarch = "armel" ] && \ - [ $arch != "armhf" -a $arch != "armel" ]; then - echo "can't create $arch container on $hostarch" - exit 1 -fi - -if [ $hostarch = "powerpc" -a $arch != "powerpc" ]; then - echo "can't create $arch container on $hostarch" - exit 1 -fi - -which debootstrap >/dev/null 2>&1 || { echo "'debootstrap' command is missing" >&2; false; } - -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 - -# detect rootfs -config="$path/config" -# if $rootfs exists here, it was passed in with --rootfs -if [ -z "$rootfs" ]; then - if grep -q '^lxc.rootfs' $config 2>/dev/null ; then - rootfs=`grep 'lxc.rootfs =' $config | awk -F= '{ print $2 }'` - else - rootfs=$path/rootfs - fi -fi - -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 - -vagrant_key_file="/tmp/vagrant.pub" -echo "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key" > /tmp/vagrant.pub -orig_auth_key="$auth_key" -auth_key="/tmp/vagrant.pub" -finalize_user vagrant -auth_key="$orig_auth_key" - -echo "" -echo "##" -if [ -n "$bindhome" ]; then - echo "# Log in as user $bindhome" -else - echo "# The default user is 'ubuntu' with password 'ubuntu'!" - echo "# Use the 'sudo' command to run tasks as root in the container." -fi -echo "##" -echo "" diff --git a/tasks/boxes.rake b/tasks/boxes.rake deleted file mode 100644 index 3897e71..0000000 --- a/tasks/boxes.rake +++ /dev/null @@ -1,179 +0,0 @@ -require 'time' -require 'pathname' -require 'rake/tasklib' - -class BuildGenericBoxTask < ::Rake::TaskLib - include ::Rake::DSL - - attr_reader :name - - def initialize(name, distrib, release, arch, cfg_engines) - @name = name - @distrib = distrib - @release = release.to_s - @arch = arch.to_s - @cfg_engines = cfg_engines - @file = "lxc-#{@release}-#{@arch}-#{Date.today}.box" - @scripts_path = Pathname(Dir.pwd).join('boxes') - - task name do - RakeFileUtils.send(:verbose, true) do - build - end - end - end - - def run(script_name, *args) - script = @scripts_path.join('common', script_name) - if script.readable? - sh "sudo #{script} #{args.join(' ')}" - else - STDERR.puts "cannot execute #{script_name} (not found?)" - exit 1 - end - end - - def build - check_if_box_has_been_built! - - FileUtils.mkdir_p 'boxes/temp' unless File.exist? 'base/temp' - check_for_partially_built_box! - - import_template do |template| - create_base_container(template) do |rootfs| - install_cfg_engines(rootfs) - cleanup(rootfs) - prepare_package_contents(rootfs) - compress_box(rootfs) - end - end - end - - def check_if_box_has_been_built! - return unless File.exists?("./boxes/output/#{@file}") - - puts 'Box has been built already!' - exit 1 - end - - def check_for_partially_built_box! - return unless Dir.entries('boxes/temp').size > 2 - - puts 'There is a partially built box under ' + - File.expand_path('./boxes/temp') + - ', please remove it before building a new box' - exit 1 - end - - def create_base_container(template) - container_name = 'vagrant-base-box-tmp' - sh "sudo lxc-create -n #{container_name} -t vagrant-base-box-template -- --arch #{@arch} --release #{@release}" - yield "/var/lib/lxc/#{container_name}/rootfs" - ensure - sh "sudo lxc-destroy -n #{container_name}" - end - - def install_cfg_engines(rootfs) - puts "TODO: Install cfg engines under #{rootfs}" - end - - def prepare_package_contents(rootfs) - puts "TODO: Prepare pkg contents under #{rootfs}" - end - - def compress_box(rootfs) - puts "TODO: Compress base box under #{rootfs}" - end - - def cleanup(rootfs) - puts "TODO: Cleanup under #{rootfs}" - end - - def import_template - template_name = "vagrant-base-box-template" - tmp_template_path = templates_path.join("lxc-#{template_name}") - src = "./boxes/templates/#{@distrib}" - - sh "sudo cp #{src} #{tmp_template_path}" - - yield template_name - ensure - sh "sudo rm #{tmp_template_path}" if tmp_template_path.file? - end - - TEMPLATES_PATH_LOOKUP = %w( - /usr/share/lxc/templates - /usr/lib/lxc/templates - /usr/lib64/lxc/templates - /usr/local/lib/lxc/templates - ) - def templates_path - return @templates_path if @templates_path - - path = TEMPLATES_PATH_LOOKUP.find { |candidate| File.directory?(candidate) } - raise 'Unable to identify lxc templates path!' unless path - - @templates_path = Pathname(path) - end -end - -class BuildDebianBoxTask < BuildGenericBoxTask - def initialize(name, release, arch, opts = {}) - super(name, 'debian', release, arch, opts) - end -end - -class BuildUbuntuBoxTask < BuildGenericBoxTask - def initialize(name, release, arch, opts = {}) - super(name, 'ubuntu', release, arch, opts) - end -end - -cfg_engines = { - puppet: ENV['PUPPET'] == '1', - babushka: ENV['BABUSHKA'] == '1', - salt: ENV['SALT'] == '1', - chef: ENV['CHEF'] == '1' -} - -namespace :boxes do - namespace :ubuntu do - namespace :build do - - desc 'Build an Ubuntu Precise 64 bits box' - BuildUbuntuBoxTask.new(:precise64, :precise, 'amd64', cfg_engines) - - desc 'Build an Ubuntu Quantal 64 bits box' - BuildUbuntuBoxTask.new(:quantal64, :quantal, 'amd64', cfg_engines) - - desc 'Build an Ubuntu Raring 64 bits box' - BuildUbuntuBoxTask.new(:raring64, :raring, 'amd64', cfg_engines) - - desc 'Build an Ubuntu Saucy 64 bits box' - BuildUbuntuBoxTask.new(:saucy64, :saucy, 'amd64', cfg_engines) - - desc 'Build all Ubuntu boxes' - task :all => %w( precise64 quantal64 raring64 saucy64 ) - end - end - - namespace :debian do - %w( chef salt).each { |cfg| cfg_engines.delete(cfg.to_sym) } - namespace :build do - desc 'Build an Debian Squeeze 64 bits box' - BuildDebianBoxTask.new(:squeeze64, :squeeze, 'amd64', cfg_engines) - - desc 'Build an Debian Wheezy 64 bits box' - BuildDebianBoxTask.new(:wheezy64, :wheezy, 'amd64', cfg_engines) - - desc 'Build an Debian Sid/unstable 64 bits box' - BuildDebianBoxTask.new(:sid64, :sid, 'amd64', cfg_engines) - - desc 'Build all Debian boxes' - task :all => %w( squeeze64 wheezy64 sid64 ) - end - end - - desc 'Build all base boxes for release' - task :build_all => %w( ubuntu:build:all debian:build:all ) -end