diff --git a/boxes/build-openmandriva-box.sh b/boxes/build-openmandriva-box.sh new file mode 100644 index 0000000..1e091f0 --- /dev/null +++ b/boxes/build-openmandriva-box.sh @@ -0,0 +1,159 @@ +#!/bin/bash + +# set -x +set -e + +# Script used to build OpenMandriva base vagrant-lxc containers, currently limited to +# host's arch +# +# USAGE: +# $ cd boxes && sudo ./build-openmandriva-box.sh OPENMANDRIVA_RELEASE BOX_ARCH +# +# TODO: scripts for install CHEF, PUPPET, SALT, BABUSHKA +# To enable Chef or any other configuration management tool pass '1' to the +# corresponding env var: +# $ CHEF=1 sudo -E ./build-openmandriva-box.sh OPENMANDRIVA_RELEASE BOX_ARCH +# $ PUPPET=1 sudo -E ./build-openmandriva-box.sh OPENMANDRIVA_RELEASE BOX_ARCH +# $ SALT=1 sudo -E ./build-openmandriva-box.sh OPENMANDRIVA_RELEASE BOX_ARCH +# $ BABUSHKA=1 sudo -E ./build-openmandriva-box.sh OPENMANDRIVA_RELEASE BOX_ARCH + +################################################################################## +# 0 - Initial setup and sanity checks + +TODAY=$(date -u +"%Y-%m-%d") +NOW=$(date -u) +RELEASE=${1:-"openmandriva2013.0"} +ARCH=${2:-"x86_64"} +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/${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-openmandriva +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 openmandriva -- -R ${RELEASE} --arch ${ARCH} +fi + + +###################################### +# 2 - Fix some known issues + +# Fixes some networking issues +cat /etc/resolv.conf > ${ROOTFS}/etc/resolv.conf + +################################################################################## +# 3 - Prepare vagrant user +chroot ${ROOTFS} su -c 'useradd --create-home -s /bin/bash vagrant' + +# echo -n 'vagrant:vagrant' | chroot ${ROOTFS} chpasswd +chroot ${ROOTFS} su -c "echo -n 'vagrant:vagrant' | 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} urpmi sudo --auto +chroot ${ROOTFS} usermod -a -G wheel vagrant + +# Enable passwordless sudo for users under the "sudo" group +cp ${ROOTFS}/etc/sudoers{,.orig} +sed -i 's/Defaults requiretty/\# Defaults requiretty/' ${ROOTFS}/etc/sudoers +sed -i 's/\#%wheel/\%wheel/' ${ROOTFS}/etc/sudoers +sed -i 's/\# %wheel/\%wheel/' ${ROOTFS}/etc/sudoers +# 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 bash-completion openssh-server openssh-clients tar) +chroot ${ROOTFS} urpmi ${PACKAGES[*]} --auto +chroot ${ROOTFS} urpmi.update -a + + +################################################################################## +# 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} urpmi clean metadata + + +################################################################################## +# 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 lxc-template +cp $LXC_CONF . +cp $METATADA_JSON . +chmod +x lxc-template +sed -i "s//${NOW}/" metadata.json + +# Vagrant box! +tar -czf $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/common/lxc-template-openmandriva b/boxes/common/lxc-template-openmandriva new file mode 100644 index 0000000..2cbe34f --- /dev/null +++ b/boxes/common/lxc-template-openmandriva @@ -0,0 +1,225 @@ +#!/bin/bash + +# This is a modified version of /usr/share/lxc/templates/lxc-openmandriva +# that comes with OpenMandriva changed to suit vagrant-lxc needs + +# +# template script for generating openmandriva container for LXC +# + +# +# lxc: linux Container library + +# Authors: +# Alexander Khryukin +# Vokhmin Alexey V + +# 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 + +extract_rootfs() +{ + tarball=$1 + arch=$2 + rootfs=$3 + + echo "Extracting $tarball ..." + mkdir -p $(dirname $rootfs) + (cd `dirname $rootfs` && tar xfz $tarball) + return 0 +} + +install_openmandriva() +{ + 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 < + [-p|--path=] [-c|--clean] [-R|--release=] + [-4|--ipv4=] [-6|--ipv6=] + [-g|--gw=] [-d|--dns=] + [-P|--profile=] [--rootfs=] + [-A|--arch=] + [-T|--tarball ] + [-S|--auth-key ] + [-h|--help] +Mandatory args: + -n,--name container name, used to as an identifier for that container from now on +Optional args: + -p,--path path to where the container rootfs will be created, defaults to /var/lib/lxc. The container config will go under /var/lib/lxc in that case + -c,--clean clean the cache + -R,--release openmandriva2013.0/cooker/rosa2012.1 release for the new container. if the host is OpenMandriva, then it will default to the host's release. + -4,--ipv4 specify the ipv4 address to assign to the virtualized interface, eg. 192.168.1.123/24 + -6,--ipv6 specify the ipv6 address to assign to the virtualized interface, eg. 2003:db8:1:0:214:1234:fe0b:3596/64 + -g,--gw specify the default gw, eg. 192.168.1.1 + -G,--gw6 specify the default gw, eg. 2003:db8:1:0:214:1234:fe0b:3596 + -d,--dns specify the DNS server, eg. 192.168.1.2 + -P,--profile Profile name is the file name in /etc/lxc/profiles contained packages name for install to cache. + -A,--arch Define what arch the container will be [i586,x86_64,armv7l,armv7hl] + ---rootfs rootfs path + -h,--help print this help +EOF + return 0 +} + +options=$(getopt -o hp:n:P:cR:4:6:g:d:A:S:T: -l help,rootfs:,path:,name:,profile:,clean:,release:,ipv4:,ipv6:,gw:,dns:,arch:,auth-key:,tarball: -- "$@") +if [ $? -ne 0 ]; then + usage $(basename $0) + exit 1 +fi +eval set -- "$options" + +# doesn't use +release=${release:-"cooker"} + +hostarch=$(uname -m) +while true +do + case "$1" in + -h|--help) usage $0 && exit 0;; + -p|--path) path=$2; shift 2;; + --rootfs) rootfs_path=$2; shift 2;; + -n|--name) name=$2; shift 2;; + -P|--profile) profile=$2; shift 2;; + -c|--clean) clean=$2; shift 2;; + -R|--release) release=$2; shift 2;; + -T|--tarball) tarball=$2; shift 2;; + -S|--auth-key) auth_key=$2; shift 2;; + -A|--arch) arch=$2; shift 2;; + -4|--ipv4) ipv4=$2; shift 2;; + -6|--ipv6) ipv6=$2; shift 2;; + -g|--gw) gw=$2; shift 2;; + -d|--dns) dns=$2; shift 2;; + --) shift 1; break ;; + *) break ;; + esac +done + +arch=${arch:-$hostarch} +if [ $hostarch = "i586" -a $arch = "x86_64" ]; then + echo "can't create x86_64 container on i586" + 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 $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_openmandriva $rootfs $release $tarball +if [ $? -ne 0 ]; then + echo "failed to install openmandriva $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 + +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/lib/vagrant-lxc/action/fetch_ip_with_lxc_attach.rb b/lib/vagrant-lxc/action/fetch_ip_with_lxc_attach.rb index dd8641f..3569c69 100644 --- a/lib/vagrant-lxc/action/fetch_ip_with_lxc_attach.rb +++ b/lib/vagrant-lxc/action/fetch_ip_with_lxc_attach.rb @@ -1,43 +1,43 @@ module Vagrant module LXC module Action - class FetchIpWithLxcAttach - # Include this so we can use `Subprocess` more easily. - include Vagrant::Util::Retryable + class FetchIpWithLxcAttach + # Include this so we can use `Subprocess` more easily. + include Vagrant::Util::Retryable - def initialize(app, env) - @app = app - @logger = Log4r::Logger.new("vagrant::lxc::action::fetch_ip_with_lxc_attach") - end + def initialize(app, env) + @app = app + @logger = Log4r::Logger.new("vagrant::lxc::action::fetch_ip_with_lxc_attach") + end - def call(env) - env[:machine_ip] ||= assigned_ip(env) - rescue LXC::Errors::NamespacesNotSupported - @logger.info 'The `lxc-attach` command available does not support the --namespaces parameter, falling back to dnsmasq leases to fetch container ip' - ensure - @app.call(env) - end + def call(env) + env[:machine_ip] ||= assigned_ip(env) + rescue LXC::Errors::NamespacesNotSupported + @logger.info 'The `lxc-attach` command available does not support the --namespaces parameter, falling back to dnsmasq leases to fetch container ip' + ensure + @app.call(env) + end - def assigned_ip(env) - driver = env[:machine].provider.driver - ip = '' - retryable(:on => LXC::Errors::ExecuteError, :tries => 10, :sleep => 3) do - unless ip = get_container_ip_from_ip_addr(driver) - # retry - raise LXC::Errors::ExecuteError, :command => "lxc-attach" - end + def assigned_ip(env) + driver = env[:machine].provider.driver + ip = '' + retryable(:on => LXC::Errors::ExecuteError, :tries => 10, :sleep => 3) do + unless ip = get_container_ip_from_ip_addr(driver) + # retry + raise LXC::Errors::ExecuteError, :command => "lxc-attach" end - ip end + ip + end - # From: https://github.com/lxc/lxc/blob/staging/src/python-lxc/lxc/__init__.py#L371-L385 - def get_container_ip_from_ip_addr(driver) - output = driver.attach '/sbin/ip', '-4', 'addr', 'show', 'scope', 'global', 'eth0', namespaces: 'network' - if output =~ /^\s+inet ([0-9.]+)\/[0-9]+\s+/ - return $1.to_s - end + # From: https://github.com/lxc/lxc/blob/staging/src/python-lxc/lxc/__init__.py#L371-L385 + def get_container_ip_from_ip_addr(driver) + output = driver.attach '/sbin/ip', '-4', 'addr', 'show', 'scope', 'global', 'eth0', namespaces: 'network' + if output =~ /^\s+inet ([0-9.]+)\/[0-9]+\s+/ + return $1.to_s end end end end end +end