[lxc-devel] [PATCH 1/3] lxc-stop: use api, remove lxc_shutdown, extend lxc-stop functionality

Serge Hallyn serge.hallyn at ubuntu.com
Mon May 20 17:47:32 UTC 2013


[ Christian: this should be a good starting point for adding the
lxc.signal.{halt,reboot,kill}, etc.  If you don't have time, I'll
get back to looking at that later.  Thanks! ]

implement c->reboot(c) in the api.

Also if the container is not running, return -2.  Currently
lxc-stop will return 0, so you cannot tell the difference
between successfull stopping and noop.

Per stgraber's email:

 - Remove lxc-shutdown
 - Change lxc-stop so that:
   * Default behaviour is to call shutdown(), wait 15s for STOPPED, if
not STOPPED, print a message to the user and call stop() [ NOTE:
actually 60 seconds per followup thread]
   * We have a -r option to reboot the container (with proper check that
the container indeed rebooted within the next 15s)
   * We have a -s option to shutdown the container without the automatic
fallback to stop()
   * Add a -k option allowing a user to just kill a container
(equivalent to old lxc-stop, no shutdown() call and no delay).

and update manpages.

Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
---
 configure.ac             |   2 -
 doc/Makefile.am          |   1 -
 doc/lxc-shutdown.sgml.in |  98 ----------------------------
 doc/lxc-stop.sgml.in     |  92 ++++++++++++++++++++++++--
 src/lxc/Makefile.am      |   1 -
 src/lxc/arguments.h      |   6 +-
 src/lxc/lxc-shutdown.in  | 165 -----------------------------------------------
 src/lxc/lxc_stop.c       | 117 ++++++++++++++++++++++++++++++++-
 src/lxc/lxccontainer.c   |  18 ++++++
 src/lxc/lxccontainer.h   |   2 +
 10 files changed, 225 insertions(+), 277 deletions(-)
 delete mode 100644 doc/lxc-shutdown.sgml.in
 delete mode 100644 src/lxc/lxc-shutdown.in

