#!/bin/bash # # Control program for bespoke arbitrary services through unshared sub-hosts # # $1 = the command: start or stop # $2 = the sub-host to start or stop # $3... = the optional chroot-ed command (/startup by default) set -x SCRIPT=$0 CMD=$1 NAME=$2 shift 2 usage() { echo "$SCRIPT (start|stop) " >&2 exit 1 } [ -z "$NAME" ] && usage : ${SUBHOST=/opt/subhost} : ${OSROOT=} : ${TOP=$SUBHOST/$NAME} : ${TARGET=$TOP/live} : ${IMAGE=$TOP/$NAME.img} : ${UPPER=$TOP/root} : ${WORK=$TOP/work} : ${MOUNT=$TOP/mnt} : ${NSNAME=$NAME} : ${BRIDGES=lan_br} : ${CONFIG=$TOP/config} [ -e "$CONFIG" ] && . "$CONFIG" cd "$SUBHOST" || exit 1 # Create a simple overlay subhost without its own image file create_subhost() { mkdir -p $TARGET $MOUNT $UPPER $WORK [ -d "$OSROOT" ] || OSROOT=$SUBHOST/chimaera/base [ -e $CONFIG ] || cat < "$CONFIG" # Subhost $NAME is an autogenerated overlay subhost with shared filesystem OSROOT="$OSROOT" BRIDGES="$BRIDGES" EOF } # Generate a mac address for given arguments pass through 40-bit b2sum # and with 02: prefix. macaddr() { local V="$(b2sum -l 40 <<< "$*" )" V="$( sed 's/\(..\)/\1:/g' <<< "${V}aaaaaaaaaa")" echo "02:${V:0:14}" } # setup the subhost network namespace and link up the host side setup_network() { E=0 ip netns add $NSNAME for BRIDGE in ${BRIDGES[@]} ; do IF=$NAME$E B=( ${BRIDGE/:/ } ) BRIDGE="${B[0]}" MAC="${B[1]}" [ -z "$MAC" ] && MAC="$(macaddr "$(hostname)" "$NAME" "$IF")" brctl show $BRIDGE >& /dev/null || brctl addbr $BRIDGE ip link add $IF type veth peer name eth$E address $MAC netns $NSNAME ip link set $IF up [ -n "$BRIDGE" ] && brctl addif $BRIDGE $IF E=$((E+1)) done } # check if $1 is mounted is_mounted() { grep -qE "^[^ ]+ $1 " /proc/mounts } # Setup or re-setup the subhost filesystem setup_rootfs() { if is_mounted $TARGET ; then mount -oremount $TARGET else if [ -e "$IMAGE" ] ; then # $IMAGE is either an image file or a link to a partition, # with /root and /work in it. is_mounted $MOUNT || mount $IMAGE $MOUNT || exit 1 UPPER=$MOUNT/root WORK=$MOUNT/work fi if [ -z "$OSROOT" ] ; then # No overlay mount --rbind $UPPER $TARGET else # overlay of $UPPER (+$WORK) over $OSROOT onto $TARGET mount -t overlay $NAME \ -olowerdir=$OSROOT,upperdir=$UPPER,workdir=$WORK \ $TARGET fi fi } # Set up cgroup CPU accounting (cpuacct) accounting() { # 1-- once, system wide grep -q "/sys/fs/cgroup cgroup" /proc/mounts || \ mount -t cgroup -ocpuacct none /sys/fs/cgroup if [ -d /sys/fs/cgroup/$NAME ] ; then : # reset? else mkdir /sys/fs/cgroup/$NAME # the following fixes things that sometimes are broken? for f in cpuset.mems cpuset.cpus ; do [ -z "$(cat /sys/fs/cgroups/$NAME/$F)" ] && \ echo 0 > /sys/fs/cgroups/$NAME/$F done fi # Register this task for subhost accounting echo $$ > /sys/fs/cgroup/$NAME/tasks } case "$CMD" in start) [ -e "/run/netns/$NSNAME" ] || setup_network [ -d "$MOUNT" ] || create_subhost setup_rootfs START=/bin/bash [ -x $TARGET/startup ] && START=/startup accounting exec ip netns exec $NSNAME unshare \ --fork --pid --mount-proc --kill-child \ --uts --ipc --mount --cgroup \ chroot $TARGET $START ;; stop) umount $TARGET [ -e $IMAGE ] && umount $MOUNT ip netns del $NSNAME rmdir /sys/fs/cgroup/$NAME ;; *) usage ;; esac