[lxc-devel] [PATCH 1/3] lxc-shutdown: switch from script to program using api.
Serge Hallyn
serge.hallyn at ubuntu.com
Fri May 17 20:56:27 UTC 2013
Quoting Stéphane Graber (stgraber at ubuntu.com):
> On 05/17/2013 03:15 PM, Serge Hallyn wrote:
> > implement c->reboot(c) in the api. Remove lxc-shutdown.in, the
> > bash script. Replace it with lxc_shutdown.c which uses the
> > API.
>
>
> Thanks for those changes. As we briefly discussed on IRC, I think we
> should rework a bit the set of binaries we have to stop containers, move
> to a single one that tries to "do the right thing" by default.
>
> So my suggestion is basically to:
> - Kill 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()
If noone objects to this change in behavior (as opposed to deprecation)
I'll go ahead and merge the two patches and implement this.
> * 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).
>
> We'd therefore end up with a single binary which does shutdown, stop and
> reboot, properly checks that the actions are carried out and supports
> timing out and fallback to kill.
>
> The 15s timeout would be over-ridable through -t, 15s is a guess as to
> how long users would be ready to wait for a container to die assuming
> some complex processes (database and similar) need enough time to sync
> their data and exit.
>
> Does that sound reasonable to everyone?
>
>
> > Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
> > ---
> > configure.ac | 1 -
> > src/lxc/Makefile.am | 3 +-
> > src/lxc/arguments.h | 4 +-
> > src/lxc/lxc-shutdown.in | 165 ------------------------------------------------
> > src/lxc/lxc_shutdown.c | 117 ++++++++++++++++++++++++++++++++++
> > src/lxc/lxccontainer.c | 18 ++++++
> > src/lxc/lxccontainer.h | 2 +
> > 7 files changed, 142 insertions(+), 168 deletions(-)
> > delete mode 100644 src/lxc/lxc-shutdown.in
> > create mode 100644 src/lxc/lxc_shutdown.c
> >
> > diff --git a/configure.ac b/configure.ac
> > index 414d71b..83d997b 100644
> > --- a/configure.ac
> > +++ b/configure.ac
> > @@ -383,7 +383,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/src/lxc/Makefile.am b/src/lxc/Makefile.am
> > index 4a19061..ce79904 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 = \
> > @@ -147,6 +146,7 @@ endif
> > bin_PROGRAMS = \
> > lxc-attach \
> > lxc-unshare \
> > + lxc-shutdown \
> > lxc-stop \
> > lxc-start \
> > lxc-clone \
> > @@ -191,6 +191,7 @@ lxc_restart_SOURCES = lxc_restart.c
> > lxc_clone_SOURCES = lxc_clone.c
> > lxc_start_SOURCES = lxc_start.c
> > lxc_stop_SOURCES = lxc_stop.c
> > +lxc_shutdown_SOURCES = lxc_shutdown.c
> > lxc_unfreeze_SOURCES = lxc_unfreeze.c
> > lxc_unshare_SOURCES = lxc_unshare.c
> > lxc_wait_SOURCES = lxc_wait.c
> > diff --git a/src/lxc/arguments.h b/src/lxc/arguments.h
> > index 002a919..a0f0fc9 100644
> > --- a/src/lxc/arguments.h
> > +++ b/src/lxc/arguments.h
> > @@ -61,9 +61,11 @@ struct lxc_arguments {
> > int ttynum;
> > char escape;
> >
> > - /* for lxc-wait */
> > + /* for lxc-wait and lxc-shutdown */
> > char *states;
> > long timeout;
> > + int wait;
> > + int reboot;
> >
> > /* 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_shutdown.c b/src/lxc/lxc_shutdown.c
> > new file mode 100644
> > index 0000000..c9b5083
> > --- /dev/null
> > +++ b/src/lxc/lxc_shutdown.c
> > @@ -0,0 +1,117 @@
> > +/*
> > + *
> > + * Copyright © 2013 Serge Hallyn <serge.hallyn at ubuntu.com>.
> > + * Copyright © 2013 Canonical Ltd.
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License version 2, as
> > + * published by the Free Software Foundation.
> > + *
> > + * This program 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 General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public License along
> > + * with this program; if not, write to the Free Software Foundation, Inc.,
> > + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> > + */
> > +
> > +#include "../lxc/lxccontainer.h"
> > +
> > +/*
> > + * usage:
> > + lxc-shutdown -h
> > + usage: lxc-shutdown -n name [-w] [-r] [-P lxcpath]
> > + Cleanly shut down a container.
> > + -w: wait for shutdown to complete.
> > + -r: reboot (ignore -w).
> > + -t timeout: wait at most timeout seconds (implies -w), then kill
> > + the container.
> > + -P lxcpath: path to the lxc container directories.
> > +*/
> > +
> > +#include <stdio.h>
> > +#include <libgen.h>
> > +#include <unistd.h>
> > +#include <sys/types.h>
> > +
> > +#include <lxc/lxc.h>
> > +#include <lxc/log.h>
> > +
> > +#include "arguments.h"
> > +#include "utils.h"
> > +
> > +lxc_log_define(lxc_shutdown, lxc);
> > +
> > +static int my_parser(struct lxc_arguments* args, int c, char* arg)
> > +{
> > + switch (c) {
> > + case 'r': args->reboot = 1; break;
> > + case 'w': args->wait = 1; break;
> > + case 't': args->timeout = atoi(arg); break;
> > + }
> > + return 0;
> > +}
> > +
> > +static const struct option my_longopts[] = {
> > + {"reboot", no_argument, 0, 'r'},
> > + {"wait", no_argument, 0, 'w'},
> > + {"timeout", required_argument, 0, 't'},
> > + LXC_COMMON_OPTIONS
> > +};
> > +
> > +static struct lxc_arguments my_args = {
> > + .progname = "lxc-shutdown",
> > + .help = "\
> > +--name=NAME [-w] [-r] [-t timeout] [-P lxcpath]\n\
> > +\n\
> > +lxc-stop stops a container with the identifier NAME\n\
> > +\n\
> > +Options :\n\
> > + -n, --name=NAME NAME for name of the container\n\
> > + -t, --timeout=T wait T seconds before hardkilling\n\
> > + -w, --wait wait for the container to shut down\n\
> > + -r, --reboot reboot the container (ignore wait)\n",
> > + .options = my_longopts,
> > + .parser = my_parser,
> > + .checker = NULL,
> > +};
> > +
> > +int main(int argc, char *argv[])
> > +{
> > + struct lxc_container *c;
> > +
> > + /* this is a short term test. We'll probably want to check for
> > + * write access to lxcpath instead */
> > + if (geteuid()) {
> > + fprintf(stderr, "%s must be run as root\n", argv[0]);
> > + exit(1);
> > + }
> > +
> > + if (lxc_arguments_parse(&my_args, argc, argv))
> > + exit(1);
> > +
> > + if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
> > + my_args.progname, my_args.quiet, my_args.lxcpath[0]))
> > + exit(1);
> > +
> > + c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
> > + if (!c) {
> > + fprintf(stderr, "System error loading container\n");
> > + exit(1);
> > + }
> > +
> > + if (!c->is_running(c)) {
> > + fprintf(stderr, "%s is not running\n", my_args.name);
> > + exit(1);
> > + }
> > +
> > + if (my_args.reboot)
> > + exit(c->reboot(c) ? 0 : 1);
> > +
> > + if (!c->shutdown(c, my_args.timeout))
> > + exit(c->wait(c, "STOPPED", -1) ? 0 : 1);
> > +
> > + exit(0);
> > +}
> > 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 */
> >
>
>
> --
> Stéphane Graber
> Ubuntu developer
> http://www.ubuntu.com
>
More information about the lxc-devel
mailing list