lxc-alpine.in revision 5afb809607919f245e635a3883d7d7febb0caffa
294N/A#!/bin/sh
294N/A
787N/A# Detect use under userns (unsupported)
789N/Afor arg in "$@"; do
789N/A [ "$arg" = "--" ] && break
789N/A if [ "$arg" = "--mapped-uid" -o "$arg" = "--mapped-gid" ]; then
789N/A echo "This template can't be used for unprivileged containers." 1>&2
789N/A echo "You may want to try the \"download\" template instead." 1>&2
789N/A exit 1
789N/A fi
789N/Adone
789N/A
294N/A# Make sure the usual locations are in PATH
789N/APATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
789N/Aexport PATH
789N/A
789N/Akey_sha256sums="9c102bcc376af1498d549b77bdbfa815ae86faa1d2d82f040e616b18ef2df2d4 alpine-devel@lists.alpinelinux.org-4a6a0840.rsa.pub
789N/A2adcf7ce224f476330b5360ca5edb92fd0bf91c92d83292ed028d7c4e26333ab alpine-devel@lists.alpinelinux.org-4d07755e.rsa.pub
789N/Aebf31683b56410ecc4c00acd9f6e2839e237a3b62b5ae7ef686705c7ba0396a9 alpine-devel@lists.alpinelinux.org-5243ef4b.rsa.pub
789N/A1bb2a846c0ea4ca9d0e7862f970863857fc33c32f5506098c636a62a726a847b alpine-devel@lists.alpinelinux.org-524d27bb.rsa.pub
789N/A12f899e55a7691225603d6fb3324940fc51cd7f133e7ead788663c2b7eecb00c alpine-devel@lists.alpinelinux.org-5261cecb.rsa.pub"
789N/A
789N/A
789N/Aget_static_apk () {
789N/A wget="wget -q -O -"
789N/A pkglist=alpine-keys:apk-tools-static
789N/A auto_repo_dir=
789N/A
789N/A if [ -z "$repository" ]; then
789N/A url=http://wiki.alpinelinux.org/cgi-bin/dl.cgi
789N/A yaml_path="latest-stable/releases/$apk_arch/latest-releases.yaml"
787N/A if [ -z "$release" ]; then
294N/A echo -n "Determining the latest release... "
294N/A release=$($wget $url/$yaml_path | \
294N/A awk '$1 == "branch:" {print $2; exit 0}')
294N/A if [ -z "$release" ]; then
294N/A release=$($wget $url/.latest.$apk_arch.txt | \
294N/A cut -d " " -f 3 | cut -d / -f 1 | uniq)
294N/A fi
787N/A if [ -z "$release" ]; then
789N/A echo failed
789N/A return 1
789N/A fi
789N/A echo $release
789N/A fi
789N/A auto_repo_dir=$release/main
294N/A repository=$url/$auto_repo_dir
294N/A pkglist=$pkglist:alpine-mirrors
294N/A fi
294N/A
294N/A rootfs="$1"
789N/A echo "Using static apk from $repository/$apk_arch"
294N/A wget="$wget $repository/$apk_arch"
787N/A
789N/A # parse APKINDEX to find the current versions
789N/A static_pkgs=$($wget/APKINDEX.tar.gz | \
787N/A tar -Oxz APKINDEX | \
789N/A awk -F: -v pkglist=$pkglist '
789N/A BEGIN { split(pkglist,pkg) }
789N/A $0 != "" { f[$1] = $2 }
789N/A $0 == "" { for (i in pkg)
789N/A if (pkg[i] == f["P"])
789N/A print(f["P"] "-" f["V"] ".apk") }')
294N/A [ "$static_pkgs" ] || return 1
789N/A
294N/A mkdir -p "$rootfs" || return 1
294N/A for pkg in $static_pkgs; do
789N/A echo "Downloading $pkg"
294N/A $wget/$pkg | tar -xz -C "$rootfs"
294N/A done
294N/A
294N/A # clean up .apk meta files
294N/A rm -f "$rootfs"/.[A-Z]*
294N/A
294N/A # verify checksum of the key
789N/A keyname=$(echo $rootfs/sbin/apk.static.*.pub | sed 's/.*\.SIGN\.RSA\.//')
789N/A checksum=$(echo "$key_sha256sums" | grep -w "$keyname")
789N/A if [ -z "$checksum" ]; then
787N/A echo "ERROR: checksum is missing for $keyname"
789N/A return 1
294N/A fi
789N/A (cd $rootfs/etc/apk/keys && echo "$checksum" | sha256sum -c -) || return 1
789N/A
789N/A # verify the static apk binary signature
789N/A APK=$rootfs/sbin/apk.static
789N/A openssl dgst -sha1 -verify $rootfs/etc/apk/keys/$keyname \
789N/A -signature "$APK.SIGN.RSA.$keyname" "$APK" || return 1
789N/A
789N/A if [ "$auto_repo_dir" ]; then
789N/A mirror_list=$rootfs/usr/share/alpine-mirrors/MIRRORS.txt
789N/A mirror_count=$(wc -l $mirror_list | cut -d " " -f 1)
787N/A random=$(hexdump -n 2 -e '/2 "%u"' /dev/urandom)
787N/A repository=$(sed $(expr $random % $mirror_count + 1)\!d \
294N/A $mirror_list)$auto_repo_dir
294N/A echo "Selecting mirror $repository"
789N/A fi
294N/A}
294N/A
294N/Ainstall_alpine() {
294N/A rootfs="$1"
789N/A shift
294N/A mkdir -p "$rootfs"/etc/apk || return 1
294N/A : ${keys_dir:=/etc/apk/keys}
294N/A if ! [ -d "$rootfs"/etc/apk/keys ] && [ -d "$keys_dir" ]; then
789N/A cp -r "$keys_dir" "$rootfs"/etc/apk/keys
294N/A fi
789N/A if [ -n "$repository" ]; then
294N/A echo "$repository" > "$rootfs"/etc/apk/repositories
789N/A else
789N/A cp /etc/apk/repositories "$rootfs"/etc/apk/repositories || return 1
789N/A if [ -n "$release" ]; then
789N/A sed -E -i "s:/[^/]+/([^/]+)$:/$release/\\1:" \
294N/A "$rootfs"/etc/apk/repositories
789N/A fi
789N/A fi
294N/A opt_arch=
789N/A if [ -n "$apk_arch" ]; then
789N/A opt_arch="--arch $apk_arch"
789N/A fi
789N/A $APK add -U --initdb --root $rootfs $opt_arch "$@" alpine-base
789N/A}
789N/A
294N/Aconfigure_alpine() {
294N/A rootfs="$1"
789N/A echo "Setting up /etc/inittab"
294N/A cat >"$rootfs"/etc/inittab<<EOF
294N/A::sysinit:/sbin/rc sysinit
789N/A::wait:/sbin/rc default
294N/Aconsole:12345:respawn:/sbin/getty 38400 console
294N/Atty1:12345:respawn:/sbin/getty 38400 tty1
294N/Atty2:12345:respawn:/sbin/getty 38400 tty2
789N/Atty3:12345:respawn:/sbin/getty 38400 tty3
294N/Atty4:12345:respawn:/sbin/getty 38400 tty4
789N/A::ctrlaltdel:/sbin/reboot
294N/A::shutdown:/sbin/rc shutdown
294N/AEOF
789N/A # set up timezone
789N/A if [ -f /etc/TZ ]; then
789N/A cp /etc/TZ "$rootfs/etc/TZ"
789N/A fi
789N/A
787N/A # set up nameserver
294N/A grep nameserver /etc/resolv.conf > "$rootfs/etc/resolv.conf"
789N/A
789N/A # configure the network using the dhcp
789N/A cat <<EOF > $rootfs/etc/network/interfaces
789N/Aauto lo
789N/Aiface lo inet loopback
789N/A
789N/Aauto eth0
294N/Aiface eth0 inet dhcp
294N/AEOF
294N/A
294N/A # set the hostname
294N/A echo $hostname > $rootfs/etc/hostname
294N/A
294N/A # missing device nodes
294N/A echo "Setting up device nodes"
294N/A mkdir -p -m 755 "$rootfs/dev/pts"
294N/A mkdir -p -m 1777 "$rootfs/dev/shm"
294N/A mknod -m 666 "$rootfs/dev/zero" c 1 5
294N/A mknod -m 666 "$rootfs/dev/full" c 1 7
294N/A mknod -m 666 "$rootfs/dev/random" c 1 8
294N/A mknod -m 666 "$rootfs/dev/urandom" c 1 9
294N/A mknod -m 666 "$rootfs/dev/tty0" c 4 0
294N/A mknod -m 666 "$rootfs/dev/tty1" c 4 1
294N/A mknod -m 666 "$rootfs/dev/tty2" c 4 2
789N/A mknod -m 666 "$rootfs/dev/tty3" c 4 3
789N/A mknod -m 666 "$rootfs/dev/tty4" c 4 4
789N/A# mknod -m 600 "$rootfs/dev/initctl" p
789N/A mknod -m 666 "$rootfs/dev/tty" c 5 0
789N/A mknod -m 666 "$rootfs/dev/console" c 5 1
789N/A mknod -m 666 "$rootfs/dev/ptmx" c 5 2
789N/A
789N/A # start services
789N/A ln -s /etc/init.d/bootmisc "$rootfs"/etc/runlevels/boot/bootmisc
789N/A ln -s /etc/init.d/syslog "$rootfs"/etc/runlevels/boot/syslog
789N/A
789N/A return 0
789N/A}
789N/A
789N/Acopy_configuration() {
789N/A path=$1
789N/A rootfs=$2
789N/A hostname=$3
789N/A
789N/A grep -q "^lxc.rootfs" $path/config 2>/dev/null \
789N/A || echo "lxc.rootfs = $rootfs" >> $path/config
789N/A if [ -n "$lxc_arch" ]; then
789N/A echo "lxc.arch = $lxc_arch" >> $path/config
789N/A fi
789N/A
789N/A lxc_network_link_line="# lxc.network.link = br0"
789N/A for br in lxcbr0 virbr0 br0; do
789N/A if [ -d /sys/class/net/$br/bridge ]; then
789N/A lxc_network_link_line="lxc.network.link = $br"
789N/A break
789N/A fi
789N/A done
789N/A
789N/A if ! grep -q "^lxc.network.type" $path/config 2>/dev/null; then
789N/A cat <<EOF >> $path/config
789N/Alxc.network.type = veth
789N/A$lxc_network_link_line
789N/Alxc.network.flags = up
789N/AEOF
789N/A fi
789N/A
789N/A # if there is exactly one veth or macvlan network entry, make sure
789N/A # it has an associated mac address.
789N/A nics=$(awk -F '[ \t]*=[ \t]*' \
789N/A '$1=="lxc.network.type" && ($2=="veth" || $2=="macvlan") {print $2}' \
789N/A $path/config | wc -l)
789N/A if [ "$nics" -eq 1 ] && ! grep -q "^lxc.network.hwaddr" $path/config; then
789N/A # see http://sourceforge.net/tracker/?func=detail&aid=3411497&group_id=163076&atid=826303
789N/A hwaddr="fe:$(dd if=/dev/urandom bs=8 count=1 2>/dev/null |od -t x8 | \
789N/A head -n 1 |awk '{print $2}' | cut -c1-10 |\
789N/A sed 's/\(..\)/\1:/g; s/.$//')"
789N/A echo "lxc.network.hwaddr = $hwaddr" >> $path/config
789N/A fi
294N/A
789N/A cat <<EOF >> $path/config
789N/A
789N/Alxc.tty = 4
789N/Alxc.pts = 1024
789N/Alxc.utsname = $hostname
789N/Alxc.cap.drop = sys_module mac_admin mac_override sys_time sys_admin
789N/A
789N/A# When using LXC with apparmor, uncomment the next line to run unconfined:
789N/A#lxc.aa_profile = unconfined
789N/A
789N/A# devices
789N/Alxc.cgroup.devices.deny = a
789N/A# /dev/null, zero and full
789N/Alxc.cgroup.devices.allow = c 1:3 rwm
789N/Alxc.cgroup.devices.allow = c 1:5 rwm
789N/Alxc.cgroup.devices.allow = c 1:7 rwm
789N/A# consoles
789N/Alxc.cgroup.devices.allow = c 5:1 rwm
789N/Alxc.cgroup.devices.allow = c 5:0 rwm
789N/Alxc.cgroup.devices.allow = c 4:0 rwm
789N/Alxc.cgroup.devices.allow = c 4:1 rwm
789N/A# /dev/{,u}random
789N/Alxc.cgroup.devices.allow = c 1:9 rwm
789N/Alxc.cgroup.devices.allow = c 1:8 rwm
789N/Alxc.cgroup.devices.allow = c 136:* rwm
789N/Alxc.cgroup.devices.allow = c 5:2 rwm
789N/A# rtc
789N/Alxc.cgroup.devices.allow = c 254:0 rm
789N/A
789N/A# mounts point
789N/Alxc.mount.auto=cgroup:mixed proc:mixed sys:mixed
789N/Alxc.mount.entry=run run tmpfs nodev,noexec,nosuid,relatime,size=1m,mode=0755 0 0
789N/Alxc.mount.entry=shm dev/shm tmpfs nodev,nosuid,noexec,mode=1777,create=dir 0 0
789N/A
789N/AEOF
789N/A
789N/A return 0
789N/A}
789N/A
789N/Adie() {
789N/A echo "$@" >&2
789N/A exit 1
789N/A}
789N/A
789N/Ausage() {
789N/A cat >&2 <<EOF
789N/AUsage: $(basename $0) [-h|--help] [-r|--repository <url>]
789N/A [-R|--release <release>] [-a|--arch <arch>]
789N/A [--rootfs <rootfs>] -p|--path <path> -n|--name <name>
789N/A [PKG...]
789N/AEOF
789N/A}
789N/A
789N/Ausage_err() {
787N/A usage
789N/A exit 1
789N/A}
789N/A
789N/Adefault_path=@LXCPATH@
789N/Arelease=
789N/Aarch=$(uname -m)
789N/A
789N/A# template mknods, requires root
789N/Aif [ $(id -u) -ne 0 ]; then
789N/A echo "$(basename $0): must be run as root" >&2
789N/A exit 1
789N/Afi
789N/A
789N/Aoptions=$(getopt -o hn:p:r:R:a: -l help,name:,rootfs:,path:,repository:,release:,arch: -- "$@")
789N/A[ $? -eq 0 ] || usage_err
789N/Aeval set -- "$options"
789N/A
789N/Awhile [ $# -gt 0 ]; do
789N/A case "$1" in
789N/A -h|--help)
789N/A usage
789N/A exit 0
789N/A ;;
789N/A -n|--name)
789N/A name=$2
789N/A ;;
789N/A --rootfs)
789N/A rootfs=$2
789N/A ;;
789N/A -p|--path)
789N/A path=$2
789N/A ;;
789N/A -r|--repository)
789N/A repository=$2
789N/A ;;
789N/A -R|--release)
789N/A release=$2
789N/A ;;
789N/A -a|--arch)
789N/A arch=$2
789N/A ;;
789N/A --)
789N/A shift
789N/A break;;
789N/A esac
789N/A shift 2
789N/Adone
789N/A
789N/A
789N/A[ -z "$name" ] && usage_err
789N/A
789N/Aif [ -z "${path}" ]; then
789N/A path="${default_path}/${name}"
789N/Afi
789N/A
789N/Aif [ -z "$rootfs" ]; then
787N/A rootfs=`awk -F= '$1 ~ /^lxc.rootfs/ { print $2 }' "$path/config" 2>/dev/null`
789N/A if [ -z "$rootfs" ]; then
789N/A rootfs="${path}/rootfs"
789N/A fi
789N/Afi
789N/A
789N/Alxc_arch=$arch
789N/Aapk_arch=$arch
789N/A
789N/Acase "$arch" in
789N/A i[3-6]86)
789N/A apk_arch=x86
789N/A lxc_arch=x86
789N/A ;;
789N/A x86)
789N/A lxc_arch=i686
789N/A ;;
789N/A x86_64|"")
789N/A ;;
789N/A arm*)
789N/A apk_arch=armhf
789N/A ;;
789N/A *)
789N/A die "unsupported architecture: $arch"
789N/A ;;
789N/Aesac
789N/A
789N/A: ${APK:=apk}
789N/Aif ! which $APK >/dev/null; then
789N/A get_static_apk "$rootfs" || die "Failed to download a valid static apk"
789N/Afi
789N/A
789N/Ainstall_alpine "$rootfs" "$@" || die "Failed to install rootfs for $name"
789N/Aconfigure_alpine "$rootfs" "$name" || die "Failed to configure $name"
789N/Acopy_configuration "$path" "$rootfs" "$name"
789N/A