diff options
author | Leonardo Arena <rnalrd@alpinelinux.org> | 2011-08-16 11:26:52 +0000 |
---|---|---|
committer | Leonardo Arena <rnalrd@alpinelinux.org> | 2011-08-16 11:26:52 +0000 |
commit | 1fb30d930d4f7069c0b7b73dd9895c036e8d0f56 (patch) | |
tree | 51ddcc9e8edbc824ac3b40c0c866a6af878e655b /main/lxc | |
parent | 6f18af728d40558a2744a05ad438686b921ea7a6 (diff) | |
download | aports-1fb30d930d4f7069c0b7b73dd9895c036e8d0f56.tar.bz2 aports-1fb30d930d4f7069c0b7b73dd9895c036e8d0f56.tar.xz |
testing/lxc: move to main
Diffstat (limited to 'main/lxc')
-rw-r--r-- | main/lxc/APKBUILD | 52 | ||||
-rw-r--r-- | main/lxc/lxc.initd | 114 | ||||
-rwxr-xr-x | main/lxc/setup-lxc-guest | 282 | ||||
-rwxr-xr-x | main/lxc/setup-lxc-template | 44 |
4 files changed, 492 insertions, 0 deletions
diff --git a/main/lxc/APKBUILD b/main/lxc/APKBUILD new file mode 100644 index 0000000000..10f55deebc --- /dev/null +++ b/main/lxc/APKBUILD @@ -0,0 +1,52 @@ +# Contributor: William Pitcock <nenolod@dereferenced.org> +# Maintainer: William Pitcock <nenolod@dereferenced.org> +pkgname=lxc +pkgver=0.7.4 +_mypkgver=${pkgver/_rc/-rc} +pkgrel=3 +pkgdesc="linux containers - tools" +url="http://lxc.sourceforge.net/" +arch="all" +license="GPL" +depends= +depends_dev="libcap-dev" +makedepends="$depends_dev" +install="" +subpackages="$pkgname-dev $pkgname-doc" +source="http://lxc.sourceforge.net/download/lxc/$pkgname-$_mypkgver.tar.gz + lxc.initd + setup-lxc-template + setup-lxc-guest + " + +_builddir="${srcdir}/${pkgname}-${_mypkgver}" +prepare() { + local i + cd "$_builddir" + for i in $source; do + case $i in + *.patch) msg $i; patch -p1 -i "$srcdir"/$i || return 1;; + esac + done +} + +build() { + cd "$_builddir" + ./configure --prefix=/usr \ + --sysconfdir=/etc \ + --localstatedir=/var + make || return 1 +} + +package() { + cd "$_builddir" + make DESTDIR="$pkgdir" install || return 1 + install -Dm755 "$srcdir"/lxc.initd "$pkgdir"/etc/init.d/lxc + install -Dm755 "$srcdir"/setup-lxc-template "$pkgdir"/usr/bin/setup-lxc-template + install -Dm755 "$srcdir"/setup-lxc-guest "$pkgdir"/usr/bin/setup-lxc-guest +} + +md5sums="51bb5d7d9d22e2c98490aed47fc02ad9 lxc-0.7.4.tar.gz +e66c3cf8e70168b07060746a4e65b671 lxc.initd +45d0f604310e58a1359f1745a4739843 setup-lxc-template +c3f7fd7e85d40c4a4b1b427048ff9652 setup-lxc-guest" diff --git a/main/lxc/lxc.initd b/main/lxc/lxc.initd new file mode 100644 index 0000000000..86bae5f757 --- /dev/null +++ b/main/lxc/lxc.initd @@ -0,0 +1,114 @@ +#!/sbin/runscript +# Copyright 1999-2011 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-x86/app-emulation/lxc/files/lxc.initd,v 1.3 2011/02/26 18:02:51 flameeyes Exp $ + +CONTAINER=${SVCNAME#*.} +CONFIGFILE=${CONFIGFILE:-/etc/lxc/${CONTAINER}.conf} + +lxc_get_var() { + awk 'BEGIN { FS="[ \t]*=[ \t]*" } $1 == "'$1'" { print $2; exit }' ${CONFIGFILE} +} + +cgroup_get_mount() { + mount | awk '$5 == "cgroup" { print $3; exit }' +} + +checkconfig() { + if [ ${CONTAINER} = ${SVCNAME} ]; then + eerror "You have to create an init script for each container:" + eerror " ln -s lxc /etc/init.d/lxc.container" + return 1 + fi + + utsname=$(lxc_get_var lxc.utsname) + if [ ${CONTAINER} != ${utsname} ]; then + eerror "You should use the same name for the service and the" + eerror "container. Right now the container is called ${utsname}" + return 1 + fi +} + +depend() { + # be quiet, since we have to run depend() also for the + # non-muxed init script, unfortunately. + checkconfig 2>/dev/null || return 0 + + config ${CONFIGFILE} + need localmount + + # find out which network interface the container is linked to, + # and then require that to be enabled, so that the + # dependencies are correct. + netif=$(lxc_get_var lxc.network.link) + [ -n "${netif}" ] && need net.${netif} +} + +start() { + checkconfig || return 1 + + # make sure that cgroup is mounted if it isn't already, this + # ensures that we can actually proceed! + cgroupmount=$(cgroup_get_mount) + if [ -z ${cgroupmount} ]; then + mkdir -p /cgroup + + if ! mount -t cgroup cgroup /cgroup; then + eerror "Unable to mount cgroup pseudo-filesystem on /cgroup" + return 1 + fi + + cgroupmount=/cgroup + fi + + rm /var/log/lxc/${CONTAINER}.log + + rootpath=$(lxc_get_var lxc.rootfs) + + # Check the format of our init and the chroot's init, to see if we + # have to use linux32 or linux64… + case $(scanelf -BF '%M#f' /sbin/init ${rootpath}/sbin/init | tr '\n' ':') in + ELFCLASS64:ELFCLASS64:) setarch=;; + ELFCLASS32:ELFCLASS32:) setarch=;; + ELFCLASS32:ELFCLASS64:) setarch=linux64;; + ELFCLASS64:ELFCLASS32:) setarch=linux32;; + esac + + ebegin "Starting ${CONTAINER}" + ${setarch} lxc-start -l WARN -n ${CONTAINER} -f ${CONFIGFILE} -d -o /var/log/lxc/${CONTAINER}.log + sleep 0.5 + + # lxc-start -d will _always_ report a correct startup, even if it + # failed, so rather than trust that, check that the cgroup exists. + [ -d ${cgroupmount}/${CONTAINER} ] + eend $? +} + +stop() { + checkconfig || return 1 + + cgroupmount=$(cgroup_get_mount) + + if ! [ -d ${cgroupmount}/${CONTAINER} ]; then + ewarn "${CONTAINER} doesn't seem to be started." + return 0 + fi + + init_pid=$(head -n1 ${cgroupmount}/${CONTAINER}/tasks) + + ebegin "Shutting down system in ${CONTAINER}" + kill -INT ${init_pid} + eend $? + + sleep 15 + + missingprocs=$(pgrep -P ${init_pid}) + + if [ -n "${missingprocs}" ]; then + ewarn "Something failed to properly shut down in ${CONTAINER}" + fi + + ebegin "Stopping ${CONTAINER}" + lxc-stop -n ${CONTAINER} + eend $? +} diff --git a/main/lxc/setup-lxc-guest b/main/lxc/setup-lxc-guest new file mode 100755 index 0000000000..0519ae0299 --- /dev/null +++ b/main/lxc/setup-lxc-guest @@ -0,0 +1,282 @@ +#!/bin/sh + +# simple script to set up a new lxc guest +# test the first argument against the remaining ones, return success on a match +isin() { + local _a=$1 _b + + shift + for _b; do + [ "$_a" = "$_b" ] && return 0 + done + return 1 +} + +# remove all occurrences of first argument from list formed by +# the remaining arguments +rmel() { + local _a=$1 _b + + shift + for _b; do + [ "$_a" != "$_b" ] && echo -n "$_b " + done +} + +# Issue a read into the global variable $resp. +_ask() { + local _redo=0 + + read resp + case "$resp" in + !) echo "Type 'exit' to return to setup." + sh + _redo=1 + ;; + !*) eval "${resp#?}" + _redo=1 + ;; + esac + return $_redo +} + +# Ask for user input. +# +# $1 = the question to ask the user +# $2 = the default answer +# +# Save the user input (or the default) in $resp. +# +# Allow the user to escape to shells ('!') or execute commands +# ('!foo') before entering the input. +ask() { + local _question=$1 _default=$2 + + while :; do + echo -n "$_question " + [ -z "$_default" ] || echo -n "[$_default] " + _ask && : ${resp:=$_default} && break + done +} + +# Ask for user input until a non-empty reply is entered. +# +# $1 = the question to ask the user +# $2 = the default answer +# +# Save the user input (or the default) in $resp. +ask_until() { + resp= + while [ -z "$resp" ] ; do + ask "$1" "$2" + done +} + +# Ask for the user to select one value from a list, or 'done'. +# +# $1 = name of the list items (disk, cd, etc.) +# $2 = question to ask +# $3 = list of valid choices +# $4 = default choice, if it is not specified use the first item in $3 +# +# N.B.! $3 and $4 will be "expanded" using eval, so be sure to escape them +# if they contain spooky stuff +# +# At exit $resp holds selected item, or 'done' +ask_which() { + local _name=$1 _query=$2 _list=$3 _def=$4 _dynlist _dyndef + + while :; do + # Put both lines in ask prompt, rather than use a + # separate 'echo' to ensure the entire question is + # re-ask'ed after a '!' or '!foo' shell escape. + eval "_dynlist=\"$_list\"" + eval "_dyndef=\"$_def\"" + + # Clean away whitespace and determine the default + set -o noglob + set -- $_dyndef; _dyndef="$1" + set -- $_dynlist; _dynlist="$*" + set +o noglob + [ $# -lt 1 ] && resp=done && return + + : ${_dyndef:=$1} + echo "Available ${_name}s are: $_dynlist." + echo -n "Which one $_query? (or 'done') " + [ -n "$_dyndef" ] && echo -n "[$_dyndef] " + _ask || continue + [ -z "$resp" ] && resp="$_dyndef" + + # Quote $resp to prevent user from confusing isin() by + # entering something like 'a a'. + isin "$resp" $_dynlist done && break + echo "'$resp' is not a valid choice." + done +} + +# Ask for user input until a non-empty reply is entered. +# +# $1 = the question to ask the user +# $2 = the default answer +# +# Save the user input (or the default) in $resp. +ask_until() { + resp= + while [ -z "$resp" ] ; do + ask "$1" "$2" + done +} + +# http://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names +valid_hostname() { + # check length + if [ $(echo "$1" | wc -c) -gt 63 ]; then + echo "Hostname '$1' is too long." + return 1 + fi + # check that it only contains valid chars + if ! [ -z "$(echo $1 | sed 's/[0-9a-z-]//g')" ]; then + echo "Hostname must only contain letters (a-z), digits (0-9) or -" + return 1 + fi + # must not start with - + case "$1" in + -*) echo "Hostname must not start with a '-'"; return 1;; + esac + return 0 +} + +# return last ipv4 address and mask +# +# $1 = interface +# +last_ipv4_addr_mask() { + local _iface=$1 + ip addr show dev $_iface | awk '$1 == "inet" {print $2}' | tail -n1 +} + +valid_ip_and_prefix() { + [ "$1" ] || return 0 + ipcalc -s -m $1 >/dev/null 2>&1 && ! ipcalc -s -m $1/0 >/dev/null 2>&1 +} + +# ask for hostname +# +# $1 = default +# +# retrusn hostname in global var $resp +# +ask_hostname() { + while true; do + ask "Hostname for new lxc container:" $1 + if [ -d /var/lib/lxc/$resp ]; then + echo "/var/lib/lxc/$resp already exist" + continue + fi + if [ -d /lxc/$resp ]; then + echo "/lxc/$resp already exist" + continue + fi + valid_hostname $resp && break + done +} + +ask_ifaceopts() { + # get ip address(es) + resp= + local ifaceopts= _def= _iface= + local ifaces=$(ip addr | awk -F: '$1 ~ /^[0-9]/ {printf "%s" $2} END {printf "\n"}') + local last_iface=$(echo $ifaces | sed 's/.* //') + while [ "$resp" != "done" ]; do + if [ -z "$ifaces" ] || [ "$ifaces" = "lo " ] || [ -n "$ifaceopts" ]; then + _def="done" + else + _def=$(echo $ifaces | sed 's/.* //') + fi + ask_which "network interface" "to use for $_hostname" \ + "$ifaces" $_def + [ "$resp" = "done" ] && break + + _iface=$resp + ifaces=$(rmel $_iface $ifaces) + # suggested ip by last digit + 1 + _last_ip_mask=$(last_ipv4_addr_mask $_iface) + _last_ip=${_last_ip_mask%/*} + _last_ip_digit=${_last_ip##*.} + _ip=${_last_ip%.*}.$((($_last_ip_digit + 1) % 256)) + _mask=${_last_ip_mask#*/} + while true; do + ask "Enter IP address/mask for $_iface:" $_ip/$_mask + valid_ip_and_prefix "$resp" 2>&1 && break + echo "$resp is not a valid IPv4 address/mask" + done + _ip_mask=$resp + ifaceopts="$ifaceopts --interface $_iface:$_ip_mask" + echo "lxc.network.ipv4 = $_iface/$_ip_mask" >> /tmp/lxc-$hostname.conf + conffile=/tmp/lxc-$hostname.conf + done + resp="$conffile" +} + +ask_template() { + local temp + # get template + while true; do + ask "Enter template file (or empty for generate a new):" \ + $_template + if [ -z "$resp" ] || [ -r "$resp" ]; then + break + fi + echo "Can not read $resp" + done + temp=$resp + if [ -z "$temp" ]; then + temp=/tmp/template.tar.gz + echo "Generating template..." + if setup-lxc-template -q -o $temp; then + echo "ok" + else + echo "Failed to create template" + exit 1 + fi + fi + resp=$temp +} + +usage() { + echo "Usage: ${0##*/} [-h] [HOSTNAME...]" + exit 1 +} + +while getopts "h" opt; do + case "$opt" in + h) usage;; + ?) usage;; + esac +done + +shift $(($OPTIND - 1)) + +if [ "$(whoami)" != "root" ]; then + echo "Need to be root. Sorry." + exit 1 +fi + +while true; do + ask_hostname $1 + _hostname=$resp + + ask_ifaceopts + _conffile=$resp + + ask_template + _template=$resp + + lxc-create -n $_hostname \ + -f $_conffile \ + -t "$_template" \ + || exit 1 + + shift + [ $# -le 0 ] && exit 0 +done diff --git a/main/lxc/setup-lxc-template b/main/lxc/setup-lxc-template new file mode 100755 index 0000000000..f8e9fe4a39 --- /dev/null +++ b/main/lxc/setup-lxc-template @@ -0,0 +1,44 @@ +#!/bin/sh + +# create a lxc template +PROG=$0 + +usage() { + echo "usage: $PROG [-fhq] [-o OUTFILE] [-X repository] [packages...]" + exit $1 +} + +clean_exit() { + rm -rf "$tmpdir" + exit $1 +} + +outfile=template.tar.gz +fakeroot= +repos= +while getopts "ho:qX:" opt; do + case "$opt" in + h) usage 0;; + o) outfile="$OPTARG";; + q) quiet=-q;; + X) repos="$repos --repository $OPTARG";; + esac +done +shift $(( $OPTIND - 1 )) + +if [ "$(whoami)" != "root" ]; then + echo "Warning: you need root permissions" >&2 +fi + +tmpdir=$(mktemp -d ${TMPDIR:-/tmp}/setup-lxc-template-XXXXXX) + +apk add --root "$tmpdir" --initdb --keys-dir /etc/apk/keys -U \ + $quiet ${repos:---repositories-file /etc/apk/repositories} \ + alpine-base $@ \ + || clean_exit 1 + +tar -czf "$outfile" -C "$tmpdir" $(ls "$tmpdir") || clean_exit 1 + +[ -z "$quiet" ] && echo "Created $outfile" +clean_exit 0 + |