Revert "Refactor lxc-snapshot, lxc-clone, make LXC_CLONE_KEEPNAME work and add option to destroy container with all snapshots to lxc-destroy"

This commit is contained in:
Serge Hallyn 2015-08-14 10:59:19 -05:00
parent f69d74e359
commit 965ef7f460
19 changed files with 337 additions and 470 deletions

View File

@ -94,22 +94,6 @@ struct lxc_arguments {
int list; int list;
char *groups; 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 */ /* remaining arguments */
char *const *argv; char *const *argv;
int argc; int argc;

View File

@ -146,7 +146,7 @@ static struct lxc_arguments my_args = {
Execute the specified COMMAND - enter the container NAME\n\ Execute the specified COMMAND - enter the container NAME\n\
\n\ \n\
Options :\n\ Options :\n\
-n, --name=NAME NAME of the container\n\ -n, --name=NAME NAME for name of the container\n\
-e, --elevated-privileges=PRIVILEGES\n\ -e, --elevated-privileges=PRIVILEGES\n\
Use elevated privileges instead of those of the\n\ Use elevated privileges instead of those of the\n\
container. If you don't specify privileges to be\n\ container. If you don't specify privileges to be\n\

View File

@ -105,7 +105,7 @@ lxc-checkpoint checkpoints and restores a container\n\
its running state at a later time.\n\ its running state at a later time.\n\
\n\ \n\
Options :\n\ Options :\n\
-n, --name=NAME NAME of the container\n\ -n, --name=NAME NAME for name of the container\n\
-r, --restore Restore container\n\ -r, --restore Restore container\n\
-D, --checkpoint-dir=DIR directory to save the checkpoint in\n\ -D, --checkpoint-dir=DIR directory to save the checkpoint in\n\
-v, --verbose Enable verbose criu logs\n\ -v, --verbose Enable verbose criu logs\n\

View File

@ -27,198 +27,17 @@
#include <stdlib.h> #include <stdlib.h>
#include <errno.h> #include <errno.h>
#include <ctype.h> #include <ctype.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <lxc/lxccontainer.h> #include <lxc/lxccontainer.h>
#include "log.h" #include "log.h"
#include "confile.h" #include "config.h"
#include "arguments.h"
#include "lxc.h" #include "lxc.h"
#include "conf.h" #include "conf.h"
#include "state.h" #include "state.h"
lxc_log_define(lxc_clone_ui, lxc); lxc_log_define(lxc_clone_ui, lxc);
static int my_parser(struct lxc_arguments *args, int c, char *arg);
static const struct option my_longopts[] = {
{ "newname", required_argument, 0, 'N'},
{ "newpath", required_argument, 0, 'p'},
{ "rename", no_argument, 0, 'R'},
{ "snapshot", no_argument, 0, 's'},
{ "backingstore", required_argument, 0, 'B'},
{ "fssize", required_argument, 0, 'L'},
{ "keepname", no_argument, 0, 'K'},
{ "keepmac", no_argument, 0, 'M'},
LXC_COMMON_OPTIONS
};
static struct lxc_arguments my_args = {
.progname = "lxc-clone",
.help = "\
--name=NAME [-P lxcpath] -N newname [-p newpath] [-B backingstorage] [-s] [-K] [-M] [-L size [unit]]\n\
\n\
lxc-lcone clone a container\n\
\n\
Options :\n\
-n, --name=NAME NAME of the container\n\
-N, --newname=NEWNAME NEWNAME for the restored container\n\
-p, --newpath=NEWPATH NEWPATH for the container to be stored\n\
-R, --rename rename container\n\
-s, --snapshot create snapshot instead of clone\n\
-B, --backingstorage=TYPE backingstorage type for the container\n\
-L, --fssize size of the new block device for block device containers\n\
-K, --keepname keep the hostname of the original container\n\
-M, --keepmac keep the MAC address of the original container\n",
.options = my_longopts,
.parser = my_parser,
.checker = NULL,
};
static int do_clone(struct lxc_container *c, char *newname, char *newpath,
int flags, char *bdevtype, uint64_t fssize, char **args);
static int do_clone_rename(struct lxc_container *c, char *newname);
static uint64_t get_fssize(char *s);
int main(int argc, char *argv[])
{
struct lxc_container *c;
int flags = 0;
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);
}
}
if (!my_args.newname) {
printf("Error: You must provide a NEWNAME for the clone.\n");
exit(EXIT_FAILURE);
}
if (my_args.task == SNAP)
flags |= LXC_CLONE_SNAPSHOT;
if (my_args.keepname)
flags |= LXC_CLONE_KEEPNAME;
if (my_args.keepmac)
flags |= LXC_CLONE_KEEPMACADDR;
c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
if (!c)
exit(EXIT_FAILURE);
if (!c->may_control(c)) {
fprintf(stderr, "Insufficent privileges to control %s\n",
c->name);
lxc_container_put(c);
exit(EXIT_FAILURE);
}
if (!c->is_defined(c)) {
fprintf(stderr, "Error: container %s is not defined\n",
c->name);
lxc_container_put(c);
exit(EXIT_FAILURE);
}
if (my_args.task == RENAME) {
ret = do_clone_rename(c, my_args.newname);
} else {
ret = do_clone(c, my_args.newname, my_args.newpath, flags,
my_args.bdevtype, my_args.fssize, &argv[optind]);
}
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 'N':
args->newname = arg;
break;
case 'p':
args->newpath = arg;
break;
case 'R':
args->task = RENAME;
break;
case 's':
args->task = SNAP;
break;
case 'B':
args->bdevtype = arg;
break;
case 'L':
args->fssize = get_fssize(optarg);
break;
case 'K':
args->keepname = 1;
break;
case 'M':
args->keepmac = 1;
break;
}
return 0;
}
static int do_clone_rename(struct lxc_container *c, char *newname)
{
bool ret;
ret = c->rename(c, newname);
if (!ret) {
ERROR("Error: Renaming container %s to %s failed\n", c->name,
my_args.newname);
return -1;
}
INFO("Renamed container %s to %s\n", c->name, newname);
return 0;
}
static int do_clone(struct lxc_container *c, char *newname, char *newpath,
int flags, char *bdevtype, uint64_t fssize, char **args)
{
struct lxc_container *clone;
clone = c->clone(c, newname, newpath, flags, bdevtype, NULL, fssize,
args);
if (clone == NULL) {
fprintf(stderr, "clone failed\n");
return -1;
}
INFO("Created container %s as %s of %s\n", newname,
my_args.task ? "snapshot" : "copy", c->name);
lxc_container_put(clone);
return 0;
}
/* we pass fssize in bytes */ /* we pass fssize in bytes */
static uint64_t get_fssize(char *s) static uint64_t get_fssize(char *s)
{ {
@ -226,29 +45,171 @@ static uint64_t get_fssize(char *s)
char *end; char *end;
ret = strtoull(s, &end, 0); ret = strtoull(s, &end, 0);
if (end == s) { if (end == s)
{
fprintf(stderr, "Invalid blockdev size '%s', using default size\n", s); fprintf(stderr, "Invalid blockdev size '%s', using default size\n", s);
return 0; return 0;
} }
while (isblank(*end)) while (isblank(*end))
end++; end++;
if (*end == '\0') { if (*end == '\0')
ret *= 1024ULL * 1024ULL; // MB by default ret *= 1024ULL * 1024ULL; // MB by default
} else if (*end == 'b' || *end == 'B') { else if (*end == 'b' || *end == 'B')
ret *= 1ULL; ret *= 1ULL;
} else if (*end == 'k' || *end == 'K') { else if (*end == 'k' || *end == 'K')
ret *= 1024ULL; ret *= 1024ULL;
} else if (*end == 'm' || *end == 'M') { else if (*end == 'm' || *end == 'M')
ret *= 1024ULL * 1024ULL; ret *= 1024ULL * 1024ULL;
} else if (*end == 'g' || *end == 'G') { else if (*end == 'g' || *end == 'G')
ret *= 1024ULL * 1024ULL * 1024ULL; ret *= 1024ULL * 1024ULL * 1024ULL;
} else if (*end == 't' || *end == 'T') { else if (*end == 't' || *end == 'T')
ret *= 1024ULL * 1024ULL * 1024ULL * 1024ULL; ret *= 1024ULL * 1024ULL * 1024ULL * 1024ULL;
} else { else
fprintf(stderr, "Invalid blockdev unit size '%c' in '%s', " "using default size\n", *end, s); {
fprintf(stderr, "Invalid blockdev unit size '%c' in '%s', using default size\n", *end, s);
return 0; return 0;
} }
return ret; return ret;
} }
static void usage(const char *me)
{
printf("Usage: %s [-s] [-B backingstore] [-L size[unit]] [-K] [-M] [-H]\n", me);
printf(" [-p lxcpath] [-P newlxcpath] orig new\n");
printf("\n");
printf(" -s: snapshot rather than copy\n");
printf(" -B: use specified new backingstore. Default is the same as\n");
printf(" the original. Options include aufs, btrfs, lvm, overlayfs, \n");
printf(" dir and loop\n");
printf(" -L: for blockdev-backed backingstore, use specified size * specified\n");
printf(" unit. Default size is the size of the source blockdev, default\n");
printf(" unit is MB\n");
printf(" -K: Keep name - do not change the container name\n");
printf(" -M: Keep macaddr - do not choose a random new mac address\n");
printf(" -p: use container orig from custom lxcpath\n");
printf(" -P: create container new in custom lxcpath\n");
printf(" -R: rename existing container\n");
exit(1);
}
static struct option options[] = {
{ "snapshot", no_argument, 0, 's'},
{ "backingstore", required_argument, 0, 'B'},
{ "size", required_argument, 0, 'L'},
{ "orig", required_argument, 0, 'o'},
{ "new", required_argument, 0, 'n'},
{ "vgname", required_argument, 0, 'v'},
{ "rename", no_argument, 0, 'R'},
{ "keepname", no_argument, 0, 'K'},
{ "keepmac", no_argument, 0, 'M'},
{ "lxcpath", required_argument, 0, 'p'},
{ "newpath", required_argument, 0, 'P'},
{ "fstype", required_argument, 0, 't'},
{ "help", no_argument, 0, 'h'},
{ 0, 0, 0, 0 },
};
int main(int argc, char *argv[])
{
struct lxc_container *c1 = NULL, *c2 = NULL;
int snapshot = 0, keepname = 0, keepmac = 0, rename = 0;
int flags = 0, option_index;
uint64_t newsize = 0;
char *bdevtype = NULL, *lxcpath = NULL, *newpath = NULL, *fstype = NULL;
char *orig = NULL, *new = NULL, *vgname = NULL;
char **args = NULL;
int c;
bool ret;
if (argc < 3)
usage(argv[0]);
while (1) {
c = getopt_long(argc, argv, "sB:L:o:n:v:KMHp:P:Rt:h", options, &option_index);
if (c == -1)
break;
switch (c) {
case 's': snapshot = 1; break;
case 'B': bdevtype = optarg; break;
case 'L': newsize = get_fssize(optarg); break;
case 'o': orig = optarg; break;
case 'n': new = optarg; break;
case 'v': vgname = optarg; break;
case 'K': keepname = 1; break;
case 'M': keepmac = 1; break;
case 'p': lxcpath = optarg; break;
case 'P': newpath = optarg; break;
case 'R': rename = 1; break;
case 't': fstype = optarg; break;
case 'h': usage(argv[0]);
default: break;
}
}
if (optind < argc && !orig)
orig = argv[optind++];
if (optind < argc && !new)
new = argv[optind++];
if (optind < argc)
/* arguments for the clone hook */
args = &argv[optind];
if (!new || !orig) {
printf("Error: you must provide orig and new names\n");
usage(argv[0]);
}
if (snapshot) flags |= LXC_CLONE_SNAPSHOT;
if (keepname) flags |= LXC_CLONE_KEEPNAME;
if (keepmac) flags |= LXC_CLONE_KEEPMACADDR;
// vgname and fstype could be supported by sending them through the
// bdevdata. However, they currently are not yet. I'm not convinced
// they are worthwhile.
if (vgname) {
printf("Error: vgname not supported\n");
usage(argv[0]);
}
if (fstype) {
printf("Error: fstype not supported\n");
usage(argv[0]);
}
c1 = lxc_container_new(orig, lxcpath);
if (!c1)
exit(EXIT_FAILURE);
if (!c1->may_control(c1)) {
fprintf(stderr, "Insufficent privileges to control %s\n", orig);
lxc_container_put(c1);
exit(EXIT_FAILURE);
}
if (!c1->is_defined(c1)) {
fprintf(stderr, "Error: container %s is not defined\n", orig);
lxc_container_put(c1);
exit(EXIT_FAILURE);
}
if (rename) {
ret = c1->rename(c1, new);
if (!ret) {
fprintf(stderr,
"Error: Renaming container %s to %s failed\n",
c1->name, new);
lxc_container_put(c1);
exit(EXIT_FAILURE);
}
} else {
c2 = c1->clone(c1, new, newpath, flags, bdevtype, NULL, newsize,
args);
if (c2 == NULL) {
lxc_container_put(c1);
fprintf(stderr, "clone failed\n");
exit(EXIT_FAILURE);
}
printf("Created container %s as %s of %s\n", new,
snapshot ? "snapshot" : "copy", orig);
lxc_container_put(c2);
}
lxc_container_put(c1);
exit(EXIT_SUCCESS);
}

