[lxc-devel] Cherry-picking to stable-1.0

Michael H. Warfield mhw at WittsEnd.com
Thu Jun 5 21:40:18 UTC 2014


On Thu, 2014-06-05 at 15:09 -0400, Stéphane Graber wrote:
> On Thu, Jun 05, 2014 at 10:10:39AM -0400, Dwight Engen wrote:
> > On Wed, 04 Jun 2014 19:04:03 -0400
> > "Michael H. Warfield" <mhw at WittsEnd.com> wrote:
> > 
> > > On Wed, 2014-06-04 at 17:41 -0400, Stéphane Graber wrote:
> > > > On Wed, Jun 04, 2014 at 05:32:37PM -0400, Michael H. Warfield wrote:
> > > > > On Wed, 2014-04-30 at 15:47 -0400, Stéphane Graber wrote:
> > > > > > Hello,
> > > > > 
> > > > > > I intend to release 1.0.4 next week and am currently going
> > > > > > through all the commits in master which should be included in
> > > > > > the bugfix release.
> > > > > 
> > > > > "Next week" came and passed but we've all been busy (especially
> > > > > you). Any time frame on this?  I'm trying to position the Fedora
> > > > > Project to move on 1.0.4 as soon as it releases and I'm walking
> > > > > down their bugzilla list now.
> > > 
> > > > I'm slowly going through
> > > > https://github.com/lxc/lxc/issues?milestone=7&page=1&state=open
> > > > figuring out what we actually want fixed and what should be
> > > > postponed.
> > > 
> > > > But things are starting to look good, I'm back home and so there's a
> > > > good chance we'll have this out the door in the next week or so.
> > > 
> > > > > Will the startup initscript and lxc-autostarat changes that
> > > > > Dwight and I worked out make it into 1.0.4 at this point?
> > > 
> > > > I didn't plan on including it as it felt a bit much for a stable
> > > > release update though I didn't spend much time thinking about it
> > > > and maybe it's fine after all. If you'd like it, I can give it some
> > > > more thoughts and see exactly what bits may be controversial in
> > > > there (potential breakage to existing setups mostly).
> > 
> > I understand about not wanting to break existing stuff, and I haven't
> > thought hard about that but I would like to point out that the systemd
> > unit file we shipped before was broken as what it pointed to didn't
> > exist, so that part certainly seems like a worthwhile fix for stable.

> Ok, so I just had a quick look and the change from master won't apply
> cleanly anyway because we don't have the --ignore-auto/-A option in
> stable's lxc-autostart.

Yeah, that was kinda ugly.  It actually probably would have been easier
to add the -A option and patch forward.  One stinking line in the middle
of hunk 6 of the lxc_autostart.c patch and I had to go over every line
in the main loop to be sure I got it right.  Hunk 6 covered about 80% of
main.  :-P

There was also a failed hunk in the upstart init case that was easy
enough to deal with.  I cleaned up the sysvinit script as well to avoid
the "-A".

IAC...

> I agree that in systemd's case, things can't really be much worse
> compared to what we currently have in stable, so I'm fine with applying
> the change in that regard. On the sysvinit/upstart side, the change
> won't cause any user visible change of behaviour unless the user was
> using "onboot" already for something else (doubtful).

/me biting my tongue about systemd...

Ask and ye shall receive.  The backported autoboot rollup patch with all
the little gotchas, including the speeling eroor that KATOH had caught.
It's after the jump.  Patch against stable-1.0.

> So while I'm not thrilled getting that kind of big changeset into
> stable, it's doable and I'll apply it if someone can get me a version of
> the change which actually applies.
> 
> > > I tried pretty much to go out of my way to insure it wouldn't break
> > > any pre-existing setup.  The only thing where that might be
> > > questionable is if someone was already doing something weird with
> > > groups but, even then, the startup behavior had been only the NULL
> > > group before and now is configurable.
> > > 
> > > I'm pretty happy with it and Dwight seems pretty happy with it.  I
> > > have it in production now.  I'd personally like to see it show up in
> > > the next iteration of the Fedora package, which I may now have a hand
> > > in...
> > > 
> > > > > Regards,
> > > > > Mike
> > > 
> > > Regards,
> > > Mike
> > > 
> > > > > > Most of them applied cleanly except for two:
> > > > > >  - [PATCH] Convert punctuation marks in Japanese man pages
> > > > > >    This one we thought was identical for both branches, this
> > > > > > turned out to be wrong, so instead of cherry-picking from
> > > > > > master, I applied the one from the stable-1.0 pull request I
> > > > > > was sent.
> > > > > >  - [PATCH] lxc-oracle: fix warnings/errors from some rpm
> > > > > > scriptlets This one fails to apply on current stable-1.0,
> > > > > > probably because of the changes done to the Oracle template to
> > > > > > support installing from media. If those fixes should be
> > > > > > backported to stable, I'd appreciate receiving a separate patch
> > > > > > for that.
> > > > > > 
> > > > > > 
> > > > > > I've also gone through all the patches that have been stacking
> > > > > > in my mailbox, at the moment, the only unreviewed patches in
> > > > > > there are the menuconfig change. If you submitted something
> > > > > > else and it's not in master now, please re-send.
> > > > > > 
> > > > > > Thanks!

