[Lxc-users] container shutdown
Serge Hallyn
serge.hallyn at canonical.com
Sun Mar 18 23:00:23 UTC 2012
Hi,
Thanks to Jäkel's and Fajar's great ideas, we can now cleanly shut down
a container by sending it SIGPWR. I'm attaching two ways to do that.
In-line is a patch which modifies lxc-stop to take optional -s and -t
args - -s for shutdown (meaning send SIGPWR), and -t for a timeout,
after sending SIGPWR, to hard-kill the container.
Attached is a lxc-shutdown script (as an alternative) so lxc-stop can
continue to work as it has.
Both are in the bzr tree at
lp:~serge-hallyn/ubuntu/precise/lxc/lxc-shutdown, which builds and gives
you both.
What do we prefer?
thanks,
-serge
Signed-off-by: Serge Hallyn <serge.hallyn at canonical.com>
---
doc/lxc-stop.sgml.in | 10 ++++++++++
src/lxc/arguments.h | 4 ++++
src/lxc/commands.c | 8 ++++----
src/lxc/lxc.h | 5 ++++-
src/lxc/lxc_stop.c | 22 +++++++++++++++++++---
src/lxc/stop.c | 27 +++++++++++++++++++++++++--
6 files changed, 66 insertions(+), 10 deletions(-)
Index: lxc/doc/lxc-stop.sgml.in
===================================================================
--- lxc.orig/doc/lxc-stop.sgml.in 2012-03-18 16:33:06.254906000 -0500
+++ lxc/doc/lxc-stop.sgml.in 2012-03-18 16:34:11.970538920 -0500
@@ -49,6 +49,7 @@
<refsynopsisdiv>
<cmdsynopsis>
<command>lxc-stop <replaceable>-n name</replaceable>
+ <optional>-s</optional> <optional>-t timeout</optional>
</command>
</cmdsynopsis>
</refsynopsisdiv>
@@ -62,6 +63,15 @@
longer accessible and can no be exited normally.
</para>
+ <para>
+ If <optional>-s</optional> (<optional>--shutdown</optional>) is
+ specified, then ask the container to shut down cleanly by sending
+ a <emphasis>SIGPWR</emphasis> signal. If <optional>-t timeout</optional>
+ is also given, then <emphasis>timeout</emphasis> seconds after sending
+ SIGPWR, if the container is still up, proceed to kill the container.
+ Note that <optional>-t timeout</optional> implies <optional>-s</optional>.
+ </para>
+
</refsect1>
&commonoptions;
Index: lxc/src/lxc/arguments.h
===================================================================
--- lxc.orig/src/lxc/arguments.h 2012-03-18 16:33:06.254906000 -0500
+++ lxc/src/lxc/arguments.h 2012-03-18 16:34:19.442575978 -0500
@@ -46,6 +46,10 @@
const char *rcfile;
const char *console;
+ /* for lxc-stop */
+ int timeout;
+ int shutdown;
+
/* for lxc-checkpoint/restart */
const char *statefile;
int statefd;
Index: lxc/src/lxc/commands.c
===================================================================
--- lxc.orig/src/lxc/commands.c 2012-03-18 16:33:06.254906000 -0500
+++ lxc/src/lxc/commands.c 2012-03-18 16:34:26.862612782 -0500
@@ -162,10 +162,10 @@
typedef int (*callback)(int, struct lxc_request *, struct lxc_handler *);
callback cb[LXC_COMMAND_MAX] = {
- [LXC_COMMAND_TTY] = lxc_console_callback,
- [LXC_COMMAND_STOP] = lxc_stop_callback,
- [LXC_COMMAND_STATE] = lxc_state_callback,
- [LXC_COMMAND_PID] = lxc_pid_callback,
+ [LXC_COMMAND_TTY] = lxc_console_callback,
+ [LXC_COMMAND_STOP] = lxc_stop_callback,
+ [LXC_COMMAND_STATE] = lxc_state_callback,
+ [LXC_COMMAND_PID] = lxc_pid_callback,
};
if (request->type < 0 || request->type >= LXC_COMMAND_MAX)
Index: lxc/src/lxc/lxc_stop.c
===================================================================
--- lxc.orig/src/lxc/lxc_stop.c 2012-03-18 16:33:06.254906000 -0500
+++ lxc/src/lxc/lxc_stop.c 2012-03-18 17:24:47.137589512 -0500
@@ -30,7 +30,18 @@
#include "arguments.h"
+static int my_parser(struct lxc_arguments* args, int c, char* arg)
+{
+ switch (c) {
+ case 's': args->shutdown = 1; break;
+ case 't': args->timeout = arg; args->shutdown = 1; break;
+ }
+ return 0;
+}
+
static const struct option my_longopts[] = {
+ {"shutdown", no_argument, 0, 's'},
+ {"timeout", required_argument, 0, 't'},
LXC_COMMON_OPTIONS
};
@@ -42,10 +53,15 @@
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\
+ -s, --shutdown Ask container to shut down cleanly\n\
+ -t, --timeout=t Imply -s and hard-kill container after t seconds\n\
+ (default is -1, no timeout)\n",
.options = my_longopts,
- .parser = NULL,
+ .parser = my_parser,
.checker = NULL,
+ .timeout = -1,
+ .shutdown = 0,
};
int main(int argc, char *argv[])
@@ -57,5 +73,5 @@
my_args.progname, my_args.quiet))
return -1;
- return lxc_stop(my_args.name);
+ return lxc_stop(my_args.name, my_args.shutdown, my_args.timeout);
}
Index: lxc/src/lxc/stop.c
===================================================================
--- lxc.orig/src/lxc/stop.c 2012-03-18 16:33:06.254906000 -0500
+++ lxc/src/lxc/stop.c 2012-03-18 17:53:49.638230102 -0500
@@ -40,7 +40,7 @@
lxc_log_define(lxc_stop, lxc);
-int lxc_stop(const char *name)
+int lxc_stop(const char *name, int shutdown, int timeout)
{
struct lxc_command command = {
.request = { .type = LXC_COMMAND_STOP },
@@ -48,9 +48,30 @@
int ret, stopped = 0;
+ if (shutdown) {
+ int pid = get_init_pid(name);
+ if (pid == -1) {
+ INFO("'%s' is already stopped", name);
+ return 0;
+ }
+ ret = kill(pid, SIGPWR);
+ if (ret < 0) {
+ ERROR("failed to send SIGPWR");
+ return -1;
+ }
+ if (timeout < 0)
+ goto out;
+ while (timeout-- > 0) {
+ lxc_state_t state = lxc_getstate(name);
+ if (state == STOPPED)
+ goto out;
+ sleep(1);
+ }
+ }
ret = lxc_command(name, &command,&stopped);
if (ret < 0 && stopped) {
- INFO("'%s' is already stopped", name);
+ if (!shutdown)
+ INFO("'%s' is already stopped", name);
return 0;
}
@@ -68,6 +89,8 @@
return -1;
}
+out:
+
INFO("'%s' has stopped", name);
return 0;
Index: lxc/src/lxc/lxc.h
===================================================================
--- lxc.orig/src/lxc/lxc.h 2012-03-16 21:39:54.517075000 -0500
+++ lxc/src/lxc/lxc.h 2012-03-18 16:42:23.336975492 -0500
@@ -52,9 +52,12 @@
* Stop the container previously started with lxc_start, all
* the processes running inside this container will be killed.
* @name : the name of the container
+ * @shutdown : 1 if SIGPWR should be sent, 0 if SIGKILL
+ * @timeout : if not -1, wait this many seconds after sending
+ * SIGPWR before sending SIGKILL.
* Returns 0 on success, < 0 otherwise
*/
-extern int lxc_stop(const char *name);
+extern int lxc_stop(const char *name, int shutdown, int timeout);
/*
* Open the monitoring mechanism for a specific container
-------------- next part --------------
#!/bin/bash
# (C) Copyright Canonical 2011,2012
set -e
usage() {
echo "usage: lxc-shutdown -n name [-t timeout]"
echo " Cleanly shut down a container."
echo " If timeout is not specified, exit after sending SIGPWR"
echo " Otherwise, wait timeout seconds before calling lxc-stop"
echo " to hard-kill the container"
}
alarm() {
pid=$1
timeout=$2
sleep $timeout
kill $pid
}
shortoptions='hn:t:'
longoptions='help,name:,timeout:'
getopt=$(getopt -o $shortoptions --longoptions $longoptions -- "$@")
if [ $? != 0 ]; then
usage
exit 1;
fi
eval set -- "$getopt"
timeout="-1"
while true; do
case "$1" in
-h|--help)
help
exit 1
;;
-n|--name)
shift
lxc_name=$1
shift
;;
-t|--timeout)
shift
timeout=$1
shift
;;
--)
shift
break;;
*)
echo $1
usage
exit 1
;;
esac
done
if [ -z "$lxc_name" ]; then
echo "no container name specified"
usage
exit 1
fi
if [ "$(id -u)" != "0" ]; then
echo "This command has to be run as root"
exit 1
fi
type lxc-info > /dev/null || { echo "lxc-info not found."; exit 1; }
pid=`lxc-info -n $lxc_name -p 2>/dev/null | awk '{ print $2 }'`
if [ "$pid" = "-1" ]; then
echo "$lxc_name is not running"
exit 1
fi
kill -PWR $pid
if [ "$timeout" = "-1" ]; then
exit 0
fi
echo "Waiting $timeout seconds for container to finish shutting down..."
dolxcstop()
{
echo "Calling lxc-stop on $lxc_name"
lxc-stop -n $lxc_name
exit 0
}
trap dolxcstop EXIT
alarm $$ $timeout &
alarmpid=$!
lxc-wait -n $lxc_name -s STOPPED
echo "container has shut down"
kill $alarmpid
exit 0
More information about the lxc-users
mailing list