Commit f69d74e3 by Serge Hallyn

Merge pull request #621 from brauner/arguments

Refactor lxc-snapshot, lxc-clone, make LXC_CLONE_KEEPNAME work and add option to destroy container with all snapshots to lxc-destroy
parents 3cd05817 7909bb03
......@@ -94,6 +94,22 @@ struct lxc_arguments {
int list;
char *groups;
/* lxc-snapshot and lxc-clone */
enum task {
DESTROY,
LIST,
RESTORE,
SNAP,
RENAME,
} task;
int print_comments;
char *commentfile;
char *newname;
char *newpath;
char *snapname;
int keepname;
int keepmac;
/* remaining arguments */
char *const *argv;
int argc;
......
......@@ -146,7 +146,7 @@ static struct lxc_arguments my_args = {
Execute the specified COMMAND - enter the container NAME\n\
\n\
Options :\n\
-n, --name=NAME NAME for name of the container\n\
-n, --name=NAME NAME of the container\n\
-e, --elevated-privileges=PRIVILEGES\n\
Use elevated privileges instead of those of the\n\
container. If you don't specify privileges to be\n\
......
......@@ -105,7 +105,7 @@ lxc-checkpoint checkpoints and restores a container\n\
its running state at a later time.\n\
\n\
Options :\n\
-n, --name=NAME NAME for name of the container\n\
-n, --name=NAME NAME of the container\n\
-r, --restore Restore container\n\
-D, --checkpoint-dir=DIR directory to save the checkpoint in\n\
-v, --verbose Enable verbose criu logs\n\
......
......@@ -78,7 +78,7 @@ static struct lxc_arguments my_args = {
lxc-console logs on the container with the identifier NAME\n\
\n\
Options :\n\
-n, --name=NAME NAME for name of the container\n\
-n, --name=NAME NAME of the container\n\
-t, --tty=NUMBER console tty number\n\
-e, --escape=PREFIX prefix for escape command\n",
.options = my_longopts,
......
......@@ -61,7 +61,7 @@ static uint64_t get_fssize(char *s)
else if (*end == 't' || *end == 'T')
ret *= 1024ULL * 1024ULL * 1024ULL * 1024ULL;
else
{
{
fprintf(stderr, "Invalid blockdev unit size '%c' in '%s', using default size\n", *end, s);
return 0;
}
......@@ -131,7 +131,7 @@ static struct lxc_arguments my_args = {
lxc-create creates a container\n\
\n\
Options :\n\
-n, --name=NAME NAME for name of the container\n\
-n, --name=NAME NAME of the container\n\
-f, --config=file Initial configuration file\n\
-t, --template=t Template to use to setup container\n\
-B, --bdev=BDEV Backing store type to use\n\
......
......@@ -31,16 +31,11 @@
lxc_log_define(lxc_destroy_ui, lxc);
static int my_parser(struct lxc_arguments* args, int c, char* arg)
{
switch (c) {
case 'f': args->force = 1; break;
}
return 0;
}
static int my_parser(struct lxc_arguments* args, int c, char* arg);
static const struct option my_longopts[] = {
{"force", no_argument, 0, 'f'},
{"snapshots", no_argument, 0, 's'},
LXC_COMMON_OPTIONS
};
......@@ -52,61 +47,104 @@ static struct lxc_arguments my_args = {
lxc-destroy destroys a container with the identifier NAME\n\
\n\
Options :\n\
-n, --name=NAME NAME for name of the container\n\
-n, --name=NAME NAME of the container\n\
-s, --snapshots destroy including all snapshots\n\
-f, --force wait for the container to shut down\n",
.options = my_longopts,
.parser = my_parser,
.checker = NULL,
.task = DESTROY,
};
static int do_destroy(struct lxc_container *c);
static int do_destroy_with_snapshots(struct lxc_container *c);
int main(int argc, char *argv[])
{
struct lxc_container *c;
int ret;
if (lxc_arguments_parse(&my_args, argc, argv))
exit(1);
exit(EXIT_FAILURE);
if (!my_args.log_file)
my_args.log_file = "none";
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);
exit(EXIT_FAILURE);
lxc_log_options_no_override();
c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
if (!c) {
fprintf(stderr, "System error loading container\n");
exit(1);
exit(EXIT_FAILURE);
}
if (!c->may_control(c)) {
fprintf(stderr, "Insufficent privileges to control %s\n", my_args.name);
lxc_container_put(c);
exit(1);
exit(EXIT_FAILURE);
}
if (!c->is_defined(c)) {
fprintf(stderr, "Container is not defined\n");
lxc_container_put(c);
exit(1);
exit(EXIT_FAILURE);
}
if (c->is_running(c)) {
if (!my_args.force) {
fprintf(stderr, "%s is running\n", my_args.name);
lxc_container_put(c);
exit(1);
exit(EXIT_FAILURE);
}
c->stop(c);
}
if (my_args.task == SNAP) {
ret = do_destroy_with_snapshots(c);
} else {
ret = do_destroy(c);
}
lxc_container_put(c);
if (ret == 0)
exit(EXIT_SUCCESS);
exit(EXIT_FAILURE);
}
static int my_parser(struct lxc_arguments *args, int c, char *arg)
{
switch (c) {
case 'f': args->force = 1; break;
case 's': args->task = SNAP; break;
}
return 0;
}
static int do_destroy(struct lxc_container *c)
{
if (!c->destroy(c)) {
fprintf(stderr, "Destroying %s failed\n", my_args.name);
lxc_container_put(c);
exit(1);
return -1;
}
lxc_container_put(c);
exit(0);
printf("Destroyed container %s\n", my_args.name);
return 0;
}
static int do_destroy_with_snapshots(struct lxc_container *c)
{
if (!c->destroy_with_snapshots(c)) {
fprintf(stderr, "Destroying %s failed\n", my_args.name);
return -1;
}
printf("Destroyed container including snapshots %s\n", my_args.name);
return 0;
}
......@@ -53,7 +53,7 @@ static struct lxc_arguments my_args = {
lxc-device attach or detach DEV to or from container.\n\
\n\
Options :\n\
-n, --name=NAME NAME for name of the container",
-n, --name=NAME NAME of the container",
.options = my_longopts,
.parser = NULL,
.checker = NULL,
......
......@@ -79,7 +79,7 @@ lxc-execute creates a container with the identifier NAME\n\
and execs COMMAND into this container.\n\
\n\
Options :\n\
-n, --name=NAME NAME for name of the container\n\
-n, --name=NAME NAME of the container\n\
-f, --rcfile=FILE Load configuration file FILE\n\
-s, --define KEY=VAL Assign VAL to configuration variable KEY\n",
.options = my_longopts,
......
......@@ -47,7 +47,7 @@ static struct lxc_arguments my_args = {
lxc-freeze freezes a container with the identifier NAME\n\
\n\
Options :\n\
-n, --name=NAME NAME for name of the container",
-n, --name=NAME NAME of the container",
.options = my_longopts,
.parser = NULL,
.checker = NULL,
......
......@@ -87,7 +87,7 @@ static struct lxc_arguments my_args = {
lxc-info display some information about a container with the identifier NAME\n\
\n\
Options :\n\
-n, --name=NAME NAME for name of the container\n\
-n, --name=NAME NAME of the container\n\
-c, --config=KEY show configuration variable KEY from running container\n\
-i, --ips shows the IP addresses\n\
-p, --pid shows the process id of the init container\n\
......
......@@ -61,7 +61,7 @@ static void interrupt_handler(int sig)
static void usage(void) {
fprintf(stderr, "Usage: lxc-init [OPTION]...\n\n"
"Common options :\n"
" -n, --name=NAME NAME for name of the container\n"
" -n, --name=NAME NAME of the container\n"
" -l, --logpriority=LEVEL Set log priority to LEVEL\n"
" -q, --quiet Don't produce any output\n"
" -P, --lxcpath=PATH Use specified container path\n"
......
......@@ -61,7 +61,7 @@ static struct lxc_arguments my_args = {
lxc-monitor monitors the state of the NAME container\n\
\n\
Options :\n\
-n, --name=NAME NAME for name of the container\n\
-n, --name=NAME NAME of the container\n\
NAME may be a regular expression\n\
-Q, --quit tell lxc-monitord to quit\n",
.name = ".*",
......
......@@ -16,8 +16,8 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include "confile.h"
#include <stdio.h>
#include <libgen.h>
#include <unistd.h>
......@@ -35,18 +35,149 @@
lxc_log_define(lxc_snapshot_ui, lxc);
static char *newname;
static char *snapshot;
static int my_parser(struct lxc_arguments *args, int c, char *arg);
#define DO_SNAP 0
#define DO_LIST 1
#define DO_RESTORE 2
#define DO_DESTROY 3
static int action;
static int print_comments;
static char *commentfile;
static const struct option my_longopts[] = {
{"list", no_argument, 0, 'L'},
{"restore", required_argument, 0, 'r'},
{"newname", required_argument, 0, 'N'},
{"destroy", required_argument, 0, 'd'},
{"comment", required_argument, 0, 'c'},
{"showcomments", no_argument, 0, 'C'},
LXC_COMMON_OPTIONS
};
static struct lxc_arguments my_args = {
.progname = "lxc-snapshot",
.help = "\
--name=NAME [-P lxcpath] [-L [-C]] [-c commentfile] [-r snapname [-N newname]]\n\
\n\
lxc-snapshot snapshots a container\n\
\n\
Options :\n\
-n, --name=NAME NAME of the container\n\
-L, --list list all snapshots\n\
-r, --restore=NAME restore snapshot NAME, e.g. 'snap0'\n\
-N, --newname=NEWNAME NEWNAME for the restored container\n\
-d, --destroy=NAME destroy snapshot NAME, e.g. 'snap0'\n\
use ALL to destroy all snapshots\n\
-c, --comment=FILE add FILE as a comment\n\
-C, --showcomments show snapshot comments\n",
.options = my_longopts,
.parser = my_parser,
.checker = NULL,
.task = SNAP,
};
static int do_destroy_snapshots(struct lxc_container *c, char *snapname);
static int do_list_snapshots(struct lxc_container *c, int print_comments);
static int do_restore_snapshots(struct lxc_container *c, char *snapname,
char *newname);
static int do_snapshot(struct lxc_container *c, char *commentfile);
static int do_snapshot_task(struct lxc_container *c, enum task task);
static void print_file(char *path);
int main(int argc, char *argv[])
{
struct lxc_container *c;
int ret;
if (lxc_arguments_parse(&my_args, argc, argv))
exit(EXIT_FAILURE);
if (!my_args.log_file)
my_args.log_file = "none";
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(EXIT_FAILURE);
lxc_log_options_no_override();
if (geteuid()) {
if (access(my_args.lxcpath[0], O_RDWR) < 0) {
fprintf(stderr, "You lack access to %s\n",
my_args.lxcpath[0]);
exit(EXIT_FAILURE);
}
}
c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
if (!c) {
fprintf(stderr, "System error loading container\n");
exit(EXIT_FAILURE);
}
if (!c->may_control(c)) {
fprintf(stderr, "Insufficent privileges to control %s\n",
my_args.name);
lxc_container_put(c);
exit(EXIT_FAILURE);
}
static int do_snapshot(struct lxc_container *c)
ret = do_snapshot_task(c, my_args.task);
lxc_container_put(c);
if (ret == 0)
exit(EXIT_SUCCESS);
exit(EXIT_FAILURE);
}
static int do_snapshot_task(struct lxc_container *c, enum task task)
{
int ret = 0;
switch (task) {
case DESTROY:
ret = do_destroy_snapshots(c, my_args.snapname);
break;
case LIST:
ret = do_list_snapshots(c, my_args.print_comments);
break;
case RESTORE:
ret =
do_restore_snapshots(c, my_args.snapname, my_args.newname);
break;
case SNAP:
ret = do_snapshot(c, my_args.commentfile);
break;
default:
ret = 0;
break;
}
return ret;
}
static int my_parser(struct lxc_arguments *args, int c, char *arg)
{
switch (c) {
case 'L':
args->task = LIST;
break;
case 'r':
args->task = RESTORE;
args->snapname = arg;
break;
case 'N':
args->newname = arg;
break;
case 'd':
args->task = DESTROY;
args->snapname = arg;
break;
case 'c':
args->commentfile = arg;
break;
case 'C':
args->print_comments = 1;
break;
}
return 0;
}
static int do_snapshot(struct lxc_container *c, char *commentfile)
{
int ret;
......@@ -57,26 +188,11 @@ static int do_snapshot(struct lxc_container *c)
}
INFO("Created snapshot snap%d", ret);
return 0;
}
static void print_file(char *path)
{
if (!path)
return;
FILE *f = fopen(path, "r");
char *line = NULL;
size_t sz = 0;
if (!f)
return;
while (getline(&line, &sz, f) != -1) {
printf("%s", line);
}
free(line);
fclose(f);
return 0;
}
static int do_list_snapshots(struct lxc_container *c)
static int do_list_snapshots(struct lxc_container *c, int print_comments)
{
struct lxc_snapshot *s;
int i, n;
......@@ -90,148 +206,69 @@ static int do_list_snapshots(struct lxc_container *c)
printf("No snapshots\n");
return 0;
}
for (i=0; i<n; i++) {
for (i = 0; i < n; i++) {
printf("%s (%s) %s\n", s[i].name, s[i].lxcpath, s[i].timestamp);
if (print_comments)
print_file(s[i].comment_pathname);
s[i].free(&s[i]);
}
free(s);
return 0;
}
static int do_restore_snapshots(struct lxc_container *c)
static int do_restore_snapshots(struct lxc_container *c, char *snapname,
char *newname)
{
if (c->snapshot_restore(c, snapshot, newname))
if (!newname) {
printf("Error: You must provide a NEWNAME for the container\n");
return -1;
}
if (c->snapshot_restore(c, snapname, newname))
return 0;
ERROR("Error restoring snapshot %s", snapshot);
ERROR("Error restoring snapshot %s", snapname);
return -1;
}
static int do_destroy_snapshots(struct lxc_container *c)
static int do_destroy_snapshots(struct lxc_container *c, char *snapname)
{
bool bret;
if (strcmp(snapshot, "ALL") == 0)
bret = c->snapshot_destroy_all(c);
bool ret;
if (strcmp(snapname, "ALL") == 0)
ret = c->snapshot_destroy_all(c);
else
bret = c->snapshot_destroy(c, snapshot);
ret = c->snapshot_destroy(c, snapname);
if (bret)
if (ret)
return 0;
ERROR("Error destroying snapshot %s", snapshot);
return -1;
}
ERROR("Error destroying snapshot %s", snapname);
static int my_parser(struct lxc_arguments* args, int c, char* arg)
{
switch (c) {
case 'L': action = DO_LIST; break;
case 'r': snapshot = arg; action = DO_RESTORE; break;
case 'd': snapshot = arg; action = DO_DESTROY; break;
case 'c': commentfile = arg; break;
case 'C': print_comments = true; break;
}
return 0;
return -1;
}
static const struct option my_longopts[] = {
{"list", no_argument, 0, 'L'},
{"restore", required_argument, 0, 'r'},
{"destroy", required_argument, 0, 'd'},
{"comment", required_argument, 0, 'c'},
{"showcomments", no_argument, 0, 'C'},
LXC_COMMON_OPTIONS
};
static struct lxc_arguments my_args = {
.progname = "lxc-snapshot",
.help = "\
--name=NAME [-P lxcpath] [-L [-C]] [-c commentfile] [-r snapname [newname]]\n\
\n\
lxc-snapshot snapshots a container\n\
\n\
Options :\n\
-n, --name=NAME NAME for name of the container\n\
-L, --list list snapshots\n\
-C, --showcomments show snapshot comments in list\n\
-c, --comment=file add file as a comment\n\
-r, --restore=name restore snapshot name, i.e. 'snap0'\n\
-d, --destroy=name destroy snapshot name, i.e. 'snap0'\n\
use ALL to destroy all snapshots\n",
.options = my_longopts,
.parser = my_parser,
.checker = NULL,
};
/*
* lxc-snapshot -P lxcpath -n container
* lxc-snapshot -P lxcpath -n container -l
* lxc-snapshot -P lxcpath -n container -r snap3 recovered_1
*/
int main(int argc, char *argv[])
static void print_file(char *path)
{
struct lxc_container *c;
int ret = 0;
if (lxc_arguments_parse(&my_args, argc, argv))
exit(1);
if (!my_args.log_file)
my_args.log_file = "none";
if (my_args.argc > 1) {
ERROR("Too many arguments");
exit(1);
}
if (my_args.argc == 1)
newname = my_args.argv[0];
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);
lxc_log_options_no_override();
if (geteuid()) {
if (access(my_args.lxcpath[0], O_RDWR) < 0) {
fprintf(stderr, "You lack access to %s\n", my_args.lxcpath[0]);
exit(1);
}
}
if (!path)
return;
c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
if (!c) {
fprintf(stderr, "System error loading container\n");
exit(1);
}
FILE *f = fopen(path, "r");
char *line = NULL;
size_t sz = 0;
if (!c->may_control(c)) {
fprintf(stderr, "Insufficent privileges to control %s\n", my_args.name);
lxc_container_put(c);
exit(1);
}
if (!f)
return;
switch(action) {
case DO_SNAP:
ret = do_snapshot(c);
break;
case DO_LIST:
ret = do_list_snapshots(c);
break;
case DO_RESTORE:
ret = do_restore_snapshots(c);
break;
case DO_DESTROY:
ret = do_destroy_snapshots(c);
break;
while (getline(&line, &sz, f) != -1) {
printf("%s", line);
}
lxc_container_put(c);
if (ret == 0)
exit(EXIT_SUCCESS);
exit(EXIT_FAILURE);
free(line);
fclose(f);
}
......@@ -181,7 +181,7 @@ static struct lxc_arguments my_args = {
lxc-start start COMMAND in specified container NAME\n\
\n\
Options :\n\
-n, --name=NAME NAME for name of the container\n\
-n, --name=NAME NAME of the container\n\
-d, --daemon Daemonize the container (default)\n\
-F, --foreground Start with the current tty attached to /dev/console\n\
-p, --pidfile=FILE Create a file with the process id\n\
......
......@@ -69,7 +69,7 @@ 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 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\
......
......@@ -45,7 +45,7 @@ static struct lxc_arguments my_args = {
lxc-unfreeze unfreezes a container with the identifier NAME\n\
\n\
Options :\n\
-n, --name=NAME NAME for name of the container\n",
-n, --name=NAME NAME of the container\n",
.options = my_longopts,
.parser = NULL,
.checker = NULL,
......
......@@ -68,7 +68,7 @@ static struct lxc_arguments my_args = {
lxc-wait waits for NAME container state to reach STATE\n\
\n\
Options :\n\
-n, --name=NAME NAME for name of the container\n\
-n, --name=NAME NAME of the container\n\
-s, --state=STATE ORed states to wait for\n\
STOPPED, STARTING, RUNNING, STOPPING,\n\
ABORTING, FREEZING, FROZEN, THAWED\n\
......
......@@ -2906,12 +2906,15 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
if (ret < 0)
goto out;
clear_unexp_config_line(c2->lxc_conf, "lxc.utsname", false);
// update utsname
if (!set_config_item_locked(c2, "lxc.utsname", newname)) {
ERROR("Error setting new hostname");
goto out;
if (!(flags & LXC_CLONE_KEEPNAME)) {
clear_unexp_config_line(c2->lxc_conf, "lxc.utsname", false);
if (!set_config_item_locked(c2, "lxc.utsname", newname)) {
ERROR("Error setting new hostname");
goto out;
}
}
// copy hooks
......
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