View File

@ -78,7 +78,7 @@ static struct lxc_arguments my_args = {
lxc-console logs on the container with the identifier NAME\n\ lxc-console logs on the container with the identifier NAME\n\
\n\ \n\
Options :\n\ Options :\n\
-n, --name=NAME NAME of the container\n\ -n, --name=NAME NAME for name of the container\n\
-t, --tty=NUMBER console tty number\n\ -t, --tty=NUMBER console tty number\n\
-e, --escape=PREFIX prefix for escape command\n", -e, --escape=PREFIX prefix for escape command\n",
.options = my_longopts, .options = my_longopts,

View File

@ -131,7 +131,7 @@ static struct lxc_arguments my_args = {
lxc-create creates a container\n\ lxc-create creates a container\n\
\n\ \n\
Options :\n\ Options :\n\
-n, --name=NAME NAME of the container\n\ -n, --name=NAME NAME for name of the container\n\
-f, --config=file Initial configuration file\n\ -f, --config=file Initial configuration file\n\
-t, --template=t Template to use to setup container\n\ -t, --template=t Template to use to setup container\n\
-B, --bdev=BDEV Backing store type to use\n\ -B, --bdev=BDEV Backing store type to use\n\

View File

@ -31,11 +31,16 @@
lxc_log_define(lxc_destroy_ui, lxc); lxc_log_define(lxc_destroy_ui, lxc);
static int my_parser(struct lxc_arguments* args, int c, char* arg); static int my_parser(struct lxc_arguments* args, int c, char* arg)
{
switch (c) {
case 'f': args->force = 1; break;
}
return 0;
}
static const struct option my_longopts[] = { static const struct option my_longopts[] = {
{"force", no_argument, 0, 'f'}, {"force", no_argument, 0, 'f'},
{"snapshots", no_argument, 0, 's'},
LXC_COMMON_OPTIONS LXC_COMMON_OPTIONS
}; };
@ -47,104 +52,61 @@ static struct lxc_arguments my_args = {
lxc-destroy destroys a container with the identifier NAME\n\ lxc-destroy destroys a container with the identifier NAME\n\
\n\ \n\
Options :\n\ Options :\n\
-n, --name=NAME NAME of the container\n\ -n, --name=NAME NAME for name of the container\n\
-s, --snapshots destroy including all snapshots\n\
-f, --force wait for the container to shut down\n", -f, --force wait for the container to shut down\n",
.options = my_longopts, .options = my_longopts,
.parser = my_parser, .parser = my_parser,
.checker = NULL, .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[]) int main(int argc, char *argv[])
{ {
struct lxc_container *c; struct lxc_container *c;
int ret;
if (lxc_arguments_parse(&my_args, argc, argv)) if (lxc_arguments_parse(&my_args, argc, argv))
exit(EXIT_FAILURE); exit(1);
if (!my_args.log_file) if (!my_args.log_file)
my_args.log_file = "none"; my_args.log_file = "none";
if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority, 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])) my_args.progname, my_args.quiet, my_args.lxcpath[0]))
exit(EXIT_FAILURE); exit(1);
lxc_log_options_no_override(); lxc_log_options_no_override();
c = lxc_container_new(my_args.name, my_args.lxcpath[0]); c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
if (!c) { if (!c) {
fprintf(stderr, "System error loading container\n"); fprintf(stderr, "System error loading container\n");
exit(EXIT_FAILURE); exit(1);
} }
if (!c->may_control(c)) { if (!c->may_control(c)) {
fprintf(stderr, "Insufficent privileges to control %s\n", my_args.name); fprintf(stderr, "Insufficent privileges to control %s\n", my_args.name);
lxc_container_put(c); lxc_container_put(c);
exit(EXIT_FAILURE); exit(1);
} }
if (!c->is_defined(c)) { if (!c->is_defined(c)) {
fprintf(stderr, "Container is not defined\n"); fprintf(stderr, "Container is not defined\n");
lxc_container_put(c); lxc_container_put(c);
exit(EXIT_FAILURE); exit(1);
} }
if (c->is_running(c)) { if (c->is_running(c)) {
if (!my_args.force) { if (!my_args.force) {
fprintf(stderr, "%s is running\n", my_args.name); fprintf(stderr, "%s is running\n", my_args.name);
lxc_container_put(c); lxc_container_put(c);
exit(EXIT_FAILURE); exit(1);
} }
c->stop(c); c->stop(c);
} }
if (my_args.task == SNAP) { if (!c->destroy(c)) {
ret = do_destroy_with_snapshots(c); fprintf(stderr, "Destroying %s failed\n", my_args.name);
} else { lxc_container_put(c);
ret = do_destroy(c); exit(1);
} }
lxc_container_put(c); lxc_container_put(c);
exit(0);
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);
return -1;
}
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;
}

