mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-07-16 18:41:21 +00:00
Merge pull request #1084 from brauner/2016-07-16/clone_on_tmpfs
lxc-copy: allow snapshots to be placed on tmpfs
This commit is contained in:
commit
897dcac41f
@ -131,6 +131,9 @@ struct lxc_arguments {
|
||||
bool ls_running;
|
||||
bool ls_stopped;
|
||||
|
||||
/* lxc-copy */
|
||||
bool tmpfs;
|
||||
|
||||
/* remaining arguments */
|
||||
char *const *argv;
|
||||
int argc;
|
||||
|
@ -87,6 +87,7 @@ static const struct option my_longopts[] = {
|
||||
{ "keepdata", no_argument, 0, 'D'},
|
||||
{ "keepname", no_argument, 0, 'K'},
|
||||
{ "keepmac", no_argument, 0, 'M'},
|
||||
{ "tmpfs", no_argument, 0, 't'},
|
||||
LXC_COMMON_OPTIONS
|
||||
};
|
||||
|
||||
@ -119,6 +120,8 @@ Options :\n\
|
||||
-m, --mount directory to mount into container, either \n\
|
||||
{bind,aufs,overlay}=/src-path or {bind,aufs,overlay}=/src-path:/dst-path\n\
|
||||
-B, --backingstorage=TYPE backingstorage type for the container\n\
|
||||
-t, --tmpfs place ephemeral container on a tmpfs\n\
|
||||
(WARNING: On reboot all changes made to the container will be lost.)\n\
|
||||
-L, --fssize size of the new block device for block device containers\n\
|
||||
-D, --keedata pass together with -e start a persistent snapshot \n\
|
||||
-K, --keepname keep the hostname of the original container\n\
|
||||
@ -129,6 +132,7 @@ Options :\n\
|
||||
.task = CLONE,
|
||||
.daemonize = 1,
|
||||
.quiet = false,
|
||||
.tmpfs = false,
|
||||
};
|
||||
|
||||
static struct mnts *add_mnt(struct mnts **mnts, unsigned int *num,
|
||||
@ -148,6 +152,13 @@ static int do_clone_task(struct lxc_container *c, enum task task, int flags,
|
||||
char **args);
|
||||
static void free_mnts(void);
|
||||
static uint64_t get_fssize(char *s);
|
||||
|
||||
/* Place an ephemeral container started with -e flag on a tmpfs. Restrictions
|
||||
* are that you cannot request the data to be kept while placing the container
|
||||
* on a tmpfs and that either overlay or aufs backing storage must be used.
|
||||
*/
|
||||
static char *mount_tmpfs(const char *oldname, const char *newname,
|
||||
const char *path, struct lxc_arguments *arg);
|
||||
static int parse_mntsubopts(char *subopts, char *const *keys,
|
||||
char *mntparameters);
|
||||
static int parse_aufs_mnt(char *mntstring, enum mnttype type);
|
||||
@ -369,12 +380,13 @@ static int do_clone(struct lxc_container *c, char *newname, char *newpath,
|
||||
static int do_clone_ephemeral(struct lxc_container *c,
|
||||
struct lxc_arguments *arg, char **args, int flags)
|
||||
{
|
||||
char *bdev;
|
||||
char *premount;
|
||||
char randname[MAXPATHLEN];
|
||||
unsigned int i;
|
||||
int ret = 0;
|
||||
bool bret = true, started = false;
|
||||
struct lxc_container *clone;
|
||||
|
||||
lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
|
||||
attach_options.env_policy = LXC_ATTACH_CLEAR_ENV;
|
||||
|
||||
@ -396,6 +408,23 @@ static int do_clone_ephemeral(struct lxc_container *c,
|
||||
if (!clone)
|
||||
return -1;
|
||||
|
||||
if (arg->tmpfs) {
|
||||
bdev = c->lxc_conf->rootfs.bdev_type;
|
||||
if (bdev && strcmp(bdev, "dir")) {
|
||||
fprintf(stderr, "Cannot currently use tmpfs with %s storage backend.\n", bdev);
|
||||
goto destroy_and_put;
|
||||
}
|
||||
|
||||
premount = mount_tmpfs(arg->name, arg->newname, arg->newpath, arg);
|
||||
if (!premount)
|
||||
goto destroy_and_put;
|
||||
|
||||
bret = clone->set_config_item(clone, "lxc.hook.pre-mount", premount);
|
||||
free(premount);
|
||||
if (!bret)
|
||||
goto destroy_and_put;
|
||||
}
|
||||
|
||||
if (!arg->keepdata)
|
||||
if (!clone->set_config_item(clone, "lxc.ephemeral", "1"))
|
||||
goto destroy_and_put;
|
||||
@ -423,6 +452,10 @@ static int do_clone_ephemeral(struct lxc_container *c,
|
||||
if (!my_args.quiet)
|
||||
printf("Created %s as clone of %s\n", arg->newname, arg->name);
|
||||
|
||||
if (arg->tmpfs && !my_args.quiet)
|
||||
printf("Container is placed on tmpfs.\nRebooting will cause "
|
||||
"all changes made to it to be lost!");
|
||||
|
||||
if (!arg->daemonize && arg->argc) {
|
||||
clone->want_daemonize(clone, true);
|
||||
arg->daemonize = 1;
|
||||
@ -575,6 +608,9 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg)
|
||||
case 'B':
|
||||
args->bdevtype = arg;
|
||||
break;
|
||||
case 't':
|
||||
args->tmpfs = true;
|
||||
break;
|
||||
case 'L':
|
||||
args->fssize = get_fssize(optarg);
|
||||
break;
|
||||
@ -753,3 +789,75 @@ err:
|
||||
lxc_free_array((void **)mntarray, free);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* For ephemeral snapshots backed by overlay or aufs filesystems, this function
|
||||
* mounts a fresh tmpfs over the containers directory if the user requests it.
|
||||
* Because we mount a fresh tmpfs over the directory of the container the
|
||||
* updated /etc/hostname file created during the clone residing in the upperdir
|
||||
* (currently named "delta0" by default) will be hidden. Hence, if the user
|
||||
* requests that the old name is not to be kept for the clone, we recreate this
|
||||
* file on the tmpfs. This should be all that is required to restore the exact
|
||||
* behaviour we would get with a normal clone.
|
||||
*/
|
||||
static char *mount_tmpfs(const char *oldname, const char *newname,
|
||||
const char *path, struct lxc_arguments *arg)
|
||||
{
|
||||
int ret, fd;
|
||||
size_t len;
|
||||
char *premount = NULL;
|
||||
|
||||
if (arg->tmpfs && arg->keepdata) {
|
||||
fprintf(stderr, "%s\n", "A container can only be placed on a "
|
||||
"tmpfs when storage backend is overlay "
|
||||
"or aufs.");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
if (arg->tmpfs && !arg->bdevtype) {
|
||||
arg->bdevtype = "overlayfs";
|
||||
} else if (arg->tmpfs && arg->bdevtype && strcmp(arg->bdevtype, "overlayfs") && strcmp(arg->bdevtype, "aufs")) {
|
||||
fprintf(stderr, "%s\n", "A container can only be placed on a "
|
||||
"tmpfs when storage backend is overlay "
|
||||
"or aufs.");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
len = strlen(path) + strlen(newname) + strlen("pre-start-XXXXXX") + /* //\0 */ 3;
|
||||
premount = malloc(len);
|
||||
if (!premount)
|
||||
goto err_free;
|
||||
|
||||
ret = snprintf(premount, len, "%s/%s/pre-start-XXXXXX", path, newname);
|
||||
if (ret < 0 || (size_t)ret >= len)
|
||||
goto err_free;
|
||||
|
||||
fd = mkostemp(premount, O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
goto err_free;
|
||||
|
||||
if (chmod(premount, 0755) < 0)
|
||||
goto err_close;
|
||||
|
||||
ret = dprintf(fd, "#! /bin/sh\n"
|
||||
"mount -n -t tmpfs -o mode=0755 none %s/%s\n",
|
||||
path, newname);
|
||||
if (ret < 0)
|
||||
goto err_close;
|
||||
|
||||
if (!arg->keepname) {
|
||||
ret = dprintf(fd, "mkdir -p %s/%s/delta0/etc\n"
|
||||
"echo %s > %s/%s/delta0/etc/hostname\n",
|
||||
path, newname, newname, path, newname);
|
||||
if (ret < 0)
|
||||
goto err_close;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return premount;
|
||||
|
||||
err_close:
|
||||
close(fd);
|
||||
err_free:
|
||||
free(premount);
|
||||
return NULL;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user