Commit a6adab20 by Stéphane Graber

Add lxc-autostart

This introduces a new lxc-autostart binary (and associated manpage) which will let you start/shutdown/kill/restart any container that's marked as lxc.start.auto=1. It respects the lxc.start.delay value, sorts by lxc.start.order and filters by lxc.group. By default it'll affect all containers that DO NOT have lxc.group set. If -g is specified, ONLY containers in those group will be affected. To have a command applied to all containers, the -a argument can be used. A -L flag is also offered for distributions wishing to start the containers themselves while still using LXC's calculated order and wait delays. Instead of performing the action, it'll print the container name and (if relevant for the action) the wait time. Signed-off-by: 's avatarStéphane Graber <stgraber@ubuntu.com> Acked-by: 's avatarSerge E. Hallyn <serge.hallyn@ubuntu.com>
parent cfd149a6
...@@ -43,6 +43,7 @@ templates/lxc-ubuntu-cloud ...@@ -43,6 +43,7 @@ templates/lxc-ubuntu-cloud
src/lxc/lxc-attach src/lxc/lxc-attach
src/lxc/lxc-autostart
src/lxc/lxc-cgroup src/lxc/lxc-cgroup
src/lxc/lxc-checkconfig src/lxc/lxc-checkconfig
src/lxc/lxc-checkpoint src/lxc/lxc-checkpoint
......
...@@ -474,6 +474,7 @@ AC_CONFIG_FILES([ ...@@ -474,6 +474,7 @@ AC_CONFIG_FILES([
doc/api/Makefile doc/api/Makefile
doc/legacy/lxc-ls.sgml doc/legacy/lxc-ls.sgml
doc/lxc-attach.sgml doc/lxc-attach.sgml
doc/lxc-autostart.sgml
doc/lxc-cgroup.sgml doc/lxc-cgroup.sgml
doc/lxc-checkconfig.sgml doc/lxc-checkconfig.sgml
doc/lxc-checkpoint.sgml doc/lxc-checkpoint.sgml
......
...@@ -15,6 +15,7 @@ EXTRA_DIST = \ ...@@ -15,6 +15,7 @@ EXTRA_DIST = \
if ENABLE_DOCBOOK if ENABLE_DOCBOOK
man_MANS = \ man_MANS = \
lxc-attach.1 \ lxc-attach.1 \
lxc-autostart.1 \
lxc-cgroup.1 \ lxc-cgroup.1 \
lxc-checkconfig.1 \ lxc-checkconfig.1 \
lxc-checkpoint.1 \ lxc-checkpoint.1 \
......
<!--
lxc-autostart
(C) Copyright 2013 Canonical Ltd.
Authors:
Stéphane Graber <stgraber@ubuntu.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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-autostart</refentrytitle>
<manvolnum>1</manvolnum>
</refmeta>
<refnamediv>
<refname>lxc-autostart</refname>
<refpurpose>
start/stop/kill auto-started containers
</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>lxc-autostart</command>
<arg choice="opt">-k</arg>
<arg choice="opt">-L</arg>
<arg choice="opt">-r</arg>
<arg choice="opt">-s</arg>
<arg choice="opt">-a</arg>
<arg choice="opt">-g <replaceable>groups</replaceable></arg>
<arg choice="opt">-t <replaceable>timeout</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
<command>lxc-autostart</command> processes containers
with lxc.start.auto set. It lets the user start, shutdown,
kill, restart containers in the right order, waiting the
right time. Supports filtering by lxc.group or just run
against all defined containers. It can also be used by
external tools in list mode where no action will be performed
and the list of affected containers (and if relevant, delays)
will be shown.
</para>
<para>
The <optional>-r</optional>, <optional>-s</optional>
and <optional>-k</optional> options specify the action to perform.
If none is specified, then the containers will be started.
<optional>-a</optional> and <optional>-g</optional> are used to
specify which containers will be affected. By default only
containers without a lxc.group set will be affected.
<optional>-t TIMEOUT</optional> specifies the maximum amount
of time to wait for the container to complete the shutdown
or reboot.
</para>
</refsect1>
<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.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-L,--list </option>
</term>
<listitem>
<para>
Rather than performing the action, just print
the container name.
</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>
&seealso;
<refsect1>
<title>Author</title>
<para>Stéphane Graber <email>stgraber@ubuntu.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:
-->
...@@ -170,6 +170,7 @@ endif ...@@ -170,6 +170,7 @@ endif
bin_PROGRAMS = \ bin_PROGRAMS = \
lxc-attach \ lxc-attach \
lxc-autostart \
lxc-unshare \ lxc-unshare \
lxc-stop \ lxc-stop \
lxc-start \ lxc-start \
...@@ -203,6 +204,7 @@ endif ...@@ -203,6 +204,7 @@ endif
LDADD=liblxc.so @CAP_LIBS@ @APPARMOR_LIBS@ @SECCOMP_LIBS@ LDADD=liblxc.so @CAP_LIBS@ @APPARMOR_LIBS@ @SECCOMP_LIBS@
lxc_attach_SOURCES = lxc_attach.c lxc_attach_SOURCES = lxc_attach.c
lxc_autostart_SOURCES = lxc_autostart.c
lxc_cgroup_SOURCES = lxc_cgroup.c lxc_cgroup_SOURCES = lxc_cgroup.c
lxc_checkpoint_SOURCES = lxc_checkpoint.c lxc_checkpoint_SOURCES = lxc_checkpoint.c
lxc_config_SOURCES = lxc_config.c lxc_config_SOURCES = lxc_config.c
......
...@@ -229,7 +229,7 @@ extern int lxc_arguments_parse(struct lxc_arguments *args, ...@@ -229,7 +229,7 @@ extern int lxc_arguments_parse(struct lxc_arguments *args,
/* Check the command options */ /* Check the command options */
if (!args->name) { if (!args->name && strcmp(args->progname, "lxc-autostart") != 0) {
lxc_error(args, "missing container name, use --name option"); lxc_error(args, "missing container name, use --name option");
return -1; return -1;
} }
......
...@@ -89,6 +89,11 @@ struct lxc_arguments { ...@@ -89,6 +89,11 @@ struct lxc_arguments {
char *lvname, *vgname, *thinpool; char *lvname, *vgname, *thinpool;
char *zfsroot, *lowerdir, *dir; char *zfsroot, *lowerdir, *dir;
/* auto-start */
int all;
int list;
char *groups;
/* remaining arguments */ /* remaining arguments */
char *const *argv; char *const *argv;
int argc; int argc;
......
/* lxc_autostart
*
* Copyright © 2013 Stéphane Graber <stgraber@ubuntu.com>
* Copyright © 2013 Canonical Ltd.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <string.h>
#include <unistd.h>
#include <lxc/lxccontainer.h>
#include "arguments.h"
#include "list.h"
#include "log.h"
static int my_parser(struct lxc_arguments* args, int c, char* arg)
{
switch (c) {
case 'k': args->hardstop = 1; break;
case 'L': args->list = 1; break;
case 'r': args->reboot = 1; break;
case 's': args->shutdown = 1; break;
case 'a': args->all = 1; break;
case 'g': args->groups = arg; break;
case 't': args->timeout = atoi(arg); break;
}
return 0;
}
static const struct option my_longopts[] = {
{"kill", no_argument, 0, 'k'},
{"list", no_argument, 0, 'L'},
{"reboot", no_argument, 0, 'r'},
{"shutdown", no_argument, 0, 's'},
{"all", no_argument, 0, 'a'},
{"groups", required_argument, 0, 'g'},
{"timeout", required_argument, 0, 't'},
{"help", no_argument, 0, 'h'},
LXC_COMMON_OPTIONS
};
static struct lxc_arguments my_args = {
.progname = "lxc-autostart",
.help = "\
\n\
lxc-autostart managed auto-started containers\n\
\n\
Options:\n\
-k, --kill kill the containers instead of starting them\n\
-L, --list list all affected containers and wait delay\n\
-r, --reboot reboot the containers instead of starting them\n\
-s, --shutdown shutdown the containers instead of starting them\n\
\n\
-a, --all list all auto-started containers (ignore groups)\n\
-g, --groups list of groups (comma separated) to select\n\
-t, --timeout=T wait T seconds before hard-stopping\n",
.options = my_longopts,
.parser = my_parser,
.checker = NULL,
.timeout = 30,
};
int lists_contain_common_entry(struct lxc_list *p1, struct lxc_list *p2) {
struct lxc_list *it1;
struct lxc_list *it2;
if (!p1 && !p2)
return 1;
if (!p1)
return 0;
if (!p2)
return 0;
lxc_list_for_each(it1, p1) {
lxc_list_for_each(it2, p2) {
if (strcmp(it1->elem, it2->elem) == 0)
return 1;
}
}
return 0;
}
struct lxc_list *get_list(char *input, char *delimiter) {
char *workstr = NULL;
char *workptr = NULL;
char *sptr = NULL;
char *token = NULL;
struct lxc_list *worklist;
struct lxc_list *workstr_list;
workstr_list = malloc(sizeof(*workstr_list));
lxc_list_init(workstr_list);
workstr = strdup(input);
if (!workstr)
return NULL;
for (workptr = workstr;;workptr = NULL) {
token = strtok_r(workptr, delimiter, &sptr);
if (!token) {
break;
}
worklist = malloc(sizeof(*worklist));
if (!worklist)
break;
worklist->elem = strdup(token);
if (!worklist->elem) {
free(worklist);
break;
}
lxc_list_add_tail(workstr_list, worklist);
}
free(workstr);
return workstr_list;
}
struct lxc_list *get_config_list(struct lxc_container *c, char *key) {
int len = 0;
char* value = NULL;
struct lxc_list *config_list = NULL;
len = c->get_config_item(c, key, NULL, 0);
if (len < 0)
return NULL;
value = (char*) malloc(sizeof(char)*len + 1);
if (value == NULL)
return NULL;
if (c->get_config_item(c, key, value, len + 1) != len) {
free(value);
return NULL;
}
if (strlen(value) == 0) {
free(value);
return NULL;
}
config_list = get_list(value, "\n");
free(value);
return config_list;
}
int get_config_integer(struct lxc_container *c, char *key) {
int len = 0;
int ret = 0;
char* value = NULL;
len = c->get_config_item(c, key, NULL, 0);
if (len < 0)
return 0;
value = (char*) malloc(sizeof(char)*len + 1);
if (value == NULL)
return 0;
if (c->get_config_item(c, key, value, len + 1) != len) {
free(value);
return 0;
}
ret = atoi(value);
free(value);
return ret;
}
static int cmporder(const void *p1, const void *p2) {
struct lxc_container *c1 = *(struct lxc_container **)p1;
struct lxc_container *c2 = *(struct lxc_container **)p2;
int c1_order = get_config_integer(c1, "lxc.start.order");
int c2_order = get_config_integer(c2, "lxc.start.order");
if (c1_order == c2_order)
return strcmp(c1->name, c2->name);
else
return (c1_order - c2_order) * -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;
char *const default_start_args[] = {
"/sbin/init",
'\0',
};
if (lxc_arguments_parse(&my_args, argc, argv))
return 1;
count = list_defined_containers(NULL, NULL, &containers);
if (count < 0)
return 1;
qsort(&containers[0], count, sizeof(struct lxc_container *), cmporder);
if (my_args.groups && !my_args.all)
cmd_groups_list = get_list((char*)my_args.groups, ",");
for (i = 0; i < count; i++) {
struct lxc_container *c = containers[i];
if (!c->may_control(c)) {
lxc_container_put(c);
continue;
}
if (get_config_integer(c, "lxc.start.auto") != 1) {
lxc_container_put(c);
continue;
}
if (!my_args.all) {
/* Filter by group */
c_groups_list = get_config_list(c, "lxc.group");
ret = lists_contain_common_entry(cmd_groups_list, c_groups_list);
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);
}
if (ret == 0) {
lxc_container_put(c);
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))
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.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"));
}
}
}
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);
}
free(cmd_groups_list);
}
free(containers);
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment