[lxc-devel] ubuntu-cloud-prep: patch /sbin/start for overlayfs

Scott Moser smoser at ubuntu.com
Fri Aug 16 20:47:32 UTC 2013


upstart depends on inotify, and overlayfs does not support inotify.

That means that the following results in 'tgt' not running. tgt is simply
used here as an example of a service that installs an upstart job and
starts it on package install.
 lxc-clone -s -B overlayfs -o source-precise-amd64 -n test1
 lxc-start -n test1
 ..
 apt-get install tgt

The change here is to modify /sbin/start inside the container so that when
something explicitly tries 'start', it results in an explicit call to
'initctl reload-configuration' so that upstart is aware of the newly
placed job.

Should overlayfs ever gain inotify support, this should still not cause
any harm.

Signed-off-by: Scott Moser <smoser at ubuntu.com>

diff --git a/hooks/ubuntu-cloud-prep b/hooks/ubuntu-cloud-prep
index 7985a73..5e0a999 100755
--- a/hooks/ubuntu-cloud-prep
+++ b/hooks/ubuntu-cloud-prep
@@ -12,6 +12,7 @@
 ##  LXC_SRC_NAME:     old container name
 ##  LXC_ROOTFS_PATH:  path or device on which the root fs is located

+set -f
 VERBOSITY="0"

 error() { echo "$@" 1>&2; }
@@ -34,9 +35,56 @@ Usage: ${0##*/} [options] root-dir
 EOF
 }

+write_patched_start() {
+    cat > "$1" <<"EOF"
+#!/bin/bash
+## This is a wrapper around upstart's /sbin/start to ensure that
+## calling 'start' on a job after writing it to /etc/init will function
+## correctly despite broken/missing support for inotify in overlayfs.
+##
+real() { exec -a /sbin/start "/sbin/start.real" "$@"; }
+
+# no args or not root
+[ $# -ne 0 -a "$UID" = "0" ] || real "$@"
+
+job=""
+# find first argument that doesn't start with '-' as 'job'
+for x in "$@"; do
+  [ "${x#-}" = "$x" ] && { job="$x"; break; }
+done
+
+# if job isn't there, no reason to check further
+[ -n "$job" ] && [ -f "/etc/init/$job.conf" ] || real "$@"
+
+# on Unknown, 'status' exits 1, and prints 'Unknown job' to stderr.
+out=$(status "$@" 2>&1)
+[ $? -eq 1 -a "${out#*nknown job}" != "$out" ] || real "$@"
+
+initctl reload-configuration >/dev/null 2>&1
+real "$@"
+EOF
+    chmod 755 "$1"
+}
+
+patch_start() {
+    # patch /sbin/start inside root_d to deal with lack of inotify
+    local root_d="$1"
+
+    # already patched
+    [ -f "$root_d/sbin/start.real" ] &&
+        { debug 1 "$root_d 'start' seems already patched"; return 1; }
+
+    debug 1 "patching /sbin/start in $root_d"
+    chroot "$root_d" dpkg-divert --local --rename \
+        --divert /sbin/start.real --add /sbin/start ||
+        { error "failed to patch /sbin/start for overlayfs"; return 1; }
+
+    write_patched_start "$root_d/sbin/start"
+}
+
 prep() {
     local short_opts="Chi:L:S:u:v"
-    local long_opts="auth-key:,cloud,help,hostid:,name:,nolocales:,userdata:,verbose"
+    local long_opts="auth-key:,cloud,help,hostid:,name:,nolocales:,patch-start,userdata:,verbose"
     local getopt_out getopt_ret
     getopt_out=$(getopt --name "${0##*/}" \
         --options "${short_opts}" --long "${long_opts}" -- "$@" 2>/dev/null) ||
@@ -49,6 +97,8 @@ prep() {

     local cur="" next=""
     local userdata="" hostid="" authkey="" locales=1 cloud=0 name=""
+    local patch_start=0
+
     while [ $# -ne 0 ]; do
         cur="$1"; next="$2";
         case "$cur" in
@@ -57,6 +107,7 @@ prep() {
                --name) name="$next";;
             -i|--hostid) hostid="$next";;
             -L|--nolocales) locales=0;;
+               --patch-start) patch_start=1;;
             -S|--auth-key)
                 [ -f "$next" ] ||
                     { error "--auth-key: '$next' not a file"; return 1; }
@@ -86,6 +137,9 @@ prep() {
         error "${0##*}: usage failed, continuing with defaults"
     fi

+    [ "$patch_start" -eq 0 ] || patch_start "$root_d" ||
+        { error "failed to patch start for overlayfs"; return 1; }
+
     local seed_d=""
     seed_d="$root_d/var/lib/cloud/seed/nocloud-net"
     if [ $cloud -eq 1 ]; then
@@ -149,10 +203,13 @@ main() {
     local _LXC_HOOK
     if [ -n "$LXC_ROOTFS_MOUNT" -a "$3" = "clone" ]; then
         _LXC_HOOK="clone"
-        local name="$1"
+        local name="$1" pstart=""
         shift 3
-        debug 1 prep "--name=$name" "$LXC_ROOTFS_MOUNT" "$@"
-        prep "--name=$name" "$LXC_ROOTFS_MOUNT" "$@"
+        # if mountpoint is overlayfs then add '--patch-start'
+        [ "${LXC_ROOTFS_PATH#overlayfs}" != "${LXC_ROOTFS_PATH}" ] &&
+           pstart="--patch-start"
+        debug 1 prep "--name=$name" $pstart "$LXC_ROOTFS_MOUNT" "$@"
+        prep "--name=$name" $pstart "$LXC_ROOTFS_MOUNT" "$@"
     else
         _LXC_HOOK=""
         prep "$@"




More information about the lxc-devel mailing list