Regards,
Mike
-- 
Michael H. Warfield (AI4NB) | (770) 978-7061 |  mhw at WittsEnd.com
   /\/\|=mhw=|\/\/          | (678) 463-0932 |  http://www.wittsend.com/mhw/
   NIC whois: MHW9          | An optimist believes we live in the best of all
 PGP Key: 0x674627FF        | possible worlds.  A pessimist is sure of it!


-- 
From 2da3cfecb11c52f5c282b84d8601433d862875cc Mon Sep 17 00:00:00 2001
From: "Michael H. Warfield" <mhw at WittsEnd.com>
Date: Thu, 5 Jun 2014 17:28:07 -0400
Subject: [PATCH] Backport of autoboot/autostart rollup to stable-1.0
Organization: Thaumaturgy & Speculums Technology

Full backport of the autostart / autoboot rollup patch from
master to stable-1.0.

Signed-off-by: Michael H. Warfield <mhw at WittsEnd.com>
---
 .gitignore                         |   3 +
 config/init/systemd/Makefile.am    |  14 +-
 config/init/systemd/lxc.service    |  17 --
 config/init/systemd/lxc.service.in |  17 ++
 config/init/sysvinit/lxc           |  66 --------
 config/init/sysvinit/lxc.in        | 124 ++++++++++++++
 config/init/upstart/lxc.conf       |  32 +++-
 configure.ac                       |   2 +
 doc/lxc-autostart.sgml.in          |  76 ++++++++-
 doc/lxc.container.conf.sgml.in     |  23 +++
 lxc.spec.in                        |   1 +
 src/lxc/lxc_autostart.c            | 333 +++++++++++++++++++++++++++----------
 12 files changed, 536 insertions(+), 172 deletions(-)
 delete mode 100644 config/init/systemd/lxc.service
 create mode 100644 config/init/systemd/lxc.service.in
 delete mode 100755 config/init/sysvinit/lxc
 create mode 100644 config/init/sysvinit/lxc.in

diff --git a/.gitignore b/.gitignore
index 8145f81..2b478cd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -111,6 +111,9 @@ config/missing
 config/libtool.m4
 config/lt*.m4
 config/bash/lxc