diff --git a/configure.ac b/configure.ac
index 414d71b..8979f75 100644
--- a/configure.ac
+++ b/configure.ac
@@ -334,7 +334,6 @@ AC_CONFIG_FILES([
 	doc/lxc-netstat.sgml
 	doc/lxc-ps.sgml
 	doc/lxc-restart.sgml
-	doc/lxc-shutdown.sgml
 	doc/lxc-start-ephemeral.sgml
 	doc/lxc-start.sgml
 	doc/lxc-stop.sgml
@@ -383,7 +382,6 @@ AC_CONFIG_FILES([
 	src/lxc/lxc-checkconfig
 	src/lxc/lxc-version
 	src/lxc/lxc-create
-	src/lxc/lxc-shutdown
 	src/lxc/lxc-start-ephemeral
 	src/lxc/lxc-destroy
 	src/lxc/legacy/lxc-ls
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 1a24695..a00036a 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -22,7 +22,6 @@ man_MANS = \
 	lxc-netstat.1 \
 	lxc-ps.1 \
 	lxc-restart.1 \
-	lxc-shutdown.1 \
 	lxc-start.1 \
 	lxc-stop.1 \
 	lxc-unfreeze.1 \
diff --git a/doc/lxc-shutdown.sgml.in b/doc/lxc-shutdown.sgml.in
deleted file mode 100644
index 9262c6d..0000000
--- a/doc/lxc-shutdown.sgml.in
+++ /dev/null
@@ -1,98 +0,0 @@
-<!--
-
-Copyright (C) 2012 Canonical, Inc
-
-Authors: Serge Hallyn <serge.hallyn at canonical.com>
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version.
-
-This library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
--->
-
-<!DOCTYPE refentry PUBLIC @docdtd@ [
-
-<!ENTITY commonoptions SYSTEM "@builddir@/common_options.sgml">
-<!ENTITY seealso SYSTEM "@builddir@/see_also.sgml">
-]>
-
-<refentry>
-
-  <docinfo><date>@LXC_GENERATE_DATE@</date></docinfo>
-
-  <refmeta>
-    <refentrytitle>lxc-shutdown</refentrytitle>
-    <manvolnum>1</manvolnum>
-  </refmeta>
-
-  <refnamediv>
-    <refname>lxc-shutdown</refname>
-
-    <refpurpose>
-      externally shut down or reboot a container
-    </refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <cmdsynopsis>
-      <command>lxc-shutdown</command>
-      <arg choice="req">-n <replaceable>name</replaceable></arg>
-      <arg choice="opt">-w</arg>
-      <arg choice="opt">-r</arg>
-    </cmdsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>
-      <command>lxc-shutdown</command> sends a SIGPWR signal to the
-      specified container to request it to cleanly shut down.  If
-      <optional>-w</optional> is specified, then <command>lxc-shutdown</command>
-      will wait until the container has shut down before exiting.
-      If <optional>-r</optional> is specified, the container will be
-      asked to reboot (using a SIGINT signal), and <optional>-w</optional>
-      will be ignored.  If the container ignore these signals, then
-      nothing will happen.  In that case, you can use <command>lxc-stop</command>
-      to force the container to stop.
-    </para>
-
-  </refsect1>
-
-  &commonoptions;
-
-  &seealso;
-
-  <refsect1>
-    <title>Author</title>
-    <para>Serge Hallyn <email>serge.hallyn at canonical.com</email></para>
-  </refsect1>
-
-</refentry>
-
-<!-- Keep this comment at the end of the file
-Local variables:
-mode: sgml
-sgml-omittag:t
-sgml-shorttag:t
-sgml-minimize-attributes:nil
-sgml-always-quote-attributes:t
-sgml-indent-step:2
-sgml-indent-data:t
-sgml-parent-document:nil
-sgml-default-dtd-file:nil
-sgml-exposed-tags:nil
-sgml-local-catalogs:nil
-sgml-local-ecat-files:nil
-End:
--->
diff --git a/doc/lxc-stop.sgml.in b/doc/lxc-stop.sgml.in
index b4dcc1b..2dbff80 100644
--- a/doc/lxc-stop.sgml.in
+++ b/doc/lxc-stop.sgml.in
@@ -50,6 +50,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
     <cmdsynopsis>
       <command>lxc-stop</command>
       <arg choice="req">-n <replaceable>name</replaceable></arg>
+      <arg choice="opt">-W</arg>
+      <arg choice="opt">-r</arg>
+      <arg choice="opt">-t <replaceable>timeout</replaceable></arg>
+      <arg choice="opt">-k</arg>
+      <arg choice="opt">-s</arg>
     </cmdsynopsis>
   </refsynopsisdiv>
 
@@ -57,14 +62,90 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
     <title>Description</title>
 
     <para>
-      <command>lxc-stop</command> kills all the processes inside the
-      container. This command should be used if the processes are no
-      longer accessible and can no be exited normally.
+      <command>lxc-stop</command> reboots, cleanly shuts down, or kills
+      all the processes inside the container.  By default, it will
+      request a clean shutdown of the container (by sending SIGPWR to
+      the container), wait 60 seconds for the container to exit, and
+      returns.  If the container fails to cleanly exit, then after 60
+      seconds the container will be sent the
+      <command>lxc.stopsignal</command> to force it to shut down.
     </para>
-
+	<para>
+	The <optional>-W</optional>, <optional>-r</optional>, <optional>-s</optional>
+	and <optional>-k</optional> options specify the action to perform.
+	<optional>-W</optional> indicates that after performing the specified
+	action, <command>lxc-stop</command> should immediately exit, while
+	<optional>-t TIMEOUT</optional> specifies the maximum amount of time
+	to wait for the container to complete the shutdown or reboot.
+	</para>
   </refsect1>
 
-  &commonoptions;
+  <refsect1>
+    <title>Options</title>
+    <variablelist>
+
+    <varlistentry>
+	<term>
+	  <option>-r,--reboot </option>
+	</term>
+	<listitem>
+	  <para>
+	    Request a reboot of the container.
+	  </para>
+	</listitem>
+	</varlistentry>
+
+    <varlistentry>
+	<term>
+	  <option>-s,--shutdown </option>
+	</term>
+	<listitem>
+	  <para>
+	    Only request a clean shutdown, do not kill the container tasks if the
+		clean shutdown fails.
+	  </para>
+	</listitem>
+	</varlistentry>
+
+    <varlistentry>
+	<term>
+	  <option>-k,--kill </option>
+	</term>
+	<listitem>
+	  <para>
+        Rather than requesting a clean shutdown of the container, explicitly
+        kill all tasks in the container.  This is the legacy
+        <command>lxc-stop</command> behavior.
+	  </para>
+	</listitem>
+	</varlistentry>
+
+    <varlistentry>
+	<term>
+	  <option>-W,--nowait </option>
+	</term>
+	<listitem>
+	  <para>
+	    Simply perform the requestion action (reboot, shutdown, or hard
+		kill) and exit.
+	  </para>
+	</listitem>
+	</varlistentry>
+
+    <varlistentry>
+	<term>
+	  <option>-t,--timeout <replaceable>TIMEOUT</replaceable></option>
+	</term>
+	<listitem>
+	  <para>
+	    Wait TIMEOUT seconds before hard-stopping the container of (in
+		the reboot case) returning failure.
+	  </para>
+	</listitem>
+	</varlistentry>
+
+  </variablelist>
+  </refsect1>
 
   <refsect1>
     <title>Diagnostic</title>
@@ -92,7 +173,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
         </listitem>
       </varlistentry>
 
-
     </variablelist>
 
   </refsect1>
diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index 4a19061..4baeb88 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -124,7 +124,6 @@ bin_SCRIPTS = \
 	lxc-checkconfig \
 	lxc-version \
 	lxc-create \
-	lxc-shutdown \
 	lxc-destroy
 
 EXTRA_DIST = \
diff --git a/src/lxc/arguments.h b/src/lxc/arguments.h
index 002a919..145474d 100644
--- a/src/lxc/arguments.h
+++ b/src/lxc/arguments.h
@@ -61,9 +61,13 @@ struct lxc_arguments {
 	int ttynum;
 	char escape;
 
-	/* for lxc-wait */
+	/* for lxc-wait and lxc-shutdown */
 	char *states;
 	long timeout;
+	int nowait;
+	int reboot;
+	int hardstop;
+	int shutdown;
 
 	/* close fds from parent? */
 	int close_all_fds;
diff --git a/src/lxc/lxc-shutdown.in b/src/lxc/lxc-shutdown.in
deleted file mode 100644
index c81e736..0000000
--- a/src/lxc/lxc-shutdown.in
+++ /dev/null
@@ -1,165 +0,0 @@
-#!/bin/sh
-
-# (C) Copyright Canonical 2011,2012
-
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# Lesser General Public License for more details.
-
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-set -e
-
-. @DATADIR@/lxc/lxc.functions
-
-usage() {
-    echo "usage: lxc-shutdown -n name [-w] [-r] [-P lxcpath]"
-    echo "  Cleanly shut down a container."
-    echo "  -w: wait for shutdown to complete."
-    echo "  -r: reboot (ignore -w)."
-    echo "  -t timeout: wait at most timeout seconds (implies -w), then kill"
-    echo "              the container."
-    echo "  -P lxcpath: path to the lxc container directories."
-}
-
-alarm() {
-    trap 'exit 0' TERM
-    pid=$1
-    timeout=$2
-    sleep $timeout
-    kill $pid
-}
-
-dolxcstop()
-{
-    echo "Calling lxc-stop on $lxc_name"
-    lxc-stop -n $lxc_name -P "$lxc_path"
-    exit 0
-}
-
-usage_err() {
-    [ -n "$1" ] && echo "$1" >&2
-    usage
-    exit 1
-}
-
-optarg_check() {
-    [ -n "$2" ] || usage_err "option '$1' requires an argument"
-}
-
-timeout="-1"
-
-reboot=0
-dowait=0
-
-while [ $# -gt 0 ]; do
-    opt="$1"
-    shift
-    case "$opt" in
-    -h|--help)
-        usage
-        exit 0
-        ;;
-    -n|--name)
-        optarg_check $opt "$1"
-        lxc_name=$1
-        shift
-        ;;
-    -w|--wait)
-        dowait=1
-        ;;
-    -r|--reboot)
-        reboot=1
-        ;;
-    -t|--timeout)
-        optarg_check $opt "$1"
-        timeout=$1
-        dowait=1
-        shift
-        ;;
-    -P|--lxcpath)
-        optarg_check $opt "$1"
-        lxc_path=$1
-        dowait=1
-        shift
-        ;;
-    --)
-        break;;
-    -?)
-        usage_err "unknown option '$opt'"
-        ;;
-    -*)
-        # split opts -abc into -a -b -c
-        set -- $(echo "${opt#-}" | sed 's/\(.\)/ -\1/g') "$@"
-        ;;
-    *)
-        usage_err "unknown option '$opt'"
-        exit 1
-        ;;
-    esac
-done
-
-if [ -z "$lxc_name" ]; then
-    echo "no container name specified"
-    usage
-    exit 1
-fi
-
-if [ ! -d "$lxc_path" ]; then
-    echo "$lxc_path: no such directory"
-    exit 1
-fi
-
-if [ "$(id -u)" != "0" ]; then
-   echo "This command has to be run as root"
-   exit 1
-fi
-
-which lxc-info > /dev/null 2>&1 || { echo "lxc-info not found."; exit 1; }
-which lxc-wait > /dev/null 2>&1 || { echo "lxc-wait not found."; exit 1; }
-
-pid=`lxc-info -n $lxc_name -P "$lxc_path" -p 2>/dev/null | awk '{ print $2 }'`
-if [ "$pid" = "-1" ]; then
-    echo "$lxc_name is not running"
-    exit 1
-fi
-
-if [ $reboot -eq 1 ]; then
-    kill -s INT $pid
-    exit 0
-else
-    kill -s PWR $pid
-fi
-
-if [ $dowait -eq 0 ]; then
-    exit 0
-fi
-
-if [ $timeout != "-1" ]; then
-    trap dolxcstop EXIT
-    alarm $$ $timeout 2>/dev/null &
-    alarmpid=$!
-fi
-
-while ! lxc-info -n $lxc_name -P "$lxc_path" --state-is STOPPED; do
-    sleep 1
-done
-
-if [ $timeout != "-1" ]; then
-    trap - EXIT
-    # include subprocesses; otherwise, we may have to wait until sleep completes
-    # if called from a non-interactive context
-    kill $alarmpid $(ps --no-headers --ppid $alarmpid -o pid) 2>/dev/null || :
-fi
-
-echo "Container $lxc_name has shut down"
-
-exit 0
diff --git a/src/lxc/lxc_stop.c b/src/lxc/lxc_stop.c
index d7c7283..1cbcfd4 100644
--- a/src/lxc/lxc_stop.c
+++ b/src/lxc/lxc_stop.c
@@ -28,10 +28,28 @@
 #include <lxc/lxc.h>
 #include <lxc/log.h>
 
