[ 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.hal...@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.hal...@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.hal...@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 ------------------------------------------------------------------------------ AlienVault Unified Security Management (USM) platform delivers complete security visibility with the essential security capabilities. Easily and efficiently configure, manage, and operate all of your security controls from a single console and one unified framework. Download a free trial. http://p.sf.net/sfu/alienvault_d2d _______________________________________________ Lxc-devel mailing list Lxc-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/lxc-devel