+config/init/systemd/lxc-autostart-helper
+config/init/systemd/lxc.service
+config/init/sysvinit/lxc
 
 doc/*.1
 doc/*.5
diff --git a/config/init/systemd/Makefile.am b/config/init/systemd/Makefile.am
index de5ee50..fc374c5 100644
--- a/config/init/systemd/Makefile.am
+++ b/config/init/systemd/Makefile.am
@@ -5,7 +5,17 @@ EXTRA_DIST = \
 if INIT_SCRIPT_SYSTEMD
 SYSTEMD_UNIT_DIR = $(prefix)/lib/systemd/system
 
-install-systemd: lxc.service lxc-devsetup
+lxc-autostart-helper: ../sysvinit/lxc.in $(top_builddir)/config.status
+	$(AM_V_GEN)sed                                          \
+	    -e 's|[@]SYSCONFDIR[@]|$(sysconfdir)|g'             \
+	    -e 's|[@]LOCALSTATEDIR[@]|$(localstatedir)|g'       \
+	    -e 's|[@]BINDIR[@]|$(bindir)|g'                     \
+	    < $< > $@-t &&                                      \
+	    chmod a+x $@-t &&                                   \
+	    mv $@-t $@
+BUILT_SOURCES = lxc-autostart-helper
+
+install-systemd: lxc.service lxc-devsetup lxc-autostart-helper
 	$(MKDIR_P) $(DESTDIR)$(SYSTEMD_UNIT_DIR)
 	$(INSTALL_DATA) lxc.service $(DESTDIR)$(SYSTEMD_UNIT_DIR)/
 
@@ -13,7 +23,7 @@ uninstall-systemd:
 	rm -f $(DESTDIR)$(SYSTEMD_UNIT_DIR)/lxc.service
 	rmdir $(DESTDIR)$(SYSTEMD_UNIT_DIR) || :
 
-pkglibexec_SCRIPTS = lxc-devsetup
+pkglibexec_SCRIPTS = lxc-devsetup lxc-autostart-helper
 
 install-data-local: install-systemd
 uninstall-local: uninstall-systemd
diff --git a/config/init/systemd/lxc.service b/config/init/systemd/lxc.service
deleted file mode 100644
index aa20b91..0000000
--- a/config/init/systemd/lxc.service
+++ /dev/null
@@ -1,17 +0,0 @@
-[Unit]
-Description=LXC Container Initialization and Autoboot Code
-After=syslog.target
-
-[Service]
-Type=oneshot
-RemainAfterExit=yes
-ExecStartPre=/usr/libexec/lxc/lxc-devsetup
-ExecStart=/usr/libexec/lxc/lxc-startup start
-ExecStop=/usr/libexec/lxc/lxc-startup stop
-# Environment=BOOTUP=serial
-# Environment=CONSOLETYPE=serial
-StandardOutput=syslog
-StandardError=syslog
-
-[Install]
-WantedBy=multi-user.target
diff --git a/config/init/systemd/lxc.service.in b/config/init/systemd/lxc.service.in
new file mode 100644
index 0000000..5f155b6
--- /dev/null
+++ b/config/init/systemd/lxc.service.in
@@ -0,0 +1,17 @@
+[Unit]
+Description=LXC Container Initialization and Autoboot Code
+After=syslog.target network.target
+
+[Service]
+Type=oneshot
+RemainAfterExit=yes
+ExecStartPre=@libexecdir@/lxc/lxc-devsetup
+ExecStart=@libexecdir@/lxc/lxc-autostart-helper start
+ExecStop=@libexecdir@/lxc/lxc-autostart-helper stop
+# Environment=BOOTUP=serial
+# Environment=CONSOLETYPE=serial
+StandardOutput=syslog
+StandardError=syslog
+
+[Install]
+WantedBy=multi-user.target
diff --git a/config/init/sysvinit/lxc b/config/init/sysvinit/lxc
deleted file mode 100755
index 09e3922..0000000
--- a/config/init/sysvinit/lxc
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/bin/sh
-#
-# lxc Start/Stop LXC autoboot containers
-#
-# chkconfig: 345 99 01
-# description: Starts/Stops all LXC containers configured for autostart.
-#
-### BEGIN INIT INFO
-# Provides: lxc
-# Default-Start: 3 4 5
-# Default-Stop: 0 1 6
-# Short-Description: Bring up/down LXC autostart containers
-# Description: Bring up/down LXC autostart containers
-### END INIT INFO
-
-# Source function library.
-. /etc/init.d/functions
-
-# Check for needed utility program
-[ -x /usr/bin/lxc-autostart ] || exit 1
-
-# If libvirtd is providing the bridge, it might not be
-# immediately available, so wait a bit for it before starting
-# up the containers or else any that use the bridge will fail
-# to start
-wait_for_bridge()
-{
-    [ -f /etc/lxc/default.conf ] || { return 0; }
-
-    BRNAME=`grep '^[ 	]*lxc.network.link' /etc/lxc/default.conf | sed 's/^.*=[ 	]*//'`
-    if [ -z "$BRNAME" ]; then
-	return 0
-    fi
-
-    for try in `seq 1 30`; do
-	ifconfig -a |grep "^$BRNAME" >/dev/null 2>&1
-	if [ $? = 0 ]; then
-	    return
-	fi
-	sleep 1
-    done
-}
-
-# See how we were called.
-case "$1" in
-  start)
-	[ ! -f /var/lock/subsys/lxc ] || { exit 0; }
-
-	# Start containers
-	wait_for_bridge
-	action $"Starting LXC containers: " /usr/bin/lxc-autostart
-	touch /var/lock/subsys/lxc
-	;;
-  stop)
-	action $"Stopping LXC containers: " /usr/bin/lxc-autostart -s
-	rm -f /var/lock/subsys/lxc
-	;;
-  restart|reload|force-reload)
-	$0 stop
-	$0 start
-	;;
-  *)
-	echo $"Usage: $0 {start|stop|restart|reload|force-reload}"
-	exit 2
-esac
-exit $?
diff --git a/config/init/sysvinit/lxc.in b/config/init/sysvinit/lxc.in
new file mode 100644
index 0000000..4bfd0f0
--- /dev/null
+++ b/config/init/sysvinit/lxc.in
@@ -0,0 +1,124 @@
+#!/bin/sh
+#
+# lxc Start/Stop LXC autoboot containers
+#
+# chkconfig: 345 99 01
+# description: Starts/Stops all LXC containers configured for autostart.
+#
+### BEGIN INIT INFO
+# Provides: lxc
+# Default-Start: 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: Bring up/down LXC autostart containers
+# Description: Bring up/down LXC autostart containers
+### END INIT INFO
+
+sysconfdir="@SYSCONFDIR@"
+bindir="@BINDIR@"
+localstatedir="@LOCALSTATEDIR@"
+
+# These can be overridden in @SYSCONFDIR@/sysconfig/lxc
+
+# BOOTGROUPS - What groups should start on bootup?
+#	Comma separated list of groups.
+#	Leading comma, trailing comma or embedded double
+#	comma indicates when the NULL group should be run.
+# Example (default): boot the onboot group first then the NULL group
+BOOTGROUPS="onboot,"
+
+# SHUTDOWNDELAY - Wait time for a container to shut down.
+#	ner shutdown can result in lengthy system
+#	shutdown times.  Even 5 seconds per container can be
+#	too long.
+SHUTDOWNDELAY=5
+
+# OPTIONS can be used for anything else.
+#	If you want to boot everything then
+#	options can be "-a" or "-a -A".
+OPTIONS=
+
+# STOPOPTS are stop options.  The can be used for anything else to stop.
+#	If you want to kill containers fast, use -k
+STOPOPTS="-a -s"
+
+# Source function library.
+test ! -r "$sysconfdir"/rc.d/init.d/functions ||
+        . "$sysconfdir"/rc.d/init.d/functions
+
+# Source any configurable options
+test ! -r "$sysconfdir"/sysconfig/lxc ||
+        . "$sysconfdir"/sysconfig/lxc
+
+# Check for needed utility program
+[ -x "$bindir"/lxc-autostart ] || exit 1
+
+# If libvirtd is providing the bridge, it might not be
+# immediately available, so wait a bit for it before starting
+# up the containers or else any that use the bridge will fail
+# to start
+wait_for_bridge()
+{
+    [ -f "$sysconfdir"/lxc/default.conf ] || { return 0; }
+
+    which ifconfig >/dev/null 2>&1
+    if [ $? = 0 ]; then
+        cmd="ifconfig -a"
+    else
+        which ip >/dev/null 2>&1
+        if [ $? = 0 ]; then
+            cmd="ip link list"
+        fi
+    fi
+    [ -n cmd ] || { return 0; }
+
+    BRNAME=`grep '^[ 	]*lxc.network.link' "$sysconfdir"/lxc/default.conf | sed 's/^.*=[ 	]*//'`
+    if [ -z "$BRNAME" ]; then
+	return 0
+    fi
+
+    for try in `seq 1 30`; do
+	eval $cmd |grep "^$BRNAME" >/dev/null 2>&1
+	if [ $? = 0 ]; then
+	    return
+	fi
+	sleep 1
+    done
+}
+
+# See how we were called.
+case "$1" in
+  start)
+	[ ! -f "$localstatedir"/lock/subsys/lxc ] || { exit 0; }
+
+	if [ -n "$BOOTGROUPS" ]
+	then
+		BOOTGROUPS="-g $BOOTGROUPS"
+	fi
+
+	# Start containers
+	wait_for_bridge
+	# Start autoboot containers first then the NULL group "onboot,".
+	action $"Starting LXC autoboot containers: " /usr/bin/lxc-autostart $OPTIONS $BOOTGROUPS
+	touch "$localstatedir"/lock/subsys/lxc
+	;;
+  stop)
+	if [ -n "$SHUTDOWNDELAY" ]
+	then
+		SHUTDOWNDELAY="-t $SHUTDOWNDELAY"
+	fi
+
+	# The stop is serialized and can take excessive time.  We need to avoid
+	# delaying the system shutdown / reboot as much as we can since it's not
+	# parallelized...  Even 5 second timout may be too long.
+	action $"Stopping LXC containers: " "$bindir"/lxc-autostart $STOPOPTS $SHUTDOWNDELAY
+	rm -f "$localstatedir"/lock/subsys/lxc
+	;;
+  restart|reload|force-reload)
+	$0 stop
+	$0 start
+	;;
+  *)
+	echo $"Usage: $0 {start|stop|restart|reload|force-reload}"
+	exit 2
+esac
+exit $?
diff --git a/config/init/upstart/lxc.conf b/config/init/upstart/lxc.conf
index 1a5c5c9..fae8836 100644
--- a/config/init/upstart/lxc.conf
+++ b/config/init/upstart/lxc.conf
@@ -6,6 +6,30 @@ stop on starting rc RUNLEVEL=[016]
 
 env LXC_AUTO="false"
 
