#!/bin/bash
+#
# chkconfig: 345 20 80
# description: Create BTRFS subvolumes for LXC reference images.
#
+# Thierry Parmentelat <thierry.parmentelat@inria.fr>
+# Copyright (C) 2012 INRIA
+#
+# not needed -- Source function library
+#. /etc/init.d/functions
-case "$1" in
- start|restart|reload)
- ;;
- force)
- FORCE=true;;
- stop|status)
- exit 0
- ;;
- *)
- echo $"Usage: $0 {start|stop|restart|reload|status|force}"
- exit 1
- ;;
-esac
+# a f>=18 root context won't have /bin nor /sbin in its path, which is where
+# chkconfig is located on f<=14 images
+export PATH=$PATH:/bin:/sbin
+
+# This is where sliceimage(s) store their reference images
+sliceimage_dir=/vservers/.vref
+sliceimage_stubs=/vservers/.vstub
+lxc_dir=/vservers/.lvref
+tmp_dir=/vservers/.ltmp
# Check if we are in the build environment
-mount | grep -q 'planetlab-vservers' || exit 0
+function check_node () {
+ mount | grep -q 'planetlab-vservers' || exit 0
+ [ -d $sliceimage_dir ] || { echo "No sliceimage installed" ; exit 1; }
+}
-# Source function library
-. /etc/init.d/functions
+function start () {
-# xxx get version some other way
-# might just want to scan /vservers/.vref instead
-# upgrades (from the real image to the .lvref area) might be challenging
-# xxx
+ check_node
+
+ mkdir -p $lxc_dir
-sliceimage_dir=/vservers/.vref
+ slicefamilies=$(cd $sliceimage_dir ; ls )
+
+ for slicefamily in $slicefamilies; do
+ # initialize if needed
+ [ -d $lxc_dir/$slicefamily ] || btrfs subvolume create $lxc_dir/$slicefamily
+ # xxx what is that ?
+ #btrfs subvolume create $lxc_dir/lxc-squeeze-x86_64
+ # copy the slice image into the btrfs ?
+ rsync -a --delete $sliceimage_dir/$slicefamily/ $lxc_dir/$slicefamily/
+ # tmp -- should very probably be done at build time
+ patch_lvref $lxc_dir/$slicefamily
+ done
+
+ # create ref images from stubs
+ unfold_system_slices
+}
+
+function status () {
+ echo -n "Checking node .. "
+ check_node
+ echo OK
+ echo "From installed sliceimage variants"
+ ls $sliceimage_dir
+ echo "Exported to lxc"
+ ls $lxc_dir
+}
+
+# inspired from https://gist.github.com/1142202
+ETC=/etc/systemd/system
+LIB=/lib/systemd/system
+function patch_lvref () {
+ # this applies to systemd only
+ [ -d $rootfs/$LIB ] || return
+ rootfs=$1; shift
+ # sliceimage comes with graphical.target as default
+ chroot $rootfs ln -sf $LIB/multi-user.target $ETC/default.target
+ # sysinit.target seems to stick on boot, so disable it. However, we need
+ # systemd-tmpfiles-setup.service that was started by the dependency of
+ # sysinit.target to boot up correctly, so start it instead.
+ chroot $rootfs cp $LIB/basic.target $ETC/basic.target
+ chroot $rootfs sed -i 's/sysinit.target/systemd-tmpfiles-setup.service/' $ETC/basic.target
+ # Stop starting sysinit.target. Symlinking one to /dev/null is a standard way
+ # to disable a target (or a service and others).
+ chroot $rootfs ln -s /dev/null $ETC/sysinit.target
+ # It also a cause of stuck on boot
+ chroot $rootfs ln -s /dev/null $ETC/udev-settle.service
+ # It prevents systemd-tmpfiles-setup.service from starting
+ chroot $rootfs ln -s /dev/null $ETC/fedora-readonly.service
+ # Libvirt lxc provides only tty1
+ chroot $rootfs rm -f $ETC/getty.target.wants/getty\@tty{2,3,4,5,6}.service
+ # It launches sulogin on console(tty1) but it interferes getty@tty1
+ chroot $rootfs ln -s /dev/null $ETC/console-shell.service
+ # Workarounds for libvirt 0.9.4. Without this, getty@tty1 doen't launch
+ # because a trigger event on tty1 doesn't happen.
+ chroot $rootfs cp $LIB/getty\@.service $ETC/getty\@.service
+ chroot $rootfs sed -i 's/^BindTo/\#&/' $ETC/getty\@.service
+ chroot $rootfs ln -sf $ETC/getty\@.service $ETC/getty.target.wants/getty\@tty1.service
+ # Allow a user who logins via ssh to sudo
+ chroot $rootfs sed -i 's/^Defaults\ *requiretty/\#&/' /etc/sudoers
+ # Allow to login at virsh console. loginuid.so doen't work in the absence of auditd
+ # which cannot run inside a container.
+ chroot $rootfs sed -i 's/^.*loginuid.so.*$/\#&/' /etc/pam.d/login
+ # Enable eth0 on bootup
+ cat <<EOF > $rootfs/etc/sysconfig/network-scripts/ifcfg-eth0
+DEVICE=eth0
+BOOTPROTO=dhcp
+ONBOOT=yes
+EOF
+ # Tweak sshd configuration
+ chroot $rootfs sed -i 's/^UsePAM\ *yes/\#&/' /etc/ssh/sshd_config
+ # commenting out the defaults in the file is not enough, need to explicitly set these to no
+ chroot $rootfs sed -i 's/^GSSAPIAuthentication.*$/GSSAPIAuthentication no/' /etc/ssh/sshd_config
+ chroot $rootfs sed -i 's/^PasswordAuthentication.*$/PasswordAuthentication no/' /etc/ssh/sshd_config
+ # Allow root to login at virsh console
+ echo "pts/0" >> $rootfs/etc/securetty
+ # our image does not have NetworkManager, only network, and it is off by default
+ chroot $rootfs chkconfig network on
+}
+
+function unfold_system_slices () {
+ for clonedstamp in $sliceimage_stubs/*/*.cloned; do
+ unfold_system_slice_from_cloned $clonedstamp
+ done
+}
+
+function unfold_system_slice_from_cloned () {
+ clonedstamp=$1; shift
+ # e.g. NAME=planetflow
+ NAME=$(basename $clonedstamp .cloned)
+ DIR=$(dirname $clonedstamp)
+ # e.g. SLICEFAMILY=planetlab-f8-i386
+ SLICEFAMILY=$(cat $clonedstamp)
+ # deduce the actual name used in .vref by replacing the first part of slice-family
+ # (pldistro) with the slice name
+ # e.g. VREFNAME=planetflow-f8-i386
+ VREFNAME=$(echo $SLICEFAMILY | sed -e "s,^[^-]*-,$NAME-,")
+
+ VREFPATH="$lxc_dir/$VREFNAME"
+
+ # do not redo existing vref's unless force is mentioned
+ [ -z "$FORCE" -a -d "$VREFPATH" ] && continue
+ [ -z "$FORCE" ] && message=Building
+ [ -n "$FORCE" ] && message=Force-building
+
+ # Copy base reference image
+ echo -n $"$message slice image for $NAME in $VREFNAME: "
+
+ # build the systemslice from the one it was originally cloned from
+ FAMILYREF="$lxc_dir/$SLICEFAMILY"
+ if [ ! -d "$FAMILYREF" ] ; then
+ echo system slice from $clonedstamp - could not find reference $FAMILYREF - skipped
+ return
+ fi
+
+ # safe side
+ mkdir -p "$lxc_dir"
+ # cleanup reference image if already exists
+ [ -d "$VREFPATH" ] && btrfs subvolume delete "$VREFPATH"
+ # extra safe
+ [ -d "$VREFPATH" ] && rm -rf "$VREFPATH"
+
+ # clone subvolume
+ btrfs subvolume snapshot $FAMILYREF $VREFPATH
+
+ # merge the stub with the reference to get the system slice
+ (cd "$DIR/$NAME"/ && find . | cpio -m -d -u -p "$VREFPATH"/) || \
+ { echo "Could not apply stub $DIR/$NAME - skipping $clonedstamp" ; btrfs subvolume delete "$VREFPATH" ; return ; }
+
+ # Clean RPM state
+ rm -f "$VREFPATH/var/lib/rpm/__db"*
+
+ echo Done
+}
+
+case "$1" in
+ start|restart|reload) start ; exit 0 ;;
+ status) status ; exit 0 ;;
+ stop) exit 0 ;;
+ *) echo $"Usage: $0 {start|stop|status}"
+ exit 1
+ ;;
+esac
-[ -d $sliceimage_dir ] || exit 0
-
-sliceimages=$(cd $sliceimage_dir ; ls )
-
-for sliceimage in $sliceimages; do
- mkdir -p /vservers/.lvref
- [ -d /vservers/.lvref/$sliceimage ] && continue
- btrfs subvolume create /vservers/.lvref/$sliceimage
-# what is that ?
-# btrfs subvolume create /vservers/.lvref/lxc-squeeze-x86_64
- # copy the slice image into the btrfs ?
- tar -C $sliceimage_dir -cf - $sliceimage | tar -C /vservers/.lvref -xf -
-# we need a smarter way to handle upgrades
-# the original code trashed the ref image that came with an rpm
-# rm -rf /vservers/lxc-reference-${VERSION}.tgz
-# this would probably cause the image to be re-created upon yum update
-# or prevent updates to make it to the node ?
-# rm -rf $sliceimage_dir/$sliceimage
-fi
-
-exit 0