From bcdb4ca5bdc2e8818a3db72d3573fdb11c39b540 Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Fri, 30 Aug 2013 16:29:51 -0300 Subject: [PATCH 01/20] :bomb: V2 boxes creation scripts --- tasks/boxes.v2.rake | 188 -------------------------------------------- 1 file changed, 188 deletions(-) delete mode 100644 tasks/boxes.v2.rake diff --git a/tasks/boxes.v2.rake b/tasks/boxes.v2.rake deleted file mode 100644 index 9fc5059..0000000 --- a/tasks/boxes.v2.rake +++ /dev/null @@ -1,188 +0,0 @@ -require 'pathname' -require 'rake/tasklib' - -class BuildGenericBoxTaskV2 < ::Rake::TaskLib - include ::Rake::DSL - - attr_reader :name - - def initialize(name, distrib, release, arch, opts = {}) - @name = name - @distrib = distrib - @release = release.to_s - @arch = arch.to_s - @install_chef = opts.fetch(:chef, false) - @install_puppet = opts.fetch(:puppet, true) - @install_babushka = opts.fetch(:babushka, true) - @install_salt = opts.fetch(:salt, true) - @file = opts[:file] || default_box_file - @scripts_path = Pathname(Dir.pwd).join('boxes') - - desc "Build an #{distrib.upcase} #{release} #{arch} box" unless - ::Rake.application.last_comment - task name do - RakeFileUtils.send(:verbose, true) do - build - end - end - end - - def default_box_file - require 'time' - "lxc-#{@release}-#{@arch}-#{Date.today}.box" - end - - def run(script_name, *args) - unless (script = @scripts_path.join(@distrib, script_name)).readable? - script = @scripts_path.join('common', script_name) - end - - 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! - - pwd = Dir.pwd - sh 'mkdir -p boxes/temp/' - Dir.chdir 'boxes/temp' do - download - install_cfg_engines - prepare_package_contents pwd - sh 'sudo rm -rf rootfs' - sh "tar -czf tmp-package.box ./*" - end - - sh 'mkdir -p boxes/output' - sh "cp boxes/temp/tmp-package.box boxes/output/#{@file}" - sh "rm -rf boxes/temp" - 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 download - run 'download', @arch, @release - end - - def install_cfg_engines - [ :puppet, :chef, :babushka, :salt ].each do |cfg_engine| - next unless instance_variable_get :"@install_#{cfg_engine}" - script_name = "install-#{cfg_engine}" - run script_name - end - end - - def prepare_package_contents(pwd) - run 'cleanup' - sh 'sudo rm -f rootfs.tar.gz' - sh 'sudo tar --numeric-owner -czf rootfs.tar.gz ./rootfs/*' - sh "sudo chown #{ENV['USER']}:#{`id -gn`.strip} rootfs.tar.gz" - sh "cp #{pwd}/boxes/#{@distrib}/lxc-template ." - compile_metadata(pwd) - end - - def compile_metadata(pwd) - metadata = File.read("#{pwd}/boxes/#{@distrib}/metadata.json.template") - metadata.gsub!('ARCH', @arch) - metadata.gsub!('RELEASE', @release) - File.open('metadata.json', 'w') { |f| f.print metadata } - end -end - -class BuildDebianBoxTaskV2 < BuildGenericBoxTaskV2 - def initialize(name, release, arch, opts = {}) - super(name, 'debian', release, arch, opts) - end -end - -class BuildUbuntuBoxTaskV2 < BuildGenericBoxTaskV2 - def initialize(name, release, arch, opts = {}) - super(name, 'ubuntu', release, arch, opts) - end -end - -chef = ENV['CHEF'] == '1' -puppet = ENV['PUPPET'] == '1' -babushka = ENV['BABUSHKA'] == '1' -salt = ENV['SALT'] == '1' - -namespace :boxes do - namespace :v2 do - namespace :ubuntu do - namespace :build do - - desc 'Build an Ubuntu Precise 64 bits box' - BuildUbuntuBoxTaskV2. - new(:precise64, - :precise, 'amd64', chef: chef, puppet: puppet, babushka: babushka, salt: salt) - - desc 'Build an Ubuntu Quantal 64 bits box' - BuildUbuntuBoxTaskV2. - new(:quantal64, - :quantal, 'amd64', chef: chef, puppet: puppet, babushka: babushka, salt: salt) - - # FIXME: Find out how to install chef on raring - desc 'Build an Ubuntu Raring 64 bits box' - BuildUbuntuBoxTaskV2. - new(:raring64, - :raring, 'amd64', chef: chef, puppet: puppet, babushka: babushka, salt: salt) - - desc 'Build an Ubuntu Saucy 64 bits box' - BuildUbuntuBoxTaskV2. - new(:saucy64, - :saucy, 'amd64', chef: chef, puppet: puppet, babushka: babushka, salt: salt) - - desc 'Build all Ubuntu boxes' - task :all => %w( precise64 quantal64 raring64 saucy64 ) - end - end - - # FIXME: Find out how to install chef on debian boxes - namespace :debian do - namespace :build do - desc 'Build an Debian Squeeze 64 bits box' - BuildDebianBoxTaskV2. - new(:squeeze64, - :squeeze, 'amd64', chef: false, puppet: puppet, babushka: babushka, salt: false) - - desc 'Build an Debian Wheezy 64 bits box' - BuildDebianBoxTaskV2. - new(:wheezy64, - :wheezy, 'amd64', chef: false, puppet: puppet, babushka: babushka, salt: false) - - desc 'Build an Debian Sid/unstable 64 bits box' - BuildDebianBoxTaskV2. - new(:sid64, - :sid, 'amd64', chef: false, puppet: puppet, babushka: babushka, salt: false) - - 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 -end From dbc6c8b231575d041cafae954ddedc61f323f378 Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Fri, 30 Aug 2013 17:03:36 -0300 Subject: [PATCH 02/20] Scaffold new base boxes rake tasks and remove old files --- boxes/debian/download | 156 -------- boxes/debian/finalize | 195 ---------- boxes/debian/lxc-template | 367 ------------------ boxes/debian/metadata.json.template | 9 - boxes/ubuntu/download | 113 ------ boxes/ubuntu/finalize | 374 ------------------- boxes/ubuntu/lxc-template | 559 ---------------------------- boxes/ubuntu/metadata.json.template | 9 - tasks/boxes.rake | 174 ++++++--- 9 files changed, 120 insertions(+), 1836 deletions(-) delete mode 100755 boxes/debian/download delete mode 100755 boxes/debian/finalize delete mode 100755 boxes/debian/lxc-template delete mode 100644 boxes/debian/metadata.json.template delete mode 100755 boxes/ubuntu/download delete mode 100755 boxes/ubuntu/finalize delete mode 100755 boxes/ubuntu/lxc-template delete mode 100644 boxes/ubuntu/metadata.json.template diff --git a/boxes/debian/download b/boxes/debian/download deleted file mode 100755 index f6a9407..0000000 --- a/boxes/debian/download +++ /dev/null @@ -1,156 +0,0 @@ -#!/bin/bash - -# This is the code extracted from /usr/share/lxc/templates/lxc-debian -# that comes with Ubuntu 13.04 which is responsible for downloading the -# rootfs files / packages - -set -e - -suggest_flush() -{ - echo < ${rootfs}/etc/apt/sources.list -# ${release} -#------------------------------------------------------------------------------ -deb ${MIRROR} ${release} main contrib non-free -EOF - else - cat < ${rootfs}/etc/apt/sources.list -# ${release} -#------------------------------------------------------------------------------ -deb ${MIRROR} ${release} main contrib non-free - -# ${release} security -#------------------------------------------------------------------------------ -deb ${SECURITY_MIRROR} ${release}/updates main contrib non-free - -# ${release} updates -#------------------------------------------------------------------------------ -deb ${MIRROR} ${release}-updates main contrib non-free - -# ${release} proposed updates -#------------------------------------------------------------------------------ -deb ${MIRROR} ${release}-proposed-updates main contrib non-free -EOF - fi -} - -download_debian() -{ - cache=$1 - arch=$2 - release=$3 - - packages=\ -sudo,\ -ifupdown,\ -locales,\ -libui-dialog-perl,\ -dialog,\ -isc-dhcp-client,\ -netbase,\ -net-tools,\ -iproute,\ -openssh-server,\ -vim,\ -jed,\ -jed-extra,\ -ssh,\ -curl,\ -wget,\ -bash-completion,\ -manpages,\ -man-db,\ -psmisc,\ -bind9-host,\ -telnet,\ -mtr-tiny,\ -iputils-ping,\ -ca-certificates - - if [ ! -z "${ADDITIONAL_PACKAGES}" ]; then - packages=${ADDITIONAL_PACKAGES},${packages} - fi - - echo "installing packages: ${packages}" - - trap cleanup EXIT SIGHUP SIGINT SIGTERM - # check the mini debian was not already downloaded - partial=${cache}/partial - mkdir -p ${partial} - if [ $? -ne 0 ]; then - echo "Failed to create '${partial}' directory" - return 1 - fi - - # download a mini debian into a cache - echo "Downloading debian ${release} minimal ..." - debootstrap \ - --variant=minbase \ - --verbose \ - --components=main,contrib,non-free \ - --arch=${arch} \ - --include=${packages} ${release} ${partial} ${MIRROR} - - if [ $? -ne 0 ]; then - echo 'Failed to download the rootfs, aborting.' - return 1 - fi - - echo 'Installing updates' - write_sourceslist ${partial} ${arch} ${release} - - chroot ${partial} apt-get update - if [ $? -ne 0 ]; then - echo 'Failed to update the apt cache' - return 1 - fi - - lxc-unshare -s MOUNT -- chroot ${partial} \ - apt-get dist-upgrade -y || { suggest_flush; false; } - - chroot ${partial} apt-get clean - - mv ${partial} ${cache}/rootfs - trap EXIT - trap SIGINT - trap SIGTERM - trap SIGHUP - echo 'Download complete' - return 0 -} - -declare cache=`readlink -f .` \ - arch=$1 \ - release=$2 - -if [ -d ${cache}/rootfs ]; then - echo < $rootfs/etc/inittab -id:3: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 -p6::ctrlaltdel:/sbin/init 6 -p0::powerfail:/sbin/init 0 -EOF - - # disable selinux in debian - mkdir -p $rootfs/selinux - echo 0 > $rootfs/selinux/enforce - - # configure the network using the dhcp - cat < $rootfs/etc/network/interfaces -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 -ff02::3 ip6-allhosts -EOF - - # set default locale - cat < $rootfs/etc/locale.gen -en_US.UTF-8 UTF-8 -EOF - echo "default locale set to en_US.UTF-8 UTF-8" - chroot $rootfs locale-gen 'en_US.UTF-8' > /dev/null 2>&1 - chroot $rootfs update-locale LANG='en_US.UTF-8' - echo 'update-locale done' - - # remove pointless services in a container - chroot $rootfs /usr/sbin/update-rc.d -f checkroot.sh remove - chroot $rootfs /usr/sbin/update-rc.d -f umountfs remove - chroot $rootfs /usr/sbin/update-rc.d -f hwclock.sh remove - chroot $rootfs /usr/sbin/update-rc.d -f hwclockfirst.sh remove - - echo "root:vagrant" | chroot $rootfs chpasswd - - if ! (grep -q vagrant $rootfs/etc/passwd); then - chroot $rootfs useradd --create-home -s /bin/bash vagrant - echo "vagrant:vagrant" | chroot $rootfs chpasswd - chroot $rootfs adduser vagrant sudo >/dev/null 2>&1 || true - chroot $rootfs cp /etc/sudoers /etc/sudoers.orig >/dev/null 2>&1 || true - chroot $rootfs sed -i -e \ - 's/%sudo\s\+ALL=(ALL\(:ALL\)\?)\s\+ALL/%sudo ALL=NOPASSWD:ALL/g' \ - /etc/sudoers >/dev/null 2>&1 || true - fi - - return 0 -} - -cleanup() -{ - rm -rf ${cache}/partial - rm -rf ${cache}/rootfs -} - -add_ssh_key() -{ - user=$1 - - 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 -} - -disable_tmp_cleanup() { - rootfs=$1 - 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 -} - -release=wheezy # Default to the last Debian stable release - -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 - -if [ "$(id -u)" != "0" ]; then - echo "This script should be run as 'root'" - exit 1 -fi - -declare cache=`readlink -f .` \ - arch=$1 \ - release=$2 \ - auth_key=$3 - -# detect rootfs -cache=`readlink -f .` -rootfs="${cache}/rootfs" - -configure_debian $rootfs $release -if [ $? -ne 0 ]; then - echo "failed to configure debian $release for a container" - exit 1 -fi - -add_ssh_key vagrant - -# vagrant and / or plugins might mount some shared folders under /tmp by default -# (like puppet manifests) and we need to make sure no shared folder gets its -# contents removed because of it. For more information, please check: -# https://github.com/fgrehm/vagrant-lxc/issues/68 -disable_tmp_cleanup $rootfs - -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/debian/lxc-template b/boxes/debian/lxc-template deleted file mode 100755 index 5af9502..0000000 --- a/boxes/debian/lxc-template +++ /dev/null @@ -1,367 +0,0 @@ -#!/bin/bash - -# This is a modified version of /usr/share/lxc/templates/lxc-debian -# that comes with Ubuntu 13.04 changed to suit vagrant-lxc needs - -set -e - -if [ -r /etc/default/lxc ]; then - . /etc/default/lxc -fi - -SUITE=${SUITE:-wheezy} -MIRROR=${MIRROR:-http://ftp.debian.org/debian} - -configure_debian() -{ - rootfs=$1 - hostname=$2 - release=$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 < $rootfs/etc/inittab -id:3: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 -p6::ctrlaltdel:/sbin/init 6 -p0::powerfail:/sbin/init 0 -EOF - - # disable selinux in debian - mkdir -p $rootfs/selinux - echo 0 > $rootfs/selinux/enforce - - # configure the network using the dhcp - cat < $rootfs/etc/network/interfaces -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 -ff02::3 ip6-allhosts -EOF - - # set default locale - cat < $rootfs/etc/locale.gen -en_US.UTF-8 UTF-8 -EOF - echo "default locale set to en_US.UTF-8 UTF-8" - chroot $rootfs locale-gen 'en_US.UTF-8' > /dev/null 2>&1 - chroot $rootfs update-locale LANG='en_US.UTF-8' - echo 'update-locale done' - - # remove pointless services in a container - chroot $rootfs /usr/sbin/update-rc.d -f checkroot.sh remove - chroot $rootfs /usr/sbin/update-rc.d -f umountfs remove - chroot $rootfs /usr/sbin/update-rc.d -f hwclock.sh remove - chroot $rootfs /usr/sbin/update-rc.d -f hwclockfirst.sh remove - - echo "root:vagrant" | chroot $rootfs chpasswd - - if ! (grep -q vagrant $rootfs/etc/passwd); then - chroot $rootfs useradd --create-home -s /bin/bash vagrant - echo "vagrant:vagrant" | chroot $rootfs chpasswd - chroot $rootfs adduser vagrant sudo >/dev/null 2>&1 || true - chroot $rootfs cp /etc/sudoers /etc/sudoers.orig >/dev/null 2>&1 || true - chroot $rootfs sed -i -e \ - 's/%sudo\s\+ALL=(ALL\(:ALL\)\?)\s\+ALL/%sudo ALL=NOPASSWD:ALL/g' \ - /etc/sudoers >/dev/null 2>&1 || true - fi - - return 0 -} - -cleanup() -{ - rm -rf ${cache}/partial - rm -rf ${cache}/rootfs -} - -extract_rootfs() -{ - tarball=$1 - arch=$2 - rootfs=$3 - - echo "Extracting $tarball ..." - mkdir -p $(dirname $rootfs) - (cd `dirname $rootfs` && tar xfz $tarball) - return 0 -} - -install_debian() -{ - 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 - - # 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 <> $path/config -lxc.network.hwaddr = 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//') -EOF - fi - - grep -q "^lxc.rootfs" $path/config 2>/dev/null || echo "lxc.rootfs = $rootfs" >> $path/config - cat <> $path/config -lxc.tty = 4 -lxc.pts = 1024 -lxc.utsname = ${name} - -# When using LXC with apparmor, uncomment the next line to run 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 - -# mounts point -lxc.mount.entry = proc proc proc nodev,noexec,nosuid 0 0 -lxc.mount.entry = sysfs sys sysfs defaults 0 0 -EOF - - if [ $? -ne 0 ]; then - echo 'failed to add configuration' - return 1 - fi - -} - - -add_ssh_key() -{ - user=$1 - - 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 -} - -disable_tmp_cleanup() { - rootfs=$1 - 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 -} - -usage() -{ - cat <] [ -S | --auth-key ] -release: the debian release (e.g. wheezy): defaults to host release on debian, otherwise uses latest stable -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:Fd:C -l arch:,help,path:,release:,name:,flush-cache,auth-key:,debug:,tarball: -- "$@") -if [ $? -ne 0 ]; then - usage $(basename $0) - exit 1 -fi -eval set -- "$options" - -release=wheezy # Default to the last Debian stable release - -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 -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;; - -S|--auth-key) auth_key=$2; shift 2;; - -a|--arch) arch=$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_debian $rootfs $release $tarball -if [ $? -ne 0 ]; then - echo "failed to install debian $release" - exit 1 -fi - -configure_debian $rootfs $release -if [ $? -ne 0 ]; then - echo "failed to configure debian $release for a container" - exit 1 -fi - -copy_configuration $path $rootfs $name -if [ $? -ne 0 ]; then - echo "failed write configuration file" - exit 1 -fi - -add_ssh_key vagrant - -# vagrant and / or plugins might mount some shared folders under /tmp by default -# (like puppet manifests) and we need to make sure no shared folder gets its -# contents removed because of it. For more information, please check: -# https://github.com/fgrehm/vagrant-lxc/issues/68 -disable_tmp_cleanup $rootfs - -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/debian/metadata.json.template b/boxes/debian/metadata.json.template deleted file mode 100644 index 70f414b..0000000 --- a/boxes/debian/metadata.json.template +++ /dev/null @@ -1,9 +0,0 @@ -{ - "provider": "lxc", - "version": "2", - - "template-opts": { - "--arch": "ARCH", - "--release": "RELEASE" - } -} diff --git a/boxes/ubuntu/download b/boxes/ubuntu/download deleted file mode 100755 index 6a26207..0000000 --- a/boxes/ubuntu/download +++ /dev/null @@ -1,113 +0,0 @@ -#!/bin/bash - -# This is the code extracted from /usr/share/lxc/templates/lxc-ubuntu -# that comes with Ubuntu 12.10 which is responsible for downloading the -# rootfs files / packages - -set -e - -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." -} - -cleanup() -{ - rm -rf $cache/partial - rm -rf $cache/rootfs -} - -write_sourceslist() -{ - # $1 => path to the rootfs - - MIRROR=${MIRROR:-http://archive.ubuntu.com/ubuntu} - SECURITY_MIRROR=${SECURITY_MIRROR:-http://security.ubuntu.com/ubuntu} - - 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 -} - -download_ubuntu() -{ - packages=vim,ssh,curl,wget,bash-completion,manpages,man-db,psmisc - - # 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" - if [ $? -ne 0 ]; then - echo "Failed to create '$cache/partial' 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 $MIRROR - else - debootstrap --verbose --components=main,universe --arch=$arch --include=$packages $release $cache/partial $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/etc/apt/sources.list - write_sourceslist $cache/partial/ $arch - - chroot "$1/partial" apt-get update - if [ $? -ne 0 ]; then - echo "Failed to update the apt cache" - return 1 - fi - cat > "$1/partial"/usr/sbin/policy-rc.d << EOF -#!/bin/sh -exit 101 -EOF - chmod +x "$1/partial"/usr/sbin/policy-rc.d - - lxc-unshare -s MOUNT -- chroot "$1/partial" apt-get dist-upgrade -y || { suggest_flush; false; } - - rm -f "$1/partial"/usr/sbin/policy-rc.d - - chroot "$1/partial" apt-get clean - - mv "$1/partial" "$1/rootfs" - trap EXIT - trap SIGINT - trap SIGTERM - trap SIGHUP - echo "Download complete" - return 0 -} - -declare cache=`readlink -f .` \ - arch=$1 \ - release=$2 - -if [ -d "${cache}/rootfs" ]; then - echo 'The rootfs cache has been built already, please remove it if you want to update' - exit 1 -fi - -download_ubuntu $cache $arch $release diff --git a/boxes/ubuntu/finalize b/boxes/ubuntu/finalize deleted file mode 100755 index 8b6e273..0000000 --- a/boxes/ubuntu/finalize +++ /dev/null @@ -1,374 +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 - -configure_ubuntu() -{ - rootfs=$1 - release=$2 - hostname=$2 - - # 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 -ff02::3 ip6-allhosts -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 ! (grep -q vagrant $rootfs/etc/passwd); then - chroot $rootfs useradd --create-home -s /bin/bash vagrant - echo "vagrant:vagrant" | chroot $rootfs chpasswd - fi - - # make sure we have the current locale defined in the container - chroot $rootfs locale-gen en_US.UTF-8 - chroot $rootfs update-locale LANG=en_US.UTF-8 - - return 0 -} - -# finish setting up the user in the container by injecting ssh key and -# adding sudo group membership. -# passed-in user is 'vagrant' -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 - - chroot $rootfs cp /etc/sudoers /etc/sudoers.orig >/dev/null 2>&1 || true - chroot $rootfs sed -i -e 's/%sudo\s\+ALL=(ALL:ALL)\s\+ALL/%sudo ALL=NOPASSWD:ALL/g' /etc/sudoers >/dev/null 2>&1 || true - - 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 -deb-src [arch=$2] $MIRROR ${release} main restricted universe multiverse -deb-src [arch=$2] $MIRROR ${release}-updates main restricted universe multiverse -deb-src [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 -deb-src $MIRROR ${release} main restricted universe multiverse -deb-src $MIRROR ${release}-updates main restricted universe multiverse -deb-src $SECURITY_MIRROR ${release}-security main restricted universe multiverse -EOF - fi -} - -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 /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 -} - -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 - - -if [ "$(id -u)" != "0" ]; then - echo "This script should be run as 'root'" - exit 1 -fi - -declare cache=`readlink -f .` \ - arch=$1 \ - release=$2 \ - auth_key=$3 - -# detect rootfs -cache=`readlink -f .` -rootfs="${cache}/rootfs" - -configure_ubuntu $rootfs $release -if [ $? -ne 0 ]; then - echo "failed to configure ubuntu $release for a container" - exit 1 -fi - -post_process $rootfs $release $trim_container - -finalize_user vagrant - -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/ubuntu/lxc-template b/boxes/ubuntu/lxc-template deleted file mode 100755 index da81453..0000000 --- a/boxes/ubuntu/lxc-template +++ /dev/null @@ -1,559 +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 - -configure_ubuntu() -{ - rootfs=$1 - release=$2 - hostname=$2 - - # 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 -ff02::3 ip6-allhosts -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 ! (grep -q vagrant $rootfs/etc/passwd); then - chroot $rootfs useradd --create-home -s /bin/bash vagrant - echo "vagrant:vagrant" | chroot $rootfs chpasswd - fi - - # make sure we have the current locale defined in the container - chroot $rootfs locale-gen en_US.UTF-8 - chroot $rootfs update-locale LANG=en_US.UTF-8 - - return 0 -} - -# finish setting up the user in the container by injecting ssh key and -# adding sudo group membership. -# passed-in user is 'vagrant' -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 - - chroot $rootfs cp /etc/sudoers /etc/sudoers.orig >/dev/null 2>&1 || true - chroot $rootfs sed -i -e 's/%sudo\s\+ALL=(ALL:ALL)\s\+ALL/%sudo ALL=NOPASSWD:ALL/g' /etc/sudoers >/dev/null 2>&1 || true - - 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 -} - -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 - arch=$4 - - 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 - -# When using LXC with apparmor, uncomment the next line to run 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 < $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 < $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 /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 -} - -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 - -configure_ubuntu $rootfs $release -if [ $? -ne 0 ]; then - echo "failed to configure ubuntu $release for a container" - 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 - -finalize_user vagrant - -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/ubuntu/metadata.json.template b/boxes/ubuntu/metadata.json.template deleted file mode 100644 index 70f414b..0000000 --- a/boxes/ubuntu/metadata.json.template +++ /dev/null @@ -1,9 +0,0 @@ -{ - "provider": "lxc", - "version": "2", - - "template-opts": { - "--arch": "ARCH", - "--release": "RELEASE" - } -} diff --git a/tasks/boxes.rake b/tasks/boxes.rake index 94dc35b..82f7ce4 100644 --- a/tasks/boxes.rake +++ b/tasks/boxes.rake @@ -1,87 +1,158 @@ +require 'time' require 'pathname' require 'rake/tasklib' -load 'tasks/boxes.v2.rake' -class BuildGenericBoxTaskV3 < BuildGenericBoxTaskV2 +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 - require 'vagrant' - check_if_box_has_been_built! FileUtils.mkdir_p 'boxes/temp' unless File.exist? 'base/temp' check_for_partially_built_box! - pwd = Dir.pwd - sh 'mkdir -p boxes/temp/' - Dir.chdir 'boxes/temp' do - download - install_cfg_engines - finalize - prepare_package_contents pwd - sh 'sudo rm -rf rootfs' - sh "tar -czf tmp-package.box ./*" + import_template do |template| + create_base_container(template) do |rootfs| + configure_vagrant_user(rootfs) + install_cfg_engines(rootfs) + prepare_package_contents(rootfs) + compress_box(rootfs) + cleanup(rootfs) + end end - - sh 'mkdir -p boxes/output' - sh "cp boxes/temp/tmp-package.box boxes/output/#{@file}" - sh "rm -rf boxes/temp" end - def finalize - auth_key = Vagrant.source_root.join('keys', 'vagrant.pub').expand_path.to_s - run 'finalize', @arch, @release, auth_key + def check_if_box_has_been_built! + return unless File.exists?("./boxes/output/#{@file}") + + puts 'Box has been built already!' + exit 1 end - def prepare_package_contents(pwd) - run 'cleanup' - sh 'sudo rm -f rootfs.tar.gz' - sh 'sudo tar --numeric-owner -czf rootfs.tar.gz ./rootfs/*' - sh "sudo chown #{ENV['USER']}:#{`id -gn`.strip} rootfs.tar.gz" - sh "cp #{pwd}/boxes/common/lxc-template ." - sh "cp #{pwd}/boxes/common/lxc.conf ." - sh "cp #{pwd}/boxes/common/metadata.json ." + 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) + puts "TODO: Create base container with #{template}" + yield "/var/lib/lxc/vagrant-base-box-tmp/rootfs" + end + + def configure_vagrant_user(rootfs) + puts "TODO: Configure vagrant user under #{rootfs}" + 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-tmp" + 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 BuildDebianBoxTaskV3 < BuildGenericBoxTaskV3 +class BuildDebianBoxTask < BuildGenericBoxTask def initialize(name, release, arch, opts = {}) super(name, 'debian', release, arch, opts) end end -class BuildUbuntuBoxTaskV3 < BuildGenericBoxTaskV3 +class BuildUbuntuBoxTask < BuildGenericBoxTask def initialize(name, release, arch, opts = {}) super(name, 'ubuntu', release, arch, opts) end end -puppet = ENV['PUPPET'] == '1' -babushka = ENV['BABUSHKA'] == '1' -salt = ENV['SALT'] == '1' +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' - BuildUbuntuBoxTaskV3. - new(:precise64, - :precise, 'amd64', puppet: puppet, babushka: babushka, salt: salt) + BuildUbuntuBoxTask.new(:precise64, :precise, 'amd64', cfg_engines) desc 'Build an Ubuntu Quantal 64 bits box' - BuildUbuntuBoxTaskV3. - new(:quantal64, - :quantal, 'amd64', puppet: puppet, babushka: babushka, salt: salt) + BuildUbuntuBoxTask.new(:quantal64, :quantal, 'amd64', cfg_engines) desc 'Build an Ubuntu Raring 64 bits box' - BuildUbuntuBoxTaskV3. - new(:raring64, - :raring, 'amd64', puppet: puppet, babushka: babushka, salt: salt) + BuildUbuntuBoxTask.new(:raring64, :raring, 'amd64', cfg_engines) desc 'Build an Ubuntu Saucy 64 bits box' - BuildUbuntuBoxTaskV3. - new(:saucy64, - :saucy, 'amd64', puppet: puppet, babushka: babushka, salt: salt) + BuildUbuntuBoxTask.new(:saucy64, :saucy, 'amd64', cfg_engines) desc 'Build all Ubuntu boxes' task :all => %w( precise64 quantal64 raring64 saucy64 ) @@ -89,21 +160,16 @@ namespace :boxes do 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' - BuildDebianBoxTaskV3. - new(:squeeze64, - :squeeze, 'amd64', puppet: puppet, babushka: babushka, salt: false) + BuildDebianBoxTask.new(:squeeze64, :squeeze, 'amd64', cfg_engines) desc 'Build an Debian Wheezy 64 bits box' - BuildDebianBoxTaskV3. - new(:wheezy64, - :wheezy, 'amd64', puppet: puppet, babushka: babushka, salt: false) + BuildDebianBoxTask.new(:wheezy64, :wheezy, 'amd64', cfg_engines) desc 'Build an Debian Sid/unstable 64 bits box' - BuildDebianBoxTaskV3. - new(:sid64, - :sid, 'amd64', puppet: puppet, babushka: babushka, salt: false) + BuildDebianBoxTask.new(:sid64, :sid, 'amd64', cfg_engines) desc 'Build all Debian boxes' task :all => %w( squeeze64 wheezy64 sid64 ) From a1c7a4ece000619dd837130ae279fc64f4221fcd Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Fri, 30 Aug 2013 17:51:27 -0300 Subject: [PATCH 03/20] Add ubuntu lxc template from staging (https://github.com/lxc/lxc/blob/188e0ab60bda276c688ad15877c6d6402081c6c9/templates/lxc-ubuntu.in) --- boxes/templates/ubuntu | 799 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 799 insertions(+) create mode 100755 boxes/templates/ubuntu diff --git a/boxes/templates/ubuntu b/boxes/templates/ubuntu new file mode 100755 index 0000000..4245fb9 --- /dev/null +++ b/boxes/templates/ubuntu @@ -0,0 +1,799 @@ +#!/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@LOCALSTATEDIR@/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 @LOCALSTATEDIR@/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 + + 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="@LOCALSTATEDIR@/cache/lxc/$release" + mkdir -p @LOCALSTATEDIR@/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>@LOCALSTATEDIR@/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 /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 + +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 "" From 739e602794b9683d7a0db89342dc9d111cb8400d Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Fri, 30 Aug 2013 18:08:51 -0300 Subject: [PATCH 04/20] %s/@LOCALSTATEDIR@/\/var/g --- boxes/templates/ubuntu | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/boxes/templates/ubuntu b/boxes/templates/ubuntu index 4245fb9..e962166 100755 --- a/boxes/templates/ubuntu +++ b/boxes/templates/ubuntu @@ -92,7 +92,7 @@ EOF fi # generate new SSH keys - if [ -x $rootfs@LOCALSTATEDIR@/lib/dpkg/info/openssh-server.postinst ]; then + if [ -x $rootfs/var/lib/dpkg/info/openssh-server.postinst ]; then cat > $rootfs/usr/sbin/policy-rc.d << EOF #!/bin/sh exit 101 @@ -101,7 +101,7 @@ EOF 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 @LOCALSTATEDIR@/lib/dpkg/info/openssh-server.postinst configure + 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 @@ -313,8 +313,8 @@ install_ubuntu() rootfs=$1 release=$2 flushcache=$3 - cache="@LOCALSTATEDIR@/cache/lxc/$release" - mkdir -p @LOCALSTATEDIR@/lock/subsys/ + cache="/var/cache/lxc/$release" + mkdir -p /var/lock/subsys/ ( flock -x 200 @@ -348,7 +348,7 @@ install_ubuntu() return 0 - ) 200>@LOCALSTATEDIR@/lock/subsys/lxc-ubuntu + ) 200>/var/lock/subsys/lxc-ubuntu return $? } From 61e7cbce42f7de5a084589b69be02b92486c63b3 Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Fri, 30 Aug 2013 18:17:28 -0300 Subject: [PATCH 05/20] boxes/ubuntu: create base container --- tasks/boxes.rake | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tasks/boxes.rake b/tasks/boxes.rake index 82f7ce4..84fd25e 100644 --- a/tasks/boxes.rake +++ b/tasks/boxes.rake @@ -43,9 +43,9 @@ class BuildGenericBoxTask < ::Rake::TaskLib create_base_container(template) do |rootfs| configure_vagrant_user(rootfs) install_cfg_engines(rootfs) + cleanup(rootfs) prepare_package_contents(rootfs) compress_box(rootfs) - cleanup(rootfs) end end end @@ -67,8 +67,11 @@ class BuildGenericBoxTask < ::Rake::TaskLib end def create_base_container(template) - puts "TODO: Create base container with #{template}" - yield "/var/lib/lxc/vagrant-base-box-tmp/rootfs" + 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 configure_vagrant_user(rootfs) @@ -92,7 +95,7 @@ class BuildGenericBoxTask < ::Rake::TaskLib end def import_template - template_name = "vagrant-base-box-tmp" + template_name = "vagrant-base-box-template" tmp_template_path = templates_path.join("lxc-#{template_name}") src = "./boxes/templates/#{@distrib}" From 03b262319f7750b0df190c8e4371f4245af48b25 Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Fri, 30 Aug 2013 18:22:07 -0300 Subject: [PATCH 06/20] boxes/ubuntu: Configure vagrant user This commit applies @smaftoul patch from https://gist.github.com/smaftoul/2d6fcf43b7c6545aa588/revisions --- boxes/templates/ubuntu | 12 ++++++++++++ tasks/boxes.rake | 5 ----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/boxes/templates/ubuntu b/boxes/templates/ubuntu index e962166..59e7841 100755 --- a/boxes/templates/ubuntu +++ b/boxes/templates/ubuntu @@ -117,6 +117,8 @@ 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 @@ -513,6 +515,9 @@ 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' @@ -787,6 +792,13 @@ 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 diff --git a/tasks/boxes.rake b/tasks/boxes.rake index 84fd25e..3897e71 100644 --- a/tasks/boxes.rake +++ b/tasks/boxes.rake @@ -41,7 +41,6 @@ class BuildGenericBoxTask < ::Rake::TaskLib import_template do |template| create_base_container(template) do |rootfs| - configure_vagrant_user(rootfs) install_cfg_engines(rootfs) cleanup(rootfs) prepare_package_contents(rootfs) @@ -74,10 +73,6 @@ class BuildGenericBoxTask < ::Rake::TaskLib sh "sudo lxc-destroy -n #{container_name}" end - def configure_vagrant_user(rootfs) - puts "TODO: Configure vagrant user under #{rootfs}" - end - def install_cfg_engines(rootfs) puts "TODO: Install cfg engines under #{rootfs}" end From 37aeabbeff90d9d0a30e704f0f74e9bcac1ad298 Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Wed, 18 Sep 2013 22:52:47 -0300 Subject: [PATCH 07/20] Add new bash script to build base ubuntu box --- boxes/build-ubuntu-box.sh | 86 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100755 boxes/build-ubuntu-box.sh diff --git a/boxes/build-ubuntu-box.sh b/boxes/build-ubuntu-box.sh new file mode 100755 index 0000000..1e3a90f --- /dev/null +++ b/boxes/build-ubuntu-box.sh @@ -0,0 +1,86 @@ +#!/bin/bash + +# Script used to build Ubuntu base vagrant-lxc containers +# USAGE: +# $ sudo ./build-ubuntu-box.sh UBUNTU_RELEASE BOX_ARCH + +# TODO: * Add support for flushing cache and specifying a custom base Ubuntu lxc +# template instead of system's built in +# * Embed vagrant public key + +################################################################################## +# 1 - Create the base container + +RELEASE=${1:-"raring"} +ARCH=${2:-"amd64"} + +lxc-create -n ${RELEASE}-base -t ubuntu -- --release ${RELEASE} --arch ${ARCH} + + +################################################################################## +# 2 - Prepare vagrant user + +ROOTFS=/var/lib/lxc/${RELEASE}-base/rootfs +chroot ${ROOTFS} usermod -l vagrant -d /home/vagrant ubuntu + +echo -n 'vagrant:vagrant' | chroot ${ROOTFS} chpasswd + + +################################################################################## +# 3 - Setup SSH access and passwordless sudo + +# Configure SSH access +mkdir -p ${ROOTFS}/home/vagrant/.ssh +wget https://raw.github.com/mitchellh/vagrant/master/keys/vagrant.pub -O ${ROOTFS}/home/vagrant/.ssh/authorized_keys +chroot ${ROOTFS} chown -R vagrant: /home/vagrant/.ssh + +# Enable passwordless sudo for users under the "sudo" group +cp ${ROOTFS}/etc/sudoers{,.orig} +sed -i -e \ + 's/%sudo\s\+ALL=(ALL\(:ALL\)\?)\s\+ALL/%sudo ALL=NOPASSWD:ALL/g' \ + ${ROOTFS}/etc/sudoers + + +################################################################################## +# 4 - Add some goodies + +PACKAGES=(vim curl wget manpages bash-completion) +chroot ${ROOTFS} apt-get install ${PACKAGES[*]} -y --force-yes + + +################################################################################## +# 5 - Configuration management tools + + +# TODO + + +################################################################################## +# 6 - Free up some disk space + +rm -rf ${ROOTFS}/tmp/* +chroot ${ROOTFS} apt-get clean + + +################################################################################## +# 7 - Build box package + +# Set up a working dir +mkdir -p /tmp/vagrant-lxc-${RELEASE} + +# Compress container's rootfs +cd /var/lib/lxc/${RELEASE}-base +tar --numeric-owner -czf /tmp/vagrant-lxc-${RELEASE}/rootfs.tar.gz ./rootfs/* + +# Prepare package contents +cd /tmp/vagrant-lxc-${RELEASE} +wget https://raw.github.com/fgrehm/vagrant-lxc/master/boxes/common/lxc-template +wget https://raw.github.com/fgrehm/vagrant-lxc/master/boxes/common/lxc.conf +wget https://raw.github.com/fgrehm/vagrant-lxc/master/boxes/common/metadata.json +chmod +x lxc-template + +# Vagrant box! +PKG=vagrant-lxc-${RELEASE}-${ARCH}.box +tar -czf $PKG ./* + +echo "The base box was built successfully to ${PKG}" From 379b030f64a7ce75c98e78ba593980ea248e3ffb Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Thu, 19 Sep 2013 01:41:02 -0300 Subject: [PATCH 08/20] :bomb: old stuff --- boxes/build-ubuntu-box.sh | 2 + boxes/common/lxc-template | 229 ----------- boxes/templates/ubuntu | 811 -------------------------------------- tasks/boxes.rake | 179 --------- 4 files changed, 2 insertions(+), 1219 deletions(-) delete mode 100755 boxes/common/lxc-template delete mode 100755 boxes/templates/ubuntu delete mode 100644 tasks/boxes.rake 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 From 7efef2a489bd2ea8b1e014ec69eefaa43120e846 Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Thu, 19 Sep 2013 12:02:14 -0300 Subject: [PATCH 09/20] Just enough code to deal with building base ubuntu boxes with support for configuration management tools --- boxes/build-ubuntu-box.sh | 75 ++++++++++++++++++++++++++++------- boxes/common/install-babushka | 5 +-- boxes/common/install-chef | 3 +- boxes/common/install-puppet | 3 +- boxes/common/install-salt | 3 +- 5 files changed, 66 insertions(+), 23 deletions(-) diff --git a/boxes/build-ubuntu-box.sh b/boxes/build-ubuntu-box.sh index 1e3e902..76de546 100755 --- a/boxes/build-ubuntu-box.sh +++ b/boxes/build-ubuntu-box.sh @@ -1,29 +1,67 @@ #!/bin/bash +# set -x +set -e + # Script used to build Ubuntu base vagrant-lxc containers +# # USAGE: -# $ sudo ./build-ubuntu-box.sh UBUNTU_RELEASE BOX_ARCH +# $ cd boxes && sudo ./build-ubuntu-box.sh UBUNTU_RELEASE BOX_ARCH +# +# To enable Chef or any other configuration management tool pass '1' to it: +# $ CHEF=1 sudo -E ./build-ubuntu-box.sh UBUNTU_RELEASE BOX_ARCH +# $ PUPPET=1 sudo -E ./build-ubuntu-box.sh UBUNTU_RELEASE BOX_ARCH +# $ SALT=1 sudo -E ./build-ubuntu-box.sh UBUNTU_RELEASE BOX_ARCH +# $ BABUSHKA=1 sudo -E ./build-ubuntu-box.sh UBUNTU_RELEASE BOX_ARCH # 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 +# * Stuff from locales (rcarmo and discourse stuff) +# * Clean up when finished + +################################################################################## +# 0 - Initial setup and sanity checks + +RELEASE=${1:-"raring"} +ARCH=${2:-"amd64"} +PKG=vagrant-lxc-${RELEASE}-${ARCH}.box +WORKING_DIR=/tmp/vagrant-lxc-${RELEASE} + +# Providing '1' will enable these tools +CHEF=${CHEF:-0} +PUPPET=${PUPPET:-0} +SALT=${SALT:-0} +BABUSHKA=${BABUSHKA:-0} + +# Set up a working dir +mkdir -p $WORKING_DIR + +if [ -f "${WORKING_DIR}/${PKG}" ]; then + echo "Found a box on ${WORKING_DIR}/${PKG} already!" + exit 1 +fi ################################################################################## # 1 - Create the base container -RELEASE=${1:-"raring"} -ARCH=${2:-"amd64"} - -lxc-create -n ${RELEASE}-base -t ubuntu -- --release ${RELEASE} --arch ${ARCH} +if $(lxc-ls | grep -q "${RELEASE}-base"); then + echo "Base container already exists, please remove it with \`lxc-destroy -n ${RELEASE}-base\`!" + exit 1 +else + lxc-create -n ${RELEASE}-base -t ubuntu -- --release ${RELEASE} --arch ${ARCH} +fi ################################################################################## # 2 - Prepare vagrant user ROOTFS=/var/lib/lxc/${RELEASE}-base/rootfs +mv ${ROOTFS}/home/{ubuntu,vagrant} chroot ${ROOTFS} usermod -l vagrant -d /home/vagrant ubuntu +chroot ${ROOTFS} groupmod -n vagrant ubuntu echo -n 'vagrant:vagrant' | chroot ${ROOTFS} chpasswd @@ -46,15 +84,28 @@ sed -i -e \ ################################################################################## # 4 - Add some goodies -PACKAGES=(vim curl wget manpages bash-completion) +PACKAGES=(vim curl wget man-db bash-completion) chroot ${ROOTFS} apt-get install ${PACKAGES[*]} -y --force-yes ################################################################################## # 5 - Configuration management tools +if [ $CHEF = 1 ]; then + ./common/install-chef $ROOTFS +fi -# TODO +if [ $PUPPET = 1 ]; then + ./common/install-puppet $ROOTFS +fi + +if [ $SALT = 1 ]; then + ./common/install-salt $ROOTFS +fi + +if [ $BABUSHKA = 1 ]; then + ./common/install-babushka $ROOTFS +fi ################################################################################## @@ -67,22 +118,18 @@ chroot ${ROOTFS} apt-get clean ################################################################################## # 7 - Build box package -# Set up a working dir -mkdir -p /tmp/vagrant-lxc-${RELEASE} - # Compress container's rootfs -cd /var/lib/lxc/${RELEASE}-base +cd $(dirname $ROOTFS) tar --numeric-owner -czf /tmp/vagrant-lxc-${RELEASE}/rootfs.tar.gz ./rootfs/* # Prepare package contents -cd /tmp/vagrant-lxc-${RELEASE} +cd $WORKING_DIR wget https://raw.github.com/fgrehm/vagrant-lxc/master/boxes/common/lxc-template wget https://raw.github.com/fgrehm/vagrant-lxc/master/boxes/common/lxc.conf wget https://raw.github.com/fgrehm/vagrant-lxc/master/boxes/common/metadata.json chmod +x lxc-template # Vagrant box! -PKG=vagrant-lxc-${RELEASE}-${ARCH}.box tar -czf $PKG ./* -echo "The base box was built successfully to ${PKG}" +echo "The base box was built successfully to ${WORKING_DIR}/${PKG}" diff --git a/boxes/common/install-babushka b/boxes/common/install-babushka index 23a7455..6d43d76 100755 --- a/boxes/common/install-babushka +++ b/boxes/common/install-babushka @@ -1,12 +1,11 @@ #!/bin/bash -cache=`readlink -f .` -rootfs="${cache}/rootfs" +rootfs=$1 echo "installing babushka" cat > $rootfs/tmp/install-babushka.sh << EOF #!/bin/sh -curl -L https://babushka.me/up | sudo bash < /dev/null +curl https://babushka.me/up | sudo bash EOF chmod +x $rootfs/tmp/install-babushka.sh diff --git a/boxes/common/install-chef b/boxes/common/install-chef index 55fd5e3..d99d0d7 100755 --- a/boxes/common/install-chef +++ b/boxes/common/install-chef @@ -1,7 +1,6 @@ #!/bin/bash -cache=`readlink -f .` -rootfs="${cache}/rootfs" +rootfs=$1 echo "installing chef" cat > $rootfs/tmp/install-chef.sh << EOF diff --git a/boxes/common/install-puppet b/boxes/common/install-puppet index a746229..1e1650e 100755 --- a/boxes/common/install-puppet +++ b/boxes/common/install-puppet @@ -1,7 +1,6 @@ #!/bin/bash -cache=`readlink -f .` -rootfs="${cache}/rootfs" +rootfs=$1 echo "installing puppet" wget http://apt.puppetlabs.com/puppetlabs-release-stable.deb -O "${rootfs}/tmp/puppetlabs-release-stable.deb" diff --git a/boxes/common/install-salt b/boxes/common/install-salt index daab9ab..e7f74a2 100755 --- a/boxes/common/install-salt +++ b/boxes/common/install-salt @@ -1,7 +1,6 @@ #!/bin/bash -cache=`readlink -f .` -rootfs="${cache}/rootfs" +rootfs=$1 echo "installing salt" chroot $rootfs apt-add-repository -y ppa:saltstack/salt From e1f91efc3ac181e26eb62eb1967ddf6c67565100 Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Thu, 19 Sep 2013 18:14:09 -0300 Subject: [PATCH 10/20] apt-get upgrade when building base boxes --- boxes/build-ubuntu-box.sh | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/boxes/build-ubuntu-box.sh b/boxes/build-ubuntu-box.sh index 76de546..da387aa 100755 --- a/boxes/build-ubuntu-box.sh +++ b/boxes/build-ubuntu-box.sh @@ -8,11 +8,12 @@ set -e # USAGE: # $ cd boxes && sudo ./build-ubuntu-box.sh UBUNTU_RELEASE BOX_ARCH # -# To enable Chef or any other configuration management tool pass '1' to it: -# $ CHEF=1 sudo -E ./build-ubuntu-box.sh UBUNTU_RELEASE BOX_ARCH -# $ PUPPET=1 sudo -E ./build-ubuntu-box.sh UBUNTU_RELEASE BOX_ARCH -# $ SALT=1 sudo -E ./build-ubuntu-box.sh UBUNTU_RELEASE BOX_ARCH -# $ BABUSHKA=1 sudo -E ./build-ubuntu-box.sh UBUNTU_RELEASE BOX_ARCH +# To enable Chef or any other configuration management tool pass '1' to the +# corresponding env var: +# $ CHEF=1 sudo -E ./build-ubuntu-box.sh UBUNTU_RELEASE BOX_ARCH +# $ PUPPET=1 sudo -E ./build-ubuntu-box.sh UBUNTU_RELEASE BOX_ARCH +# $ SALT=1 sudo -E ./build-ubuntu-box.sh UBUNTU_RELEASE BOX_ARCH +# $ BABUSHKA=1 sudo -E ./build-ubuntu-box.sh UBUNTU_RELEASE BOX_ARCH # TODO: * Add support for flushing cache and specifying a custom base Ubuntu lxc # template instead of system's built in @@ -21,6 +22,8 @@ set -e # * Ensure it is in sync with master # * Stuff from locales (rcarmo and discourse stuff) # * Clean up when finished +# * Add vagrant-lxc version to base box manifest and create an wiki page +# for describing it ################################################################################## # 0 - Initial setup and sanity checks @@ -82,10 +85,11 @@ sed -i -e \ ################################################################################## -# 4 - Add some goodies +# 4 - Add some goodies and update packages PACKAGES=(vim curl wget man-db bash-completion) chroot ${ROOTFS} apt-get install ${PACKAGES[*]} -y --force-yes +chroot ${ROOTFS} apt-get upgrade -y --force-yes ################################################################################## From 076a9e38dff293ed503b7994554fa37eb4103e10 Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Thu, 19 Sep 2013 18:15:56 -0300 Subject: [PATCH 11/20] Bring back "generic" template that was accidentally removed --- boxes/common/lxc-template | 229 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100755 boxes/common/lxc-template diff --git a/boxes/common/lxc-template b/boxes/common/lxc-template new file mode 100755 index 0000000..9e53be4 --- /dev/null +++ b/boxes/common/lxc-template @@ -0,0 +1,229 @@ +#!/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 "" From 50e82f61b17d4de444c797e0029a96d4e7a4b557 Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Thu, 19 Sep 2013 18:24:08 -0300 Subject: [PATCH 12/20] Remove unused arguments from generic lxc template and introduce support for the rootfs param --- boxes/common/lxc-template | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/boxes/common/lxc-template b/boxes/common/lxc-template index 9e53be4..a239a18 100755 --- a/boxes/common/lxc-template +++ b/boxes/common/lxc-template @@ -112,12 +112,8 @@ post_process() 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 +$1 -h|--help [-a|--arch] [--trim] [-d|--debug] [--rootfs ] [-T|--tarball arch: the container architecture (e.g. amd64): defaults to host arch -auth-key: SSH Public key file to inject into container EOF return 0 } @@ -162,12 +158,11 @@ 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;; -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 ;; @@ -179,7 +174,6 @@ if [ $debug -eq 1 ]; then set -x fi - if [ "$arch" == "i686" ]; then arch=i386 fi @@ -201,10 +195,13 @@ 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 +# 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 $tarball From 2f3d1c27ce0d3dcd1dc91724f10738af2ccb5400 Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Thu, 19 Sep 2013 18:41:23 -0300 Subject: [PATCH 13/20] Assume that we are running the ubuntu base box builder with a local checkout + add date / time to box metadata.json --- boxes/build-ubuntu-box.sh | 19 +++++++++++++------ boxes/common/metadata.json | 3 ++- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/boxes/build-ubuntu-box.sh b/boxes/build-ubuntu-box.sh index da387aa..1e870de 100755 --- a/boxes/build-ubuntu-box.sh +++ b/boxes/build-ubuntu-box.sh @@ -18,8 +18,6 @@ set -e # 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 # * Stuff from locales (rcarmo and discourse stuff) # * Clean up when finished # * Add vagrant-lxc version to base box manifest and create an wiki page @@ -28,9 +26,11 @@ set -e ################################################################################## # 0 - Initial setup and sanity checks +TODAY=$(date -u +"%Y-%m-%d") +NOW="${TODAY} $(date -u +'%H:%M:%S') UTC" RELEASE=${1:-"raring"} ARCH=${2:-"amd64"} -PKG=vagrant-lxc-${RELEASE}-${ARCH}.box +PKG=vagrant-lxc-${RELEASE}-${ARCH}-${TODAY}.box WORKING_DIR=/tmp/vagrant-lxc-${RELEASE} # Providing '1' will enable these tools @@ -39,6 +39,12 @@ PUPPET=${PUPPET:-0} SALT=${SALT:-0} BABUSHKA=${BABUSHKA:-0} +# Path to files bundled with the box +CWD=`readlink -f .` +LXC_TEMPLATE=${CWD}/common/lxc-template +LXC_CONF=${CWD}/common/lxc.conf +METATADA_JSON=${CWD}/common/metadata.json + # Set up a working dir mkdir -p $WORKING_DIR @@ -128,10 +134,11 @@ tar --numeric-owner -czf /tmp/vagrant-lxc-${RELEASE}/rootfs.tar.gz ./rootfs/* # Prepare package contents cd $WORKING_DIR -wget https://raw.github.com/fgrehm/vagrant-lxc/master/boxes/common/lxc-template -wget https://raw.github.com/fgrehm/vagrant-lxc/master/boxes/common/lxc.conf -wget https://raw.github.com/fgrehm/vagrant-lxc/master/boxes/common/metadata.json +cp $LXC_TEMPLATE . +cp $LXC_CONF . +cp $METATADA_JSON . chmod +x lxc-template +sed -i "s//${NOW}/" metadata.json # Vagrant box! tar -czf $PKG ./* diff --git a/boxes/common/metadata.json b/boxes/common/metadata.json index 824c6fd..4ae0cd3 100644 --- a/boxes/common/metadata.json +++ b/boxes/common/metadata.json @@ -1,4 +1,5 @@ { "provider": "lxc", - "version": "3" + "version": "3", + "built-on": "" } From 0f31b51e2d45dd73911fab9dc73f4f0ba1024cc4 Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Thu, 19 Sep 2013 18:58:06 -0300 Subject: [PATCH 14/20] Embed vagrant key into builder script to avoid downloading it all the time --- boxes/build-ubuntu-box.sh | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/boxes/build-ubuntu-box.sh b/boxes/build-ubuntu-box.sh index 1e870de..07c56e9 100755 --- a/boxes/build-ubuntu-box.sh +++ b/boxes/build-ubuntu-box.sh @@ -15,14 +15,6 @@ set -e # $ SALT=1 sudo -E ./build-ubuntu-box.sh UBUNTU_RELEASE BOX_ARCH # $ BABUSHKA=1 sudo -E ./build-ubuntu-box.sh UBUNTU_RELEASE BOX_ARCH -# TODO: * Add support for flushing cache and specifying a custom base Ubuntu lxc -# template instead of system's built in -# * Embed vagrant public key -# * Stuff from locales (rcarmo and discourse stuff) -# * Clean up when finished -# * Add vagrant-lxc version to base box manifest and create an wiki page -# for describing it - ################################################################################## # 0 - Initial setup and sanity checks @@ -32,6 +24,7 @@ RELEASE=${1:-"raring"} ARCH=${2:-"amd64"} PKG=vagrant-lxc-${RELEASE}-${ARCH}-${TODAY}.box WORKING_DIR=/tmp/vagrant-lxc-${RELEASE} +VAGRANT_KEY="ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key" # Providing '1' will enable these tools CHEF=${CHEF:-0} @@ -80,7 +73,7 @@ echo -n 'vagrant:vagrant' | chroot ${ROOTFS} chpasswd # Configure SSH access mkdir -p ${ROOTFS}/home/vagrant/.ssh -wget https://raw.github.com/mitchellh/vagrant/master/keys/vagrant.pub -O ${ROOTFS}/home/vagrant/.ssh/authorized_keys +echo $VAGRANT_KEY > ${ROOTFS}/home/vagrant/.ssh/authorized_keys chroot ${ROOTFS} chown -R vagrant: /home/vagrant/.ssh # Enable passwordless sudo for users under the "sudo" group From 22040ba4c2f3cd9a060d8f81b381d9646b199055 Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Fri, 20 Sep 2013 22:10:54 -0300 Subject: [PATCH 15/20] Add script for building debian base boxes --- boxes/build-debian-box.sh | 160 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100755 boxes/build-debian-box.sh diff --git a/boxes/build-debian-box.sh b/boxes/build-debian-box.sh new file mode 100755 index 0000000..751142a --- /dev/null +++ b/boxes/build-debian-box.sh @@ -0,0 +1,160 @@ +#!/bin/bash + +# set -x +set -e + +# Script used to build Debian base vagrant-lxc containers, currently limited to +# host's arch +# +# USAGE: +# $ cd boxes && sudo ./build-debian-box.sh DEBIAN_RELEASE +# +# To enable Chef or any other configuration management tool pass '1' to the +# corresponding env var: +# $ CHEF=1 sudo -E ./build-debian-box.sh DEBIAN_RELEASE +# $ PUPPET=1 sudo -E ./build-debian-box.sh DEBIAN_RELEASE +# $ SALT=1 sudo -E ./build-debian-box.sh DEBIAN_RELEASE +# $ BABUSHKA=1 sudo -E ./build-debian-box.sh DEBIAN_RELEASE + +################################################################################## +# 0 - Initial setup and sanity checks + +TODAY=$(date -u +"%Y-%m-%d") +NOW=$(date -u) +RELEASE=${1:-"wheezy"} +ARCH=$(dpkg --print-architecture) # This is what the Debian template will use under the hood +PKG=vagrant-lxc-${RELEASE}-${ARCH}-${TODAY}.box +WORKING_DIR=/tmp/vagrant-lxc-${RELEASE} +VAGRANT_KEY="ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key" +ROOTFS=/var/lib/lxc/${RELEASE}-base/rootfs + +# Providing '1' will enable these tools +CHEF=${CHEF:-0} +PUPPET=${PUPPET:-0} +SALT=${SALT:-0} +BABUSHKA=${BABUSHKA:-0} + +# Path to files bundled with the box +CWD=`readlink -f .` +LXC_TEMPLATE=${CWD}/common/lxc-template +LXC_CONF=${CWD}/common/lxc.conf +METATADA_JSON=${CWD}/common/metadata.json + +# Set up a working dir +mkdir -p $WORKING_DIR + +if [ -f "${WORKING_DIR}/${PKG}" ]; then + echo "Found a box on ${WORKING_DIR}/${PKG} already!" + exit 1 +fi + +################################################################################## +# 1 - Create the base container + +if $(lxc-ls | grep -q "${RELEASE}-base"); then + echo "Base container already exists, please remove it with \`lxc-destroy -n ${RELEASE}-base\`!" + exit 1 +else + export SUITE=$RELEASE + lxc-create -n ${RELEASE}-base -t debian +fi + + +###################################### +# 2 - Fix some known issues + +# Fixes some networking issues +# See https://github.com/fgrehm/vagrant-lxc/issues/91 for more info +sed -i -e "s/\(127.0.0.1\s\+localhost\)/\1\n127.0.1.1\t${RELEASE}-base\n/g" ${ROOTFS}/etc/hosts + +# Ensures that `/tmp` does not get cleared on halt +# See https://github.com/fgrehm/vagrant-lxc/issues/68 for more info +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 + +# Ensure locales are properly set, based on http://linux.livejournal.com/1880366.html +sed -i "s/^# en_US/en_US/" ${ROOTFS}/etc/locale.gen +chroot $ROOTFS /usr/sbin/locale-gen +chroot $ROOTFS update-locale LANG=en_US.UTF-8 + + +################################################################################## +# 3 - Prepare vagrant user +sudo chroot ${ROOTFS} useradd --create-home -s /bin/bash vagrant + +echo -n 'vagrant:vagrant' | chroot ${ROOTFS} chpasswd + + +################################################################################## +# 4 - Setup SSH access and passwordless sudo + +# Configure SSH access +mkdir -p ${ROOTFS}/home/vagrant/.ssh +echo $VAGRANT_KEY > ${ROOTFS}/home/vagrant/.ssh/authorized_keys +chroot ${ROOTFS} chown -R vagrant: /home/vagrant/.ssh + +chroot ${ROOTFS} apt-get install sudo -y --force-yes +chroot ${ROOTFS} adduser vagrant sudo + +# Enable passwordless sudo for users under the "sudo" group +cp ${ROOTFS}/etc/sudoers{,.orig} +sed -i -e \ + 's/%sudo\s\+ALL=(ALL\(:ALL\)\?)\s\+ALL/%sudo ALL=NOPASSWD:ALL/g' \ + ${ROOTFS}/etc/sudoers + + +################################################################################## +# 5 - Add some goodies and update packages + +PACKAGES=(vim curl wget man-db bash-completion ca-certificates) +chroot ${ROOTFS} apt-get install ${PACKAGES[*]} -y --force-yes +chroot ${ROOTFS} apt-get upgrade -y --force-yes + + +################################################################################## +# 6 - Configuration management tools + +if [ $CHEF = 1 ]; then + ./common/install-chef $ROOTFS +fi + +if [ $PUPPET = 1 ]; then + ./common/install-puppet $ROOTFS +fi + +if [ $SALT = 1 ]; then + ./common/install-salt $ROOTFS +fi + +if [ $BABUSHKA = 1 ]; then + ./common/install-babushka $ROOTFS +fi + + +################################################################################## +# 7 - Free up some disk space + +rm -rf ${ROOTFS}/tmp/* +chroot ${ROOTFS} apt-get clean + + +################################################################################## +# 8 - Build box package + +# Compress container's rootfs +cd $(dirname $ROOTFS) +tar --numeric-owner -czf /tmp/vagrant-lxc-${RELEASE}/rootfs.tar.gz ./rootfs/* + +# Prepare package contents +cd $WORKING_DIR +cp $LXC_TEMPLATE . +cp $LXC_CONF . +cp $METATADA_JSON . +chmod +x lxc-template +sed -i "s//${NOW}/" metadata.json + +# Vagrant box! +tar -czf $PKG ./* + +echo "The base box was built successfully to ${WORKING_DIR}/${PKG}" From c49dfc59ea6640007add724ad26fc6aa9642b9f5 Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Fri, 20 Sep 2013 22:12:26 -0300 Subject: [PATCH 16/20] Minor tweaks for the base ubuntu box script --- boxes/build-ubuntu-box.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boxes/build-ubuntu-box.sh b/boxes/build-ubuntu-box.sh index 07c56e9..880a96c 100755 --- a/boxes/build-ubuntu-box.sh +++ b/boxes/build-ubuntu-box.sh @@ -19,12 +19,13 @@ set -e # 0 - Initial setup and sanity checks TODAY=$(date -u +"%Y-%m-%d") -NOW="${TODAY} $(date -u +'%H:%M:%S') UTC" +NOW=$(date -u) RELEASE=${1:-"raring"} ARCH=${2:-"amd64"} PKG=vagrant-lxc-${RELEASE}-${ARCH}-${TODAY}.box WORKING_DIR=/tmp/vagrant-lxc-${RELEASE} VAGRANT_KEY="ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key" +ROOTFS=/var/lib/lxc/${RELEASE}-base/rootfs # Providing '1' will enable these tools CHEF=${CHEF:-0} @@ -60,7 +61,6 @@ fi ################################################################################## # 2 - Prepare vagrant user -ROOTFS=/var/lib/lxc/${RELEASE}-base/rootfs mv ${ROOTFS}/home/{ubuntu,vagrant} chroot ${ROOTFS} usermod -l vagrant -d /home/vagrant ubuntu chroot ${ROOTFS} groupmod -n vagrant ubuntu From 5f42f2b4dd51280bf3a0c042d77b8b0113a89cb1 Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Fri, 20 Sep 2013 23:01:24 -0300 Subject: [PATCH 17/20] Backport #91 --- boxes/build-ubuntu-box.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/boxes/build-ubuntu-box.sh b/boxes/build-ubuntu-box.sh index 880a96c..6d58fdf 100755 --- a/boxes/build-ubuntu-box.sh +++ b/boxes/build-ubuntu-box.sh @@ -57,6 +57,10 @@ else lxc-create -n ${RELEASE}-base -t ubuntu -- --release ${RELEASE} --arch ${ARCH} fi +# Fixes some networking issues +# See https://github.com/fgrehm/vagrant-lxc/issues/91 for more info +echo 'ff02::3 ip6-allhosts' >> ${ROOTFS}/etc/hosts + ################################################################################## # 2 - Prepare vagrant user From 2c0000b8cc728a3962bbdb657bf377f71025ec3a Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Fri, 20 Sep 2013 23:13:30 -0300 Subject: [PATCH 18/20] Clean up after ourselves when building base boxes --- boxes/build-debian-box.sh | 9 ++++++++- boxes/build-ubuntu-box.sh | 10 +++++++++- boxes/common/install-babushka | 2 ++ boxes/common/install-chef | 2 ++ boxes/common/install-puppet | 2 ++ boxes/common/install-salt | 2 ++ 6 files changed, 25 insertions(+), 2 deletions(-) diff --git a/boxes/build-debian-box.sh b/boxes/build-debian-box.sh index 751142a..597ddd3 100755 --- a/boxes/build-debian-box.sh +++ b/boxes/build-debian-box.sh @@ -157,4 +157,11 @@ sed -i "s//${NOW}/" metadata.json # Vagrant box! tar -czf $PKG ./* -echo "The base box was built successfully to ${WORKING_DIR}/${PKG}" +chmod +rw ${WORKING_DIR}/${PKG} +mkdir -p ${CWD}/output +mv ${WORKING_DIR}/${PKG} ${CWD}/output + +# Clean up after ourselves +rm -rf ${WORKING_DIR} + +echo "The base box was built successfully to ${CWD}/output/${PKG}" diff --git a/boxes/build-ubuntu-box.sh b/boxes/build-ubuntu-box.sh index 6d58fdf..dd72def 100755 --- a/boxes/build-ubuntu-box.sh +++ b/boxes/build-ubuntu-box.sh @@ -140,4 +140,12 @@ sed -i "s//${NOW}/" metadata.json # Vagrant box! tar -czf $PKG ./* -echo "The base box was built successfully to ${WORKING_DIR}/${PKG}" +chmod +rw ${WORKING_DIR}/${PKG} +mkdir -p ${CWD}/output +mv ${WORKING_DIR}/${PKG} ${CWD}/output + +# Clean up after ourselves +rm -rf ${WORKING_DIR} +lxc-destroy -n ${RELEASE}-base + +echo "The base box was built successfully to ${CWD}/output/${PKG}" diff --git a/boxes/common/install-babushka b/boxes/common/install-babushka index 6d43d76..a770bbb 100755 --- a/boxes/common/install-babushka +++ b/boxes/common/install-babushka @@ -1,5 +1,7 @@ #!/bin/bash +set -e + rootfs=$1 echo "installing babushka" diff --git a/boxes/common/install-chef b/boxes/common/install-chef index d99d0d7..2eeda2f 100755 --- a/boxes/common/install-chef +++ b/boxes/common/install-chef @@ -1,5 +1,7 @@ #!/bin/bash +set -e + rootfs=$1 echo "installing chef" diff --git a/boxes/common/install-puppet b/boxes/common/install-puppet index 1e1650e..d159d4f 100755 --- a/boxes/common/install-puppet +++ b/boxes/common/install-puppet @@ -1,5 +1,7 @@ #!/bin/bash +set -e + rootfs=$1 echo "installing puppet" diff --git a/boxes/common/install-salt b/boxes/common/install-salt index e7f74a2..b982117 100755 --- a/boxes/common/install-salt +++ b/boxes/common/install-salt @@ -1,5 +1,7 @@ #!/bin/bash +set -e + rootfs=$1 echo "installing salt" From d803119f50742c87e24e5252f8758d300f4a0062 Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Sat, 21 Sep 2013 00:32:20 -0300 Subject: [PATCH 19/20] Docs about base boxes --- BOXES.md | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 BOXES.md diff --git a/BOXES.md b/BOXES.md new file mode 100644 index 0000000..2fd1de1 --- /dev/null +++ b/BOXES.md @@ -0,0 +1,55 @@ +# vagrant-lxc base boxes + +Although the official documentation says it is only supported for VirtualBox +environments, you can use the [`vagrant package`](http://docs.vagrantup.com/v2/cli/package.html) +command to export a `.box` file from an existing vagrant-lxc container. + +There is also a set of [bash scripts](https://github.com/fgrehm/vagrant-lxc/tree/master/boxes) +that you can use to build base boxes as needed. By default it won't include any +provisioning tool and you can pick the ones you want by providing some environment +variables. + +For example: + +``` +git clone https://github.com/fgrehm/vagrant-lxc.git +cd vagrant-lxc/boxes +PUPPET=1 CHEF=1 sudo -E ./build-ubuntu-box.sh precise amd64 +``` + +Will build a Ubuntu Precise x86_64 box with latest Puppet and Chef pre-installed, please refer to the scripts for more information. + +## "Anatomy" of a box + +If you need to go deeper and build your scripts from scratch or if you are interested +on knowing what makes a base box for vagrant-lxc, here's what's needed: + +### Expected `.box` contents + +| FILE | DESCRIPTION | +| --- | --- | +| `lxc-template` | Script responsible for creating and setting up the container (used with `lxc-create`), a ["generic script"]() is provided along with project's source. | +| `rootfs.tar.gz` | Compressed container rootfs tarball (need to remeber to pass in `--numeric-owner` when creating it) | +| `lxc.conf` | | +| `metadata.json` | | + +### metadata.json + +```json +{ + "provider": "lxc", + "version": "3", + "built-on": "Sat Sep 21 21:10:00 UTC 2013", + "template-opts": { + "--arch": "amd64", + "--release": "quantal" + } +} +``` + +| KEY | REQUIRED? | DESCRIPTION | +| --- | --- | --- | +| `provider` | Yes | Required by Vagrant | +| `version` | Yes | Tracks backward incompatibilities | +| `built-on` | No | Date / time when the box was packaged | +| `template-opts` | No | Extra options to be passed to the `lxc-template` script provided with the .box package | From 1af1c91d90a80d441b55b208c7ded6cac6dcbaf4 Mon Sep 17 00:00:00 2001 From: Fabio Rehm Date: Sat, 21 Sep 2013 00:51:44 -0300 Subject: [PATCH 20/20] Update README --- README.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 42c3957..64c8774 100644 --- a/README.md +++ b/README.md @@ -106,13 +106,13 @@ to find out how to work around that specially if you are running an OS with sudo Please check [the wiki](https://github.com/fgrehm/vagrant-lxc/wiki/Base-boxes) for a list of [pre built](https://github.com/fgrehm/vagrant-lxc/wiki/Base-boxes#available-boxes) -base boxes and information on [how to build your own](https://github.com/fgrehm/vagrant-lxc/wiki/Base-boxes#building-your-own). +base boxes and have a look at [`BOXES.md`](https://github.com/fgrehm/vagrant-lxc/tree/master/BOXES.md) +for more information on building your own. ## More information -Please refer the [wiki](https://github.com/fgrehm/vagrant-lxc/wiki) for more -information. +Please refer the [wiki](https://github.com/fgrehm/vagrant-lxc/wiki). ## Problems / ideas? @@ -129,6 +129,14 @@ to ask questions, propose new functionality and / or report bugs. * [vagueant](https://github.com/neerolyte/vagueant) - "vaguely like Vagrant for linux containers (lxc)" +## Donating + +Support this project and [others by fgrehm](https://github.com/fgrehm) +via [gittip](https://www.gittip.com/fgrehm/). + +[![Support via Gittip](https://rawgithub.com/twolfson/gittip-badge/0.1.0/dist/gittip.png)](https://www.gittip.com/fgrehm/) + + ## Contributing 1. Fork it