View File

@ -53,7 +53,7 @@ static struct lxc_arguments my_args = {
lxc-device attach or detach DEV to or from container.\n\ lxc-device attach or detach DEV to or from container.\n\
\n\ \n\
Options :\n\ Options :\n\
-n, --name=NAME NAME of the container", -n, --name=NAME NAME for name of the container",
.options = my_longopts, .options = my_longopts,
.parser = NULL, .parser = NULL,
.checker = NULL, .checker = NULL,

View File

@ -79,7 +79,7 @@ lxc-execute creates a container with the identifier NAME\n\
and execs COMMAND into this container.\n\ and execs COMMAND into this container.\n\
\n\ \n\
Options :\n\ Options :\n\
-n, --name=NAME NAME of the container\n\ -n, --name=NAME NAME for name of the container\n\
-f, --rcfile=FILE Load configuration file FILE\n\ -f, --rcfile=FILE Load configuration file FILE\n\
-s, --define KEY=VAL Assign VAL to configuration variable KEY\n", -s, --define KEY=VAL Assign VAL to configuration variable KEY\n",
.options = my_longopts, .options = my_longopts,

View File

@ -47,7 +47,7 @@ static struct lxc_arguments my_args = {
lxc-freeze freezes a container with the identifier NAME\n\ lxc-freeze freezes a container with the identifier NAME\n\
\n\ \n\
Options :\n\ Options :\n\
-n, --name=NAME NAME of the container", -n, --name=NAME NAME for name of the container",
.options = my_longopts, .options = my_longopts,
.parser = NULL, .parser = NULL,
.checker = NULL, .checker = NULL,

View File

@ -87,7 +87,7 @@ static struct lxc_arguments my_args = {
lxc-info display some information about a container with the identifier NAME\n\ lxc-info display some information about a container with the identifier NAME\n\
\n\ \n\
Options :\n\ Options :\n\
-n, --name=NAME NAME of the container\n\ -n, --name=NAME NAME for name of the container\n\
-c, --config=KEY show configuration variable KEY from running container\n\ -c, --config=KEY show configuration variable KEY from running container\n\
-i, --ips shows the IP addresses\n\ -i, --ips shows the IP addresses\n\
-p, --pid shows the process id of the init container\n\ -p, --pid shows the process id of the init container\n\

View File

@ -61,7 +61,7 @@ static void interrupt_handler(int sig)
static void usage(void) { static void usage(void) {
fprintf(stderr, "Usage: lxc-init [OPTION]...\n\n" fprintf(stderr, "Usage: lxc-init [OPTION]...\n\n"
"Common options :\n" "Common options :\n"
" -n, --name=NAME NAME of the container\n" " -n, --name=NAME NAME for name of the container\n"
" -l, --logpriority=LEVEL Set log priority to LEVEL\n" " -l, --logpriority=LEVEL Set log priority to LEVEL\n"
" -q, --quiet Don't produce any output\n" " -q, --quiet Don't produce any output\n"
" -P, --lxcpath=PATH Use specified container path\n" " -P, --lxcpath=PATH Use specified container path\n"

View File

@ -61,7 +61,7 @@ static struct lxc_arguments my_args = {
lxc-monitor monitors the state of the NAME container\n\ lxc-monitor monitors the state of the NAME container\n\
\n\ \n\
Options :\n\ Options :\n\
-n, --name=NAME NAME of the container\n\ -n, --name=NAME NAME for name of the container\n\
NAME may be a regular expression\n\ NAME may be a regular expression\n\
-Q, --quit tell lxc-monitord to quit\n", -Q, --quit tell lxc-monitord to quit\n",
.name = ".*", .name = ".*",

View File

@ -16,8 +16,8 @@
* with this program; if not, write to the Free Software Foundation, Inc., * with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include "config.h"
#include "confile.h"
#include <stdio.h> #include <stdio.h>
#include <libgen.h> #include <libgen.h>
#include <unistd.h> #include <unistd.h>
@ -35,149 +35,18 @@
lxc_log_define(lxc_snapshot_ui, lxc); lxc_log_define(lxc_snapshot_ui, lxc);
static int my_parser(struct lxc_arguments *args, int c, char *arg); static char *newname;
static char *snapshot;
static const struct option my_longopts[] = { #define DO_SNAP 0
{"list", no_argument, 0, 'L'}, #define DO_LIST 1
{"restore", required_argument, 0, 'r'}, #define DO_RESTORE 2
{"newname", required_argument, 0, 'N'}, #define DO_DESTROY 3
{"destroy", required_argument, 0, 'd'}, static int action;
{"comment", required_argument, 0, 'c'}, static int print_comments;
{"showcomments", no_argument, 0, 'C'}, static char *commentfile;
LXC_COMMON_OPTIONS
};
static struct lxc_arguments my_args = { static int do_snapshot(struct lxc_container *c)
.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);
}
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; int ret;
@ -188,11 +57,26 @@ static int do_snapshot(struct lxc_container *c, char *commentfile)
} }
INFO("Created snapshot snap%d", ret); INFO("Created snapshot snap%d", ret);
return 0; return 0;
} }
static int do_list_snapshots(struct lxc_container *c, int print_comments) 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);
}
static int do_list_snapshots(struct lxc_container *c)
{ {
struct lxc_snapshot *s; struct lxc_snapshot *s;
int i, n; int i, n;
@ -206,69 +90,148 @@ static int do_list_snapshots(struct lxc_container *c, int print_comments)
printf("No snapshots\n"); printf("No snapshots\n");
return 0; 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); printf("%s (%s) %s\n", s[i].name, s[i].lxcpath, s[i].timestamp);
if (print_comments) if (print_comments)
print_file(s[i].comment_pathname); print_file(s[i].comment_pathname);
s[i].free(&s[i]); s[i].free(&s[i]);
} }
free(s); free(s);
return 0; return 0;
} }
static int do_restore_snapshots(struct lxc_container *c, char *snapname, static int do_restore_snapshots(struct lxc_container *c)
char *newname)
{ {
if (!newname) { if (c->snapshot_restore(c, snapshot, newname))
printf("Error: You must provide a NEWNAME for the container\n");
return -1;
}
if (c->snapshot_restore(c, snapname, newname))
return 0; return 0;
ERROR("Error restoring snapshot %s", snapname); ERROR("Error restoring snapshot %s", snapshot);
return -1; return -1;
} }
static int do_destroy_snapshots(struct lxc_container *c, char *snapname) static int do_destroy_snapshots(struct lxc_container *c)
{ {
bool ret; bool bret;
if (strcmp(snapshot, "ALL") == 0)
if (strcmp(snapname, "ALL") == 0) bret = c->snapshot_destroy_all(c);
ret = c->snapshot_destroy_all(c);
else else
ret = c->snapshot_destroy(c, snapname); bret = c->snapshot_destroy(c, snapshot);
if (ret) if (bret)
return 0; return 0;
ERROR("Error destroying snapshot %s", snapname); ERROR("Error destroying snapshot %s", snapshot);
return -1; return -1;
} }
static void print_file(char *path) static int my_parser(struct lxc_arguments* args, int c, char* arg)
{ {
if (!path) switch (c) {
return; case 'L': action = DO_LIST; break;
case 'r': snapshot = arg; action = DO_RESTORE; break;
FILE *f = fopen(path, "r"); case 'd': snapshot = arg; action = DO_DESTROY; break;
char *line = NULL; case 'c': commentfile = arg; break;
size_t sz = 0; case 'C': print_comments = true; break;
if (!f)
return;
while (getline(&line, &sz, f) != -1) {
printf("%s", line);
} }
return 0;
free(line);
fclose(f);
} }
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[])
{
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);
}
}
c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
if (!c) {
fprintf(stderr, "System error loading container\n");
exit(1);
}
if (!c->may_control(c)) {
fprintf(stderr, "Insufficent privileges to control %s\n", my_args.name);
lxc_container_put(c);
exit(1);
}
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;
}
lxc_container_put(c);
if (ret == 0)
exit(EXIT_SUCCESS);
exit(EXIT_FAILURE);
}