+# These can be overridden in /etc/default/lxc
+
+# BOOTGROUPS - What groups should start on bootup?
+#	Comma separated list of groups.
+#	Leading comma, trailing comma or embedded double
+#	comma indicates when the NULL group should be run.
+# Example (default): boot the onboot group first then the NULL group
+env BOOTGROUPS="onboot,"
+
+# SHUTDOWNDELAY - Wait time for a container to shut down.
+#	Container shutdown can result in lengthy system
+#	shutdown times.  Even 5 seconds per container can be
+#	too long.
+env SHUTDOWNDELAY=5
+
+# OPTIONS can be used for anything else.
+#	If you want to boot everything then
+#	options can be "-a" or "-a -A".
+env OPTIONS=
+
+# STOPOPTS are stop options.  The can be used for anything else to stop.
+#	If you want to kill containers fast, use -k
+env STOPOPTS="-a -A -s"
+
 pre-start script
 	[ -f /etc/default/lxc ] && . /etc/default/lxc
 
@@ -20,7 +44,13 @@ pre-start script
 
 	[ "x$LXC_AUTO" = "xtrue" ] || exit 0
 
-	lxc-autostart -L | while read line; do
+	if [ -n "$BOOTGROUPS" ]
+	then
+		BOOTGROUPS="-g $BOOTGROUPS"
+	fi
+
+	# Process the "onboot" group first then the NULL group.
+	lxc-autostart -L $OPTIONS $BOOTGROUPS | while read line; do
 		set -- $line
 		(start lxc-instance NAME=$1 && sleep $2) || true
 	done
diff --git a/configure.ac b/configure.ac
index d2304c2..655d0de 100644
--- a/configure.ac
+++ b/configure.ac
@@ -575,7 +575,9 @@ AC_CONFIG_FILES([
 	config/bash/lxc
 	config/init/Makefile
 	config/init/sysvinit/Makefile
+	config/init/sysvinit/lxc
 	config/init/systemd/Makefile
+	config/init/systemd/lxc.service
 	config/init/upstart/Makefile
 	config/etc/Makefile
 	config/templates/Makefile
diff --git a/doc/lxc-autostart.sgml.in b/doc/lxc-autostart.sgml.in
index 985cbe4..8d42fc4 100644
--- a/doc/lxc-autostart.sgml.in
+++ b/doc/lxc-autostart.sgml.in
@@ -153,8 +153,17 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
                 </term>
                 <listitem>
                     <para>
-                        Comma separate list of groups to select
-                        (defaults to those without a lxc.group).
+                        Comma separated list of groups to select
+                        (defaults to those without a lxc.group - the NULL group).
+                        This option may be specified multiple times
+                        and the arguments concatenated.  The NULL or
+                        empty group may be specified as a leading comma,
+                        trailing comma, embedded double comma, or empty
+                        argument where the NULL group should be processed.
+                        Groups are processed in the order specified on the
+                        command line.  Multiple invocations of the -g option
+                        may be freely intermixed with the comma separated
+                        lists and will be combined in specified order.
                     </para>
                 </listitem>
             </varlistentry>
@@ -172,6 +181,69 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
         </variablelist>
     </refsect1>
 
+    <refsect1>
+        <title>Autostart and System Boot</title>
+
+        <para>
+            The <command>lxc-autostart</command> command is used as part of the
+            LXC system service, when enabled to run on host system at bootup and at
+            shutdown.  It's used to select which containers to start in what order
+            and how much to delay between each startup when the host system boots.
+        </para>
+
+        <para>
+            Each container can be part of any number of groups or no group at all.
+            Two groups are special. One is the NULL group, i.e. the container does
+            not belong to any group. The other group is the "onboot" group.
+        </para>
+
+        <para>
+            When the system boots with the LXC service enabled, it will first
+            attempt to boot any containers with lxc.start.auto == 1 that is a member
+            of the "onboot" group. The startup will be in order of lxc.start.order.
+            If an lxc.start.delay has been specified, that delay will be honored
+            before attempting to start the next container to give the current
+            container time to begin initialization and reduce overloading the host
+            system. After starting the members of the "onboot" group, the LXC system
+            will proceed to boot containers with lxc.start.auto == 1 which are not
+            members of any group (the NULL group) and proceed as with the onboot
+            group.
+        </para>
+    </refsect1>
+
+    <refsect1>
+        <title>Startup Group Examples</title>
+        <variablelist>
+            <varlistentry>
+                <term>
+                    <option>-g "onboot,"</option>
+                </term>
+                <listitem>
+                    <para>
+                        Start the "onboot" group first then the NULL group.
+                    </para>
+                    <para>
+                        This is the equivalent of: <option>-g onboot -g ""</option>.
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>
+                    <option>-g "dns,web,,onboot"</option>
+                </term>
+                <listitem>
+                    <para>
+                        Starts the "dns" group first, the "web" group second, then
+                        the NULL group followed by the "onboot" group.
+                    </para>
+                    <para>
+                        This is the equivalent of: <option>-g dns,web -g ,onboot</option> or <option>-g dns -g web -g "" -g onboot</option>.
+                    </para>
+                </listitem>
+            </varlistentry>
+        </variablelist>
+    </refsect1>
+
     &seealso;
 
     <refsect1>
diff --git a/doc/lxc.container.conf.sgml.in b/doc/lxc.container.conf.sgml.in
index 3e2208b..d3533de 100644
--- a/doc/lxc.container.conf.sgml.in
+++ b/doc/lxc.container.conf.sgml.in
@@ -1472,6 +1472,29 @@ mknod errno 0
         </varlistentry>
       </variablelist>
     </refsect2>
+
+    <refsect2>
+    <title>Autostart and System Boot</title>
+    <para>
+          Each container can be part of any number of groups or no group at all.
+          Two groups are special. One is the NULL group, i.e. the container does
+          not belong to any group. The other group is the "onboot" group.
+    </para>
+
+    <para>
+          When the system boots with the LXC service enabled, it will first
+          attempt to boot any containers with lxc.start.auto == 1 that is a member
+          of the "onboot" group. The startup will be in order of lxc.start.order.
+          If an lxc.start.delay has been specified, that delay will be honored
+          before attempting to start the next container to give the current
+          container time to begin initialization and reduce overloading the host
+          system. After starting the members of the "onboot" group, the LXC system
+          will proceed to boot containers with lxc.start.auto == 1 which are not
+          members of any group (the NULL group) and proceed as with the onboot
+          group.
+    </para>
+
+    </refsect2>
   </refsect1>
 
   <refsect1>
diff --git a/lxc.spec.in b/lxc.spec.in
index 2717c83..57912a1 100644
--- a/lxc.spec.in
+++ b/lxc.spec.in
@@ -154,6 +154,7 @@ rm -rf %{buildroot}
 %attr(4111,root,root) %{_libexecdir}/%{name}/lxc-user-nic
 %if %{with_systemd}
 %attr(555,root,root) %{_libexecdir}/%{name}/lxc-devsetup
+%attr(555,root,root) %{_libexecdir}/%{name}/lxc-autostart-helper
 %endif
 
 %if %{with_python}
diff --git a/src/lxc/lxc_autostart.c b/src/lxc/lxc_autostart.c
index be032a7..2b55398 100644
--- a/src/lxc/lxc_autostart.c
+++ b/src/lxc/lxc_autostart.c
@@ -28,6 +28,9 @@
 #include "log.h"
 
 lxc_log_define(lxc_autostart_ui, lxc);
+static struct lxc_list *accumulate_list(char *input, char *delimiter, struct lxc_list *str_list);
+
+struct lxc_list *cmd_groups_list = NULL;
 
 static int my_parser(struct lxc_arguments* args, int c, char* arg)
 {
@@ -37,7 +40,7 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
 	case 'r': args->reboot = 1; break;
 	case 's': args->shutdown = 1; break;
 	case 'a': args->all = 1; break;
-	case 'g': args->groups = arg; break;
+	case 'g': cmd_groups_list = accumulate_list( arg, ",", cmd_groups_list); break;
 	case 't': args->timeout = atoi(arg); break;
 	}
 	return 0;
@@ -76,6 +79,29 @@ Options:\n\
 	.timeout = 60,
 };
 
+int list_contains_entry( char *str_ptr, struct lxc_list *p1 ) {
+	struct lxc_list *it1;
+
+	/*
+	 * If the entry is NULL or the empty string and the list
+	 * is NULL, we have a match
+	 */
+	if (! p1 && ! str_ptr)
+		return 1;
+	if (! p1 && ! *str_ptr)
+		return 1;
+
+	if (!p1)
+		return 0;
+
+	lxc_list_for_each(it1, p1) {
+		if (strcmp(it1->elem, str_ptr) == 0)
+			return 1;
+	}
+
+	return 0;
+}
+
 int lists_contain_common_entry(struct lxc_list *p1, struct lxc_list *p2) {
 	struct lxc_list *it1;
 	struct lxc_list *it2;
@@ -99,6 +125,78 @@ int lists_contain_common_entry(struct lxc_list *p1, struct lxc_list *p2) {
 	return 0;
 }
 
+/*
+ * This is a variation of get_list below it.
+ * This version allows two additional features.
+ * If a list is passed to it, it adds to it.
+ * It allows for empty entries (i.e. "group1,,group2") generating
+ * 	and empty list entry.
+ */
+static struct lxc_list *accumulate_list(char *input, char *delimiter, struct lxc_list *str_list) {
+	char *workstr = NULL;
+	char *workptr = NULL;
+	char *next_ptr = NULL;
+	struct lxc_list *worklist;
+	struct lxc_list *workstr_list;
+
+	workstr = strdup(input);
+	if (!workstr) {
+		return NULL;
+	}
+
+	workstr_list = str_list;
+	if ( ! workstr_list ) {
+		workstr_list = malloc(sizeof(*workstr_list));
+		lxc_list_init(workstr_list);
+	}
+
+	for (workptr = workstr; workptr; workptr = next_ptr) {
+		/*
+		 * We can't use strtok_r here because it collapses
+		 * multiple delimiters into 1 making empty fields
+		 * impossible...
+		 */
+		/* token = strtok_r(workptr, delimiter, &sptr); */
+		next_ptr = strchr( workptr, *delimiter );
+
+		if( next_ptr ) {
+			*next_ptr++ = '\0';
+		}
+
+		/*
+		 * At this point, we'd like to check to see if this
+		 * group is already contained in the list and ignore
+		 * it if it is...  This also helps us with any
+		 * corner cases where a string begins or ends with a
+		 * delimiter.
+		 */
+
+		if ( list_contains_entry( workptr, workstr_list ) ) {
+			if ( *workptr ) {
+				fprintf(stderr, "Duplicate group \"%s\" in list - ignoring\n", workptr );
+			} else {
+				fprintf(stderr, "Duilicate NULL group in list - ignoring\n" );
+			}
+		} else {
+			worklist = malloc(sizeof(*worklist));
+			if (!worklist)
+				break;
+
+			worklist->elem = strdup(workptr);
+			if (!worklist->elem) {
+				free(worklist);
+				break;
+			}
+
+			lxc_list_add_tail(workstr_list, worklist);
+		}
+	}
+
+	free(workstr);
+
+	return workstr_list;
+}
+
 static struct lxc_list *get_list(char *input, char *delimiter) {
 	char *workstr = NULL;
 	char *workptr = NULL;
@@ -206,15 +304,29 @@ static int cmporder(const void *p1, const void *p2) {
 		return (c1_order - c2_order) * -1;
 }
 
+static int toss_list( struct lxc_list *c_groups_list ) {
+	struct lxc_list *it, *next;
+
+	if (c_groups_list) {
+		lxc_list_for_each_safe(it, c_groups_list, next) {
+			lxc_list_del(it);
+			free(it->elem);
+			free(it);
+		}
+		free(c_groups_list);
+	}
+
+	return 1;
+}
+
 int main(int argc, char *argv[])
 {
 	int count = 0;
 	int i = 0;
 	int ret = 0;
 	struct lxc_container **containers = NULL;
-	struct lxc_list *cmd_groups_list = NULL;
-	struct lxc_list *c_groups_list = NULL;
-	struct lxc_list *it, *next;
+	struct lxc_list **c_groups_lists = NULL;
+	struct lxc_list *cmd_group;
 	char *const default_start_args[] = {
 		"/sbin/init",
 		NULL,
@@ -233,112 +345,165 @@ int main(int argc, char *argv[])
 	if (count < 0)
 		return 1;
 
-	qsort(&containers[0], count, sizeof(struct lxc_container *), cmporder);
+	if (!my_args.all) {
+		/* Allocate an array for our container group lists */
+		c_groups_lists = calloc( count, sizeof( struct lxc_list * ) );
+	}
 
-	if (my_args.groups && !my_args.all)
-		cmd_groups_list = get_list((char*)my_args.groups, ",");
+	qsort(&containers[0], count, sizeof(struct lxc_container *), cmporder);
 
-	for (i = 0; i < count; i++) {
-		struct lxc_container *c = containers[i];
+	if (cmd_groups_list && my_args.all) {
+		fprintf(stderr, "Specifying -a (all) with -g (groups) doesn't make sense. All option overrides.");
+	}
 
-		if (!c->may_control(c)) {
-			lxc_container_put(c);
-			continue;
-		}
+	if (!cmd_groups_list) {
+		/*
+		 * We need a default cmd_groups_list even for the -a
+		 * case in order to force a pass through the loop for
+		 * the NULL group.  This, someday, could be taken from
+		 * a config file somewhere...
+		 */
+		cmd_groups_list = accumulate_list( "" , ",", NULL );
+	}
 
-		if (get_config_integer(c, "lxc.start.auto") != 1) {
-			lxc_container_put(c);
-			continue;
-		}
+	lxc_list_for_each(cmd_group, cmd_groups_list) {
 
-		if (!my_args.all) {
-			/* Filter by group */
-			c_groups_list = get_config_list(c, "lxc.group");
+		/*
+		 * Prograpmmers Note:
+		 * Because we may take several passes through the container list
+		 * We'll switch on if the container pointer is NULL and if we process a
+		 * container (run it or decide to ignore it) and call lxc_container_put
+		 * then we'll NULL it out and not check it again.
+		 */
+		for (i = 0; i < count; i++) {
+			struct lxc_container *c = containers[i];
 
-			ret = lists_contain_common_entry(cmd_groups_list, c_groups_list);
+			if (!c)
+				/* Skip - must have been already processed */
+				continue;
 
-			if (c_groups_list) {
-				lxc_list_for_each_safe(it, c_groups_list, next) {
-					lxc_list_del(it);
-					free(it->elem);
-					free(it);
-				}
-				free(c_groups_list);
+			/*
+			 * We haven't loaded the container groups yet so
+			 * these next two checks don't need to free them
+			 * if they fail.  They'll fail on the first pass.
+			 */
+			if (!c->may_control(c)) {
+				/* We're done with this container */
+				if ( lxc_container_put(c) > 0 )
+					containers[i] = NULL;
+				continue;
 			}
 
-			if (ret == 0) {
-				lxc_container_put(c);
+			if (get_config_integer(c, "lxc.start.auto") != 1) {
+				/* We're done with this container */
+				if ( lxc_container_put(c) > 0 )
+					containers[i] = NULL;
 				continue;
 			}
-		}
 
-		c->want_daemonize(c, 1);
-
-		if (my_args.shutdown) {
-			/* Shutdown the container */
-			if (c->is_running(c)) {
-				if (my_args.list)
-					printf("%s\n", c->name);
-				else {
-					if (!c->shutdown(c, my_args.timeout)) {
-						if (!c->stop(c)) {
-							fprintf(stderr, "Error shutting down container: %s\n", c->name);
+			if (!my_args.all) {
+				/* Filter by group */
+				if( ! c_groups_lists[i] ) {
+					/* Now we're loading up a container's groups */
+					c_groups_lists[i] = get_config_list(c, "lxc.group");
+				}
+
+				ret = list_contains_entry(cmd_group->elem, c_groups_lists[i]);
+
+				if ( ret == 0 ) {
+					/* Not in the target group this pass */
+					/* Leave in the list for subsequent passes */
+					continue;
+				}
+			}
+
+			/* We have a candidate continer to process */
+			c->want_daemonize(c, 1);
+
+			if (my_args.shutdown) {
+				/* Shutdown the container */
+				if (c->is_running(c)) {
+					if (my_args.list)
+						printf("%s\n", c->name);
+					else {
+						if (!c->shutdown(c, my_args.timeout)) {
+							if (!c->stop(c)) {
+								fprintf(stderr, "Error shutting down container: %s\n", c->name);
+							}
 						}
 					}
 				}
 			}
-		}
-		else if (my_args.hardstop) {
-			/* Kill the container */
-			if (c->is_running(c)) {
-				if (my_args.list)
-					printf("%s\n", c->name);
-				else {
-					if (!c->stop(c))
-						fprintf(stderr, "Error killing container: %s\n", c->name);
+			else if (my_args.hardstop) {
+				/* Kill the container */
+				if (c->is_running(c)) {
+					if (my_args.list)
+						printf("%s\n", c->name);
+					else {
+						if (!c->stop(c))
+							fprintf(stderr, "Error killing container: %s\n", c->name);
+					}
 				}
 			}
-		}
-		else if (my_args.reboot) {
-			/* Reboot the container */
-			if (c->is_running(c)) {
-				if (my_args.list)
-					printf("%s %d\n", c->name,
-					       get_config_integer(c, "lxc.start.delay"));
-				else {
-					if (!c->reboot(c))
-						fprintf(stderr, "Error rebooting container: %s\n", c->name);
-					else
-						sleep(get_config_integer(c, "lxc.start.delay"));
+			else if (my_args.reboot) {
+				/* Reboot the container */
+				if (c->is_running(c)) {
+					if (my_args.list)
+						printf("%s %d\n", c->name,
+							get_config_integer(c, "lxc.start.delay"));
+					else {
+						if (!c->reboot(c))
+							fprintf(stderr, "Error rebooting container: %s\n", c->name);
+						else
+							sleep(get_config_integer(c, "lxc.start.delay"));
+					}
 				}
 			}
-		}
-		else {
-			/* Start the container */
-			if (!c->is_running(c)) {
-				if (my_args.list)
-					printf("%s %d\n", c->name,
-					       get_config_integer(c, "lxc.start.delay"));
-				else {
-					if (!c->start(c, 0, default_start_args))
-						fprintf(stderr, "Error starting container: %s\n", c->name);
-					else
-						sleep(get_config_integer(c, "lxc.start.delay"));
+			else {
+				/* Start the container */
+				if (!c->is_running(c)) {
+					if (my_args.list)
+						printf("%s %d\n", c->name,
+							get_config_integer(c, "lxc.start.delay"));
+					else {
+						if (!c->start(c, 0, default_start_args))
+							fprintf(stderr, "Error starting container: %s\n", c->name);
+						else
+							sleep(get_config_integer(c, "lxc.start.delay"));
+					}
 				}
 			}
-		}
-
 
-		lxc_container_put(c);
+			/*
+			 * If we get this far and we haven't hit any skip "continue"
+			 * then we're done with this container...  We can dump any
+			 * c_groups_list and the container itself.
+			 */
+			if ( lxc_container_put(c) > 0 ) {
+				containers[i] = NULL;
+			}
+			if ( c_groups_lists && c_groups_lists[i] ) {
+				toss_list(c_groups_lists[i]);
+				c_groups_lists[i] = NULL;
+			}
+		}
 	}
 
-	if (cmd_groups_list) {
-		lxc_list_for_each_safe(it, cmd_groups_list, next) {
-			lxc_list_del(it);
-			free(it->elem);
-			free(it);
+	/* clean up any lingering detritus */
+	for (i = 0; i < count; i++) {
+		if ( containers[i] ) {
+			lxc_container_put(containers[i]);
+		}
+		if ( c_groups_lists && c_groups_lists[i] ) {
+			toss_list(c_groups_lists[i]);
 		}
-		free(cmd_groups_list);
+	}
+
+	if ( c_groups_lists )
+		free(c_groups_lists);
+
+	if ( cmd_groups_list ) {
+		toss_list( cmd_groups_list );
 	}
 
 	free(containers);
-- 
1.9.3


-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 482 bytes
Desc: This is a digitally signed message part
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20140605/df540c03/attachment-0001.sig>


More information about the lxc-devel mailing list