+#include <lxc/lxccontainer.h>
 #include "arguments.h"
 #include "utils.h"
 
+static int my_parser(struct lxc_arguments* args, int c, char* arg)
+{
+	switch (c) {
+	case 'r': args->reboot = 1; break;
+	case 'W': args->nowait = 1; break;
+	case 't': args->timeout = atoi(arg); break;
+	case 'k': args->hardstop = 1; break;
+	case 's': args->shutdown = 1; break;
+	}
+	return 0;
+}
+
 static const struct option my_longopts[] = {
+	{"reboot", no_argument, 0, 'r'},
+	{"nowait", no_argument, 0, 'W'},
+	{"timeout", required_argument, 0, 't'},
+	{"kill", no_argument, 0, 'k'},
+	{"shutdown", no_argument, 0, 's'},
 	LXC_COMMON_OPTIONS
 };
 
@@ -43,14 +61,76 @@ static struct lxc_arguments my_args = {
 lxc-stop stops a container with the identifier NAME\n\
 \n\
 Options :\n\
-  -n, --name=NAME   NAME for name of the container\n",
+  -n, --name=NAME   NAME for name of the container\n\
+  -r, --reboot      reboot the container\n\
+  -W, --nowait      don't wait for shutdown or reboot to complete\n\
+  -t, --timeout=T   wait T seconds before hard-stopping\n\
+  -k, --kill        kill container rather than request clean shutdown\n\
+  -s, --shutdown    Only request clean shutdown, don't later force kill\n",
 	.options  = my_longopts,
-	.parser   = NULL,
+	.parser   = my_parser,
 	.checker  = NULL,
+	.timeout = 60,
 };
 