View File

@ -181,7 +181,7 @@ static struct lxc_arguments my_args = {
lxc-start start COMMAND in specified container NAME\n\ lxc-start start COMMAND in specified container NAME\n\
\n\ \n\
Options :\n\ Options :\n\
-n, --name=NAME NAME of the container\n\ -n, --name=NAME NAME for name of the container\n\
-d, --daemon Daemonize the container (default)\n\ -d, --daemon Daemonize the container (default)\n\
-F, --foreground Start with the current tty attached to /dev/console\n\ -F, --foreground Start with the current tty attached to /dev/console\n\
-p, --pidfile=FILE Create a file with the process id\n\ -p, --pidfile=FILE Create a file with the process id\n\

View File

@ -69,7 +69,7 @@ static struct lxc_arguments my_args = {
lxc-stop stops a container with the identifier NAME\n\ lxc-stop stops a container with the identifier NAME\n\
\n\ \n\
Options :\n\ Options :\n\
-n, --name=NAME NAME of the container\n\ -n, --name=NAME NAME for name of the container\n\
-r, --reboot reboot the container\n\ -r, --reboot reboot the container\n\
-W, --nowait don't wait for shutdown or reboot to complete\n\ -W, --nowait don't wait for shutdown or reboot to complete\n\
-t, --timeout=T wait T seconds before hard-stopping\n\ -t, --timeout=T wait T seconds before hard-stopping\n\

View File

@ -45,7 +45,7 @@ static struct lxc_arguments my_args = {
lxc-unfreeze unfreezes a container with the identifier NAME\n\ lxc-unfreeze unfreezes a container with the identifier NAME\n\
\n\ \n\
Options :\n\ Options :\n\
-n, --name=NAME NAME of the container\n", -n, --name=NAME NAME for name of the container\n",
.options = my_longopts, .options = my_longopts,
.parser = NULL, .parser = NULL,
.checker = NULL, .checker = NULL,

View File

@ -68,7 +68,7 @@ static struct lxc_arguments my_args = {
lxc-wait waits for NAME container state to reach STATE\n\ lxc-wait waits for NAME container state to reach STATE\n\
\n\ \n\
Options :\n\ Options :\n\
-n, --name=NAME NAME of the container\n\ -n, --name=NAME NAME for name of the container\n\
-s, --state=STATE ORed states to wait for\n\ -s, --state=STATE ORed states to wait for\n\
STOPPED, STARTING, RUNNING, STOPPING,\n\ STOPPED, STARTING, RUNNING, STOPPING,\n\
ABORTING, FREEZING, FROZEN, THAWED\n\ ABORTING, FREEZING, FROZEN, THAWED\n\

View File

@ -2906,15 +2906,12 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
if (ret < 0) if (ret < 0)
goto out; goto out;
clear_unexp_config_line(c2->lxc_conf, "lxc.utsname", false);
// update utsname // update utsname
if (!(flags & LXC_CLONE_KEEPNAME)) { if (!set_config_item_locked(c2, "lxc.utsname", newname)) {
clear_unexp_config_line(c2->lxc_conf, "lxc.utsname", false); ERROR("Error setting new hostname");
goto out;
if (!set_config_item_locked(c2, "lxc.utsname", newname)) {
ERROR("Error setting new hostname");
goto out;
}
} }
// copy hooks // copy hooks