[lxc-devel] [PATCH] v2 Refactoring lxc-autostart boot process and group handling.
Stéphane Graber
stgraber at ubuntu.com
Tue May 20 09:56:37 UTC 2014
On Mon, May 19, 2014 at 03:57:26PM -0400, Michael H. Warfield wrote:
> On Mon, 2014-05-19 at 17:22 +0200, Stéphane Graber wrote:
> > On Fri, May 16, 2014 at 02:07:31PM -0400, Michael H. Warfield wrote:
> > > Before anyone else spots it... I did miss one spot where I failed to
> > > toss a list (cmd_group_lists) on exit. So, some memory checkers will
> > > complain about orphaned memory or leaks (even though it's on exit).
> > > I'll fix that and add some doco once this has been reviewed further.
>
> > Hi,
>
> > I took a quick look at the proposed patch and don't have any issue with
> > it, so please resend with those updates done and I'll do some proper
> > testing and apply it.
>
> > Thanks!
>
> Ok... Ask and yea shall receive. Version 2 of the refactoring
> autostart patch with Dwight's patch and my other patches adding now the
> fix for the minor cleanup gotcha I spotted plus I enhanced the
> documentation in lxc-autostart.sgml.in for group handling.
>
> While this was going on, I also pinged Dwight about parameterizing the
> bootup groups and other options in the startup scripts. Consequently,
> with his concurrence, I've added some boot time configuration options to
> the sysvinit/systemd init script and the upstart configuration file for
> BOOTGROUPS, SHUTDOWNDELAY, OPTIONS, and STOPOPTS. For the former
> (Oracle, RHEL Fedora, CentOS, et al), it's in /etc/sysconfig/lxc and the
> later (Ubuntu, Debian, etc) in /etc/default/lxc. I've tested the
> sysvinit/systemd init script. Someone needs to verify the upstart
> changes.
>
> Attached below the jump.
>
> Thanks!
>
> Regards,
> Mike
==> Executing: "./autogen.sh" in /build/git/
+ test -d autom4te.cache
+ aclocal -I config
+ autoheader
+ autoconf
+ automake --add-missing --copy
configure.ac:31: installing 'config/compile'
configure.ac:30: installing 'config/config.guess'
configure.ac:30: installing 'config/config.sub'
configure.ac:29: installing 'config/install-sh'
configure.ac:29: installing 'config/missing'
configure.ac:565: error: required file 'config/init/systemd/lxc.service.in' not found
configure.ac:565: error: required file 'config/init/sysvinit/lxc.in' not found
src/lua-lxc/Makefile.am: installing 'config/depcomp'
+ exit 1
==> Cleaning up the environment
==> Exitting with status FAIL
Seems like "make dist" is missing a bunch of files...
> --
> 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!
>
>
> --
> v2 - Refactoring lxc-autostart boot process and group handling.
>
> This is a rollup of 5 earlier patches patching the systemd
> init to use the sysvinit script, adding an onboot group to the
> boot set, updating upstart to include the onboot group, and adding
> documentation for the special boot groups.
>
> This adds new functionality to lxc-autostart.
>
> *) The -g / --groups option is multiple cummulative entry.
> This may be mixed freely with the previous comma separated
> group list convention. Groups are processed in the
> order they first appear in the aggregated group list.
>
> *) The NULL group may be specified in the group list using either a
> leading comma, a trailing comma, or an embedded comma.
>
> *) Booting proceeds in order of the groups specified on the command line
> then ordered by lxc.start.org and name collalating sequence.
>
> *) Default host bootup is now specified as "-g onboot," meaning that first
> the "onboot" group is booted and then any remaining enabled
> containers in the NULL group are booted.
>
> *) Adds documentation to lxc-autostart for -g processing order and combinations.
>
> *) Parameterizes bootgroups, options, and shutdown delay in init scripts
> and services.
>
> From the previous 4 individual patches:
>
> Reported-by: CDR <venefax at gmail.com>
> Signed-off-by: Dwight Engen <dwight.engen at oracle.com>
>
> - reuse the sysvinit script to ensure that if the lxc is configured to use
> a bridge setup by libvirt, the bridge will be available before starting
> the container
>
> - made the sysvinit script check for the existance of ifconfig, and fall
> back to ip link list if available
>
> - made the lxc service also dependant on the network.target
>
> - autoconfized the paths in the service file and sysvinit script
>
> - v2: rename script lxc-autostart to lxc-autostart-helper to avoid confusion
>
> From: Michael H. Warfield <mhw at WittsEnd.com>
>
> - This adds a non-null group (onboot) to the sysvinit startup script
> for autobooting containers. This allows for containers which are
> in other groups to be included in the autoboot process.
>
> This script is used by both the sysvinit systems and the systemd
> systems.
>
> From: Michael H. Warfield <mhw at WittsEnd.com>
>
> - Add the feature to the Upstart init script to boot the "onboot"
> group dependent on the start.auto = 1 flag. This brings the
> the Upstart behavior into congruence with the sysvinit script
> for SysV Init and Systemd.
>
> From: Michael H. Warfield <mhw at WittsEnd.com>
>
> Added sections to lxc-autostart and lxc.container.config to document
> the behavior of the LXC service at host system boot time with regards
> to the lxc.group and lxc.start.auto parameters.
>
> 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/sysvinit/lxc | 66 --------
> config/init/upstart/lxc.conf | 44 +++++-
> 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 ++++++++++++++++++++++++++++++----------
> 10 files changed, 407 insertions(+), 172 deletions(-)
> delete mode 100644 config/init/systemd/lxc.service
> delete mode 100755 config/init/sysvinit/lxc
>
> 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/sysvinit/lxc b/config/init/sysvinit/lxc
> deleted file mode 100755
> index 5ab3c46..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 -a -A -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/upstart/lxc.conf b/config/init/upstart/lxc.conf
> index d5131ad..ab79aab 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,12 +44,28 @@ 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
> end script
>
> +# 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.
> post-stop script
> - lxc-autostart -a -A -s || true
> + [ -f /etc/default/lxc ] && . /etc/default/lxc
> +
> + if [ -n "$SHUTDOWNDELAY" ]
> + then
> + SHUTDOWNDELAY="-t $SHUTDOWNDELAY"
> + fi
> +
> + lxc-autostart $STOPOPTS $SHUTDOWNDELAY || true
> end script
> diff --git a/configure.ac b/configure.ac
> index 8865bc8..a7fce11 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -573,7 +573,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 3d423dd..3e12d5c 100644
> --- a/doc/lxc-autostart.sgml.in
> +++ b/doc/lxc-autostart.sgml.in
> @@ -154,8 +154,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 concatentated. 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>
> @@ -185,6 +194,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 c7b36a4..30fe4a8 100644
> --- a/doc/lxc.container.conf.sgml.in
> +++ b/doc/lxc.container.conf.sgml.in
> @@ -1486,6 +1486,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 1e0c608..0cab734 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)
> {
> @@ -38,7 +41,7 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
> case 's': args->shutdown = 1; break;
> case 'a': args->all = 1; break;
> case 'A': args->ignore_auto = 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;
> @@ -79,6 +82,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;
> @@ -102,6 +128,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;
> @@ -209,15 +307,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,
> @@ -236,112 +348,167 @@ 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 (!my_args.ignore_auto &&
> - 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 (!my_args.ignore_auto &&
> + 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"));
> + }
> }
> }
> - }
>
> + /*
> + * 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;
> + }
> + }
>
> - lxc_container_put(c);
> }
>
> - 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]);
> }
> + }
> +
> + if ( c_groups_lists )
> + free(c_groups_lists);
> +
> + if ( cmd_groups_list ) {
> + toss_list( cmd_groups_list );
> free(cmd_groups_list);
> }
>
> --
> 1.9.0
>
>
--
Stéphane Graber
Ubuntu developer
http://www.ubuntu.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20140520/e25e0250/attachment-0001.sig>
More information about the lxc-devel
mailing list