+/* returns -1 on failure, 0 on success */
+int do_reboot_and_check(struct lxc_arguments *a, struct lxc_container *c)
+{
+	int ret;
+	pid_t pid;
+	pid_t newpid;
+	int timeout = a->timeout;
+	
+	pid = c->init_pid(c);
+	if (pid == -1)
+		return -1;
+	if (!c->reboot(c))
+		return -1;
+	if (a->nowait)
+		return 0;
+	if (timeout <= 0)
+		goto out;
+
+	for (;;) {
+		/* can we use c-> wait for this, assuming it will
+		 * re-enter RUNNING?  For now just sleep */
+		int elapsed_time, curtime = 0;
+		struct timeval tv;
+
+		newpid = c->init_pid(c);
+		if (newpid != -1 && newpid != pid)
+			return 0;
+
+		ret = gettimeofday(&tv, NULL);
+		if (ret)
+			break;
+		curtime = tv.tv_sec;
+
+		sleep(1);
+		ret = gettimeofday(&tv, NULL);
+		if (ret)
+			break;
+		elapsed_time = tv.tv_sec - curtime;
+		if (timeout - elapsed_time <= 0)
+			break;
+		timeout -= elapsed_time;
+	}
+
+out:
+	newpid = c->init_pid(c);
+	if (newpid == -1 || newpid == pid) {
+		printf("Reboot did not complete before timeout\n");
+		return -1;
+	}
+	return 0;
+}
+
 int main(int argc, char *argv[])
 {
+	struct lxc_container *c;
+	bool s;
+	int ret = -1;
+
 	if (lxc_arguments_parse(&my_args, argc, argv))
 		return -1;
 
@@ -58,5 +138,36 @@ int main(int argc, char *argv[])
 			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
 		return -1;
 
-	return lxc_stop(my_args.name, my_args.lxcpath[0]);
+	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
+	if (!c) {
+		fprintf(stderr, "Error opening container\n");
+		goto out;
+	}
+
+	if (!c->is_running(c)) {
+		fprintf(stderr, "%s is not running\n", c->name);
+		ret = -2;
+		goto out;
+	}
+
+	if (my_args.hardstop) {
+		ret = c->stop(c) ? 0 : -1;
+		goto out;
+	}
+	if (my_args.reboot) {
+		ret = do_reboot_and_check(&my_args, c);
+		goto out;
+	}
+
+	s = c->shutdown(c, my_args.timeout);
+	if (!s) {
+		if (!my_args.shutdown)
+			ret = c->wait(c, "STOPPED", -1) ? 0 : -1;
+		else
+			ret = -1; // fail
+	}
+
+out:
+	lxc_container_put(c);
+	return ret;
 }
diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index 23db6f2..2126c89 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -689,6 +689,23 @@ out:
 	return bret;
 }
 
+static bool lxcapi_reboot(struct lxc_container *c)
+{
+	pid_t pid;
+
+	if (!c)
+		return false;
+	if (!c->is_running(c))
+		return false;
+	pid = c->init_pid(c);
+	if (pid <= 0)
+		return false;
+	if (kill(pid, SIGINT) < 0)
+		return false;
+	return true;
+
+}
+
 static bool lxcapi_shutdown(struct lxc_container *c, int timeout)
 {
 	bool retv;
@@ -1635,6 +1652,7 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
 	c->create = lxcapi_create;
 	c->createl = lxcapi_createl;
 	c->shutdown = lxcapi_shutdown;
+	c->reboot = lxcapi_reboot;
 	c->clear_config_item = lxcapi_clear_config_item;
 	c->get_config_item = lxcapi_get_config_item;
 	c->get_cgroup_item = lxcapi_get_cgroup_item;
diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h
index 67fbed4..c718d14 100644
--- a/src/lxc/lxccontainer.h
+++ b/src/lxc/lxccontainer.h
@@ -50,6 +50,8 @@ struct lxc_container {
 	bool (*save_config)(struct lxc_container *c, const char *alt_file);
 	bool (*create)(struct lxc_container *c, char *t, char *const argv[]);
 	bool (*createl)(struct lxc_container *c, char *t, ...);
+	/* send SIGINT to ask container to reboot */
+	bool (*reboot)(struct lxc_container *c);
 	/* send SIGPWR.  if timeout is not 0 or -1, do a hard stop after timeout seconds */
 	bool (*shutdown)(struct lxc_container *c, int timeout);
 	/* clear all network or capability items in the in-memory configuration */
-- 
1.8.1.2





More information about the lxc-devel mailing list