#!/bin/bash # # chkconfig: 345 20 80 # description: Create BTRFS subvolumes for LXC reference images. # # Thierry Parmentelat # Copyright (C) 2012 INRIA # # not needed -- Source function library #. /etc/init.d/functions # 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) rpms 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 function check_node () { mount | grep -q 'planetlab-vservers' || exit 0 [ -d $sliceimage_dir ] || { echo "No sliceimage installed" ; exit 1; } } function start () { echo "lxc-sliceimage: --- STARTING $(date) ---" check_node mkdir -p $lxc_dir slicefamilies=$(cd $sliceimage_dir ; ls ) for slicefamily in $slicefamilies; do echo ==================== $slicefamily # initialize if needed [ -d $lxc_dir/$slicefamily ] || { echo "creating btrfs subvolume" ; 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 ? # echo "============================== mirroring start $(date)" echo "$sliceimage_dir/$slicefamily/ onto btrfs subvolume $lxc_dir/$slicefamily/" # mention --delete for rpm updates # we want to keep only our own additions, that will be re-created in the remaining # of this script anyway rsync -a --delete $sliceimage_dir/$slicefamily/ $lxc_dir/$slicefamily/ # echo "============================== mirroring done $(date)" # adapting slice images to the node virtualization mode can unfortunately # not be done at build-time since we do not know that yet patch_lvref $lxc_dir/$slicefamily done # create ref images from stubs unfold_system_slices echo "lxc-sliceimage: --- DONE $(date) ---" } 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 } # prefer to use e.g. # sed -i $rootfs/etc/sudoers # rather than # chroot $rootfs sed -i /etc/sudoers # because the latter has sed issue weird messages like # sed: warning: failed to get security context of ... function patch_lvref () { rootfs=$1; shift echo "patch_lvref : handling $rootfs" # Allow a user who logins via ssh to sudo sed -i 's/^Defaults\ *requiretty/\#&/' $rootfs/etc/sudoers # Allow to login at virsh console. loginuid.so doen't work in the absence of auditd # which cannot run inside a container. sed -i 's/^.*loginuid.so.*$/\#&/' $rootfs/etc/pam.d/login # Enable eth0 on bootup cat < $rootfs/etc/sysconfig/network-scripts/ifcfg-eth0 DEVICE=eth0 BOOTPROTO=dhcp ONBOOT=yes EOF # Tweak sshd configuration - not all slice images have sshd preinstalled if [ -f $rootfs/etc/ssh/sshd_config ] ; then sed -e 's/^UsePAM\ *yes/\#&/' \ -e 's/^GSSAPIAuthentication.*$/GSSAPIAuthentication no/' \ -e 's/^PasswordAuthentication.*$/PasswordAuthentication no/' \ -i $rootfs/etc/ssh/sshd_config fi # 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 # this will run only if the rootfs seems to be systemd-based patch_lvref_systemd $rootfs } # beware that patch_lvref_systemd will return early on non systemd-powered images # inspired from https://gist.github.com/1142202 ETC=/etc/systemd/system LIB=/lib/systemd/system function patch_lvref_systemd () { rootfs=$1; shift absetc=$rootfs/$ETC abslib=$rootfs/$LIB # this applies to systemd only [ -d $abslib ] || return # stay away from trouble, avoid chroot'ing for straightforward stuff echo "patch_lvref_systemd: handling $rootfs" # sliceimage comes with graphical.target as default ln -sf $LIB/multi-user.target $absetc/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. cp $abslib/basic.target $absetc/basic.target sed -e 's/sysinit.target/systemd-tmpfiles-setup.service/' -i $absetc/basic.target # Stop starting sysinit.target. Symlinking one to /dev/null is a standard way # to disable a target (or a service and others). ln -sf /dev/null $absetc/sysinit.target # is also a cause of stuck on boot ln -sf /dev/null $absetc/udev-settle.service # It prevents systemd-tmpfiles-setup.service from starting ln -sf /dev/null $absetc/fedora-readonly.service # Libvirt lxc provides only tty1 rm -f $absetc/getty.target.wants/getty\@tty{2,3,4,5,6}.service # It launches sulogin on console(tty1) but it interferes getty@tty1 ln -sf /dev/null $absetc/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. cp $abslib/getty\@.service $absetc/getty\@.service sed -e 's/^BindTo/\#&/' -i $absetc/getty\@.service ln -sf $ETC/getty\@.service $absetc/getty.target.wants/getty\@tty1.service } function unfold_system_slices () { for clonedstamp in $sliceimage_stubs/*/*.cloned; do unfold_system_slice_from_cloned $clonedstamp done } # untested - how does this behave when updating the slice reference image ? # OTOH system slices probably already run at update-time # so it's kind of too late anyways 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" ] && { echo "unfold_system_slice_from_cloned : $VREFPATH looks fine" ; return ; } [ -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 } # run with the --tty option to see results, otherwise get that logged case "$1" in --tty) shift;; *) exec >> /var/log/lxc-sliceimage 2>&1 ;; esac case "$1" in start|restart|reload) start ; exit 0 ;; status) status ; exit 0 ;; stop) exit 0 ;; *) echo $"Usage: $0 [--tty] {start|stop|status}" exit 1 ;; esac