lxc-cirros.in revision 4165b2c65648b5df521c6e83b1cbad91d0896a00
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano#!/bin/bash
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano# template script for generating ubuntu container for LXC
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano#
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano# This script consolidates and extends the existing lxc ubuntu scripts
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano#
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano# Copyright � 2013 Canonical Ltd.
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano# Author: Scott Moser <scott.moser@canonical.com>
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano#
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano# This program is free software; you can redistribute it and/or modify
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano# it under the terms of the GNU General Public License version 2, as
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano# published by the Free Software Foundation.
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano# This program is distributed in the hope that it will be useful,
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano# but WITHOUT ANY WARRANTY; without even the implied warranty of
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano# GNU General Public License for more details.
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano# You should have received a copy of the GNU General Public License along
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano# with this program; if not, write to the Free Software Foundation, Inc.,
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
1490112767ea6e06ea78e80d905b9dad41051798Daniel LezcanoVERBOSITY=0
1490112767ea6e06ea78e80d905b9dad41051798Daniel LezcanoDOWNLOAD_URL="http://download.cirros-cloud.net/"
1490112767ea6e06ea78e80d905b9dad41051798Daniel LezcanoCACHE_D="@LOCALSTATEDIR@/cache/lxc/cirros"
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano
1490112767ea6e06ea78e80d905b9dad41051798Daniel LezcanoUNAME_M=$(uname -m)
1490112767ea6e06ea78e80d905b9dad41051798Daniel LezcanoARCHES=( i386 x86_64 amd64 arm )
1490112767ea6e06ea78e80d905b9dad41051798Daniel LezcanoSTREAMS=( released devel )
1490112767ea6e06ea78e80d905b9dad41051798Daniel LezcanoSOURCES=( nocloud none )
1490112767ea6e06ea78e80d905b9dad41051798Daniel LezcanoBUILD="standard"
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano
1490112767ea6e06ea78e80d905b9dad41051798Daniel LezcanoDEF_VERSION="released"
1490112767ea6e06ea78e80d905b9dad41051798Daniel LezcanoDEF_SOURCE="nocloud"
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcanocase "${UNAME_M}" in
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano i?86) DEF_ARCH="i386";;
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano x86_64) DEF_ARCH="x86_64";;
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano arm*) DEF_ARCH="arm";;
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano *) DEF_ARCH="i386";;
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcanoesac
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcanoerror() { echo "$@" 1>&2; }
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcanoinargs() {
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano local needle="$1" x=""
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano shift
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano for x in "$@"; do
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano [ "$needle" = "$x" ] && return 0
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano done
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano return 1
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano}
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano
1490112767ea6e06ea78e80d905b9dad41051798Daniel LezcanoUsage() {
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano cat <<EOF
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano${0##*/} [options]
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano -a | --arch A architecture to use [${ARCHES[*]}]
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano default: ${DEF_ARCH}
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano -h | --help this usage
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano -v | --verbose increase verbosity
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano -S | --auth-key K insert auth key 'K'
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano -v | --version V version [${STREAMS[*]}]
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano default: ${DEF_VERSION}
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano -u | --userdata U user-data file
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano --tarball T read from tarball 'T' rather than downloading
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano or using cache.
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano --source S insert userdata/metadata via source S
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano [${SOURCES[*]}]
1490112767ea6e06ea78e80d905b9dad41051798Daniel LezcanoEOF
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano}
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcanobad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; return 1; }
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcanodebug() {
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano local level=${1}; shift;
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano [ "${level}" -gt "${VERBOSITY}" ] && return
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano error "${@}"
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano}
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcanojsondict() {
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano local k="" v="" ret="{"
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano for arg in "$@"; do
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano k="${arg%%=*}"
7115cb787d20da6368e3392a97069894ec5d19d6Michel Normand v="${arg#*=}"
7115cb787d20da6368e3392a97069894ec5d19d6Michel Normand ret="${ret} \"${k}\": \"$v\","
7115cb787d20da6368e3392a97069894ec5d19d6Michel Normand done
7115cb787d20da6368e3392a97069894ec5d19d6Michel Normand ret="${ret%,} }"
7115cb787d20da6368e3392a97069894ec5d19d6Michel Normand echo "$ret"
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano}
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcanocopy_configuration()
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano{
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano local path=$1 rootfs=$2 name=$3 arch=$4 release=$5
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcanocat >> "$path/config" <<EOF
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano# Template used to create this container: cirros
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcanolxc.rootfs = $rootfs
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano#lxc.mount = $path/fstab
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcanolxc.pivotdir = lxc_putold
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcanolxc.tty = 4
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcanolxc.pts = 1024
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcanolxc.utsname = $name
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcanolxc.arch = $arch
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcanolxc.cap.drop = sys_module mac_admin mac_override sys_time
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano# When using LXC with apparmor, uncomment the next line to run unconfined:
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano#lxc.aa_profile = unconfined
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano# To support container nesting on an Ubuntu host, uncomment next two lines:
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano#lxc.aa_profile = lxc-container-default-with-nesting
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano#lxc.hook.mount = /usr/share/lxc/hooks/mountcgroups
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcanolxc.cgroup.devices.deny = a
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano# Allow any mknod (but not using the node)
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcanolxc.cgroup.devices.allow = c *:* m
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcanolxc.cgroup.devices.allow = b *:* m
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcano# /dev/null and zero
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcanolxc.cgroup.devices.allow = c 1:3 rwm
1490112767ea6e06ea78e80d905b9dad41051798Daniel Lezcanolxc.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 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
}
insert_ds_nocloud() {
local root_d="$1" authkey="$2" udfile="$3"
local sdir="$root_d/var/lib/cloud/seed/nocloud"
mkdir -p "$sdir" ||
{ error "failed to make datasource dir $sdir"; return 1; }
rm -f "$sdir/meta-data" "$sdir/user-data" ||
{ error "failed to clean old data from $sdir"; return 1; }
iid="iid-local01"
jsondict "instance-id=$iid" \
${authkeys:+"public-keys=${authkeys}"} > "$sdir/meta-data" ||
{ error "failed to write metadata to $sdir/meta-data"; return 1; }
if [ -n "$udfile" ]; then
cat "$udfile" > "$sdir/user-data" ||
{ error "failed to write user-data to $sdir"; return 1; }
else
rm -f "$sdir/user-data"
fi
}
insert_ds() {
local dstype="$1" root_d="$2" authkey="$3" udfile="$4"
case "$dstype" in
nocloud) insert_ds_nocloud "$root_d" "$authkey" "$udfile"
esac
}
extract_rootfs() {
local tarball="$1" rootfs_d="$2"
mkdir -p "${rootfs_d}" ||
{ error "failed to make rootfs dir ${rootfs_d}"; return 1; }
tar -C "${rootfs_d}" -Sxzf "${tarball}" ||
{ error "failed to populate ${rootfs_d}"; return 1; }
return 0
}
download_tarball() {
local arch="$1" ver="$2" cached="$3" baseurl="$4"
local out="" outd="" file="" dlpath=""
file="cirros-$ver-$arch-lxc.tar.gz"
dlpath="$ver/$file"
outd="${cached}/${dlpath%/*}"
if [ -f "$cached/$dlpath" ]; then
_RET="$cached/$dlpath"
return 0
fi
mkdir -p "${outd}" ||
{ error "failed to create ${outd}"; return 1; }
debug 1 "downloading ${baseurl%/}/$dlpath" to "${cached}/$dlpath"
wget "${baseurl%/}/$dlpath" -O "$cached/${dlpath}.$$" &&
mv "$cached/$dlpath.$$" "$cached/$dlpath" || {
rm -f "$cached/$dlpath.$$";
error "failed to download $dlpath";
return 1;
}
_RET="$cached/$dlpath"
}
create_main() {
local short_opts="a:hn:p:S:uvV"
local long_opts="arch:,auth-key:,name:,path:,tarball:,userdata:,verbose,version:,rootfs:"
local getopt_out=""
getopt_out=$(getopt --name "${0##*/}" \
--options "${short_opts}" --long "${long_opts}" -- "$@") &&
eval set -- "${getopt_out}" ||
{ bad_Usage; return; }
local arch="${DEF_ARCH}" dsource="${DEF_SOURCE}" version="${DEF_VERSION}"
local authkey_f="" authkeys="" userdata_f="" path="" tarball=""
local cur="" next=""
local rootfs_d=""
while [ $# -ne 0 ]; do
cur=$1; next=$2;
case "$cur" in
-a|--arch) arch="$next"; shift;;
-h|--help) Usage ; return 0;;
-n|--name) name="$next"; shift;;
-v|--verbose) VERBOSITY=$((${VERBOSITY}+1));;
-S|--auth-key) authkey_f="$next"; shift;;
-p|--path) path=$next; shift;;
-v|--version) version=$next; shift;;
-u|--userdata) userdata_f="$next"; shift;;
--tarball) tarball="$next"; shift;;
--source) dsource="$next"; shift;;
--rootfs) rootfs_d="$next"; shift;;
--) shift; break;;
esac
shift;
done
[ -n "$rootfs_d" ] || rootfs_d="$path/rootfs"
[ $# -eq 0 ] || { bad_Usage "unexpected arguments: $*"; return; }
[ -n "$path" ] || { error "'path' parameter is required"; return 1; }
if [ "$(id -u)" != "0" ]; then
{ error "must be run as root"; return 1; }
fi
case "$arch" in
i?86) arch="i386";;
amd64) arch="x86_64";;
esac
inargs "$arch" "${ARCHES[@]}" ||
{ error "bad arch '$arch'. allowed: ${ARCHES[*]}"; return 1; }
inargs "$dsource" "${SOURCES[@]}" ||
{ error "bad source '$dsource'. allowed: ${SOURCES[*]}"; return 1; }
if [ "$dsource" = "none" ] && [ -n "$userdata_f" -o -n "$authkey_f" ]; then
error "userdata and authkey are incompatible with --source=none";
return 1;
fi
if [ -n "$authkey_f" ]; then
if [ ! -f "$authkey_f" ]; then
error "--auth-key=${authkey_f} must reference a file"
return 1
fi
authkeys=$(cat "$authkey_f") ||
{ error "failed to read ${authkey_f}"; return 1; }
fi
if [ -n "$userdata_f" -a ! -f "${userdata_f}" ]; then
error "${userdata_f}: --userdata arg not a file"
return 1
fi
if [ -z "$tarball" ]; then
if inargs "$version" "${STREAMS[@]}"; then
out=$(wget -O - -q "${DOWNLOAD_URL%/}/version/$version") ||
{ error "failed to convert 'version=$version'"; return 1; }
version="$out"
fi
download_tarball "$arch" "$version" "${CACHE_D}" "${DOWNLOAD_URL}" ||
return
tarball="$_RET"
fi
extract_rootfs "${tarball}" "${rootfs_d}" || return
# cirros 0.3.1 was broken for /dev/random and /dev/urandom
if [ -b "$rootfs_d/dev/random" ]; then
rm -f "$rootfs_d/dev/random" &&
mknod --mode=666 "$rootfs_d/dev/random" c 1 8 ||
{ error "failed to fix /dev/random"; return 1; }
fi
if [ -b "$rootfs_d/dev/urandom" ]; then
rm -f "$rootfs_d/dev/urandom" &&
mknod --mode=666 "$rootfs_d/dev/urandom" c 1 9 ||
{ error "failed to fix /dev/urandom"; return 1; }
fi
if [ "$version" = "0.3.2~pre1" ]; then
debug 1 "fixing console for lxc and '$version'"
sed -i 's,^\(#console.* 115200 \)# /dev/console,\1 console,g' \
"$rootfs_d/etc/inittab" ||
{ error "failed to fix console entry for $version"; return 1; }
fi
if [ "$dsource" != "none" ]; then
insert_ds "$dsource" "$path/rootfs" "$authkeys" "$userdata_f" || {
error "failed to insert userdata to $path/rootfs"
return 1
}
fi
copy_configuration "$path" "$path/rootfs" "$name" "$arch" "$release"
return
}
create_main "$@"
# vi: ts=4 expandtab