nspawn: support ephemeral boots from images
Previously --ephemeral was only supported with container trees in btrfs subvolumes (i.e. in combination with --directory=). This adds support for --ephemeral in conjunction with disk images (i.e. --image=) too. As side effect this fixes that --ephemeral was accepted but ignored when using -M on a container that turned out to be an image. Fixes: #4664
This commit is contained in:
parent
1a1b13c957
commit
0f3be6ca4d
|
@ -211,13 +211,8 @@
|
||||||
<term><option>-x</option></term>
|
<term><option>-x</option></term>
|
||||||
<term><option>--ephemeral</option></term>
|
<term><option>--ephemeral</option></term>
|
||||||
|
|
||||||
<listitem><para>If specified, the container is run with a
|
<listitem><para>If specified, the container is run with a temporary snapshot of its file system that is removed
|
||||||
temporary <literal>btrfs</literal> snapshot of its root
|
immediately when the container terminates. May not be specified together with
|
||||||
directory (as configured with <option>--directory=</option>),
|
|
||||||
that is removed immediately when the container terminates.
|
|
||||||
This option is only supported if the root file system is
|
|
||||||
<literal>btrfs</literal>. May not be specified together with
|
|
||||||
<option>--image=</option> or
|
|
||||||
<option>--template=</option>.</para>
|
<option>--template=</option>.</para>
|
||||||
<para>Note that this switch leaves host name, machine ID and
|
<para>Note that this switch leaves host name, machine ID and
|
||||||
all other settings that could identify the instance
|
all other settings that could identify the instance
|
||||||
|
@ -252,11 +247,12 @@
|
||||||
Partitions Specification</ulink>.</para></listitem>
|
Partitions Specification</ulink>.</para></listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
||||||
<para>Any other partitions, such as foreign partitions, swap
|
<para>On GPT images, if an EFI System Partition (ESP) is discovered, it is automatically mounted to
|
||||||
partitions or EFI system partitions are not mounted. May not
|
<filename>/efi</filename> (or <filename>/boot</filename> as fallback) in case a directory by this name exists
|
||||||
be specified together with <option>--directory=</option>,
|
and is empty.</para>
|
||||||
<option>--template=</option> or
|
|
||||||
<option>--ephemeral</option>.</para></listitem>
|
<para>Any other partitions, such as foreign partitions or swap partitions are not mounted. May not be specified
|
||||||
|
together with <option>--directory=</option>, <option>--template=</option>.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
|
|
|
@ -143,6 +143,10 @@
|
||||||
#define GRND_RANDOM 0x0002
|
#define GRND_RANDOM 0x0002
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef FS_NOCOW_FL
|
||||||
|
#define FS_NOCOW_FL 0x00800000
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef BTRFS_IOCTL_MAGIC
|
#ifndef BTRFS_IOCTL_MAGIC
|
||||||
#define BTRFS_IOCTL_MAGIC 0x94
|
#define BTRFS_IOCTL_MAGIC 0x94
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1143,11 +1143,6 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arg_ephemeral && arg_image) {
|
|
||||||
log_error("--ephemeral and --image= may not be combined.");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arg_ephemeral && !IN_SET(arg_link_journal, LINK_NO, LINK_AUTO)) {
|
if (arg_ephemeral && !IN_SET(arg_link_journal, LINK_NO, LINK_AUTO)) {
|
||||||
log_error("--ephemeral and --link-journal= may not be combined.");
|
log_error("--ephemeral and --link-journal= may not be combined.");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -2605,7 +2600,7 @@ static int determine_names(void) {
|
||||||
r = image_find(arg_machine, &i);
|
r = image_find(arg_machine, &i);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to find image for machine '%s': %m", arg_machine);
|
return log_error_errno(r, "Failed to find image for machine '%s': %m", arg_machine);
|
||||||
else if (r == 0) {
|
if (r == 0) {
|
||||||
log_error("No image for machine '%s': %m", arg_machine);
|
log_error("No image for machine '%s': %m", arg_machine);
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
@ -2615,14 +2610,14 @@ static int determine_names(void) {
|
||||||
else
|
else
|
||||||
r = free_and_strdup(&arg_directory, i->path);
|
r = free_and_strdup(&arg_directory, i->path);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Invalid image directory: %m");
|
return log_oom();
|
||||||
|
|
||||||
if (!arg_ephemeral)
|
if (!arg_ephemeral)
|
||||||
arg_read_only = arg_read_only || i->read_only;
|
arg_read_only = arg_read_only || i->read_only;
|
||||||
} else
|
} else
|
||||||
arg_directory = get_current_dir_name();
|
arg_directory = get_current_dir_name();
|
||||||
|
|
||||||
if (!arg_directory && !arg_machine) {
|
if (!arg_directory && !arg_image) {
|
||||||
log_error("Failed to determine path, please use -D or -i.");
|
log_error("Failed to determine path, please use -D or -i.");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -2633,7 +2628,6 @@ static int determine_names(void) {
|
||||||
arg_machine = gethostname_malloc();
|
arg_machine = gethostname_malloc();
|
||||||
else
|
else
|
||||||
arg_machine = strdup(basename(arg_image ?: arg_directory));
|
arg_machine = strdup(basename(arg_image ?: arg_directory));
|
||||||
|
|
||||||
if (!arg_machine)
|
if (!arg_machine)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
|
@ -4077,7 +4071,7 @@ int main(int argc, char *argv[]) {
|
||||||
_cleanup_fdset_free_ FDSet *fds = NULL;
|
_cleanup_fdset_free_ FDSet *fds = NULL;
|
||||||
int r, n_fd_passed, loop_nr = -1, ret = EXIT_SUCCESS;
|
int r, n_fd_passed, loop_nr = -1, ret = EXIT_SUCCESS;
|
||||||
char veth_name[IFNAMSIZ] = "";
|
char veth_name[IFNAMSIZ] = "";
|
||||||
bool secondary = false, remove_subvol = false;
|
bool secondary = false, remove_subvol = false, remove_image = false;
|
||||||
pid_t pid = 0;
|
pid_t pid = 0;
|
||||||
union in_addr_union exposed = {};
|
union in_addr_union exposed = {};
|
||||||
_cleanup_release_lock_file_ LockFile tree_global_lock = LOCK_FILE_INIT, tree_local_lock = LOCK_FILE_INIT;
|
_cleanup_release_lock_file_ LockFile tree_global_lock = LOCK_FILE_INIT, tree_local_lock = LOCK_FILE_INIT;
|
||||||
|
@ -4148,7 +4142,7 @@ int main(int argc, char *argv[]) {
|
||||||
else
|
else
|
||||||
r = tempfn_random(arg_directory, "machine.", &np);
|
r = tempfn_random(arg_directory, "machine.", &np);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_error_errno(r, "Failed to generate name for snapshot: %m");
|
log_error_errno(r, "Failed to generate name for directory snapshot: %m");
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4219,19 +4213,46 @@ int main(int argc, char *argv[]) {
|
||||||
assert(arg_image);
|
assert(arg_image);
|
||||||
assert(!arg_template);
|
assert(!arg_template);
|
||||||
|
|
||||||
r = image_path_lock(arg_image, (arg_read_only ? LOCK_SH : LOCK_EX) | LOCK_NB, &tree_global_lock, &tree_local_lock);
|
if (arg_ephemeral) {
|
||||||
if (r == -EBUSY) {
|
_cleanup_free_ char *np = NULL;
|
||||||
r = log_error_errno(r, "Disk image %s is currently busy.", arg_image);
|
|
||||||
goto finish;
|
r = tempfn_random(arg_image, "machine.", &np);
|
||||||
}
|
if (r < 0) {
|
||||||
if (r < 0) {
|
log_error_errno(r, "Failed to generate name for image snapshot: %m");
|
||||||
r = log_error_errno(r, "Failed to create image lock: %m");
|
goto finish;
|
||||||
goto finish;
|
}
|
||||||
|
|
||||||
|
r = image_path_lock(np, (arg_read_only ? LOCK_SH : LOCK_EX) | LOCK_NB, &tree_global_lock, &tree_local_lock);
|
||||||
|
if (r < 0) {
|
||||||
|
r = log_error_errno(r, "Failed to create image lock: %m");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = copy_file(arg_image, np, O_EXCL, arg_read_only ? 0400 : 0600, FS_NOCOW_FL);
|
||||||
|
if (r < 0) {
|
||||||
|
r = log_error_errno(r, "Failed to copy image file: %m");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(arg_image);
|
||||||
|
arg_image = np;
|
||||||
|
np = NULL;
|
||||||
|
|
||||||
|
remove_image = true;
|
||||||
|
} else {
|
||||||
|
r = image_path_lock(arg_image, (arg_read_only ? LOCK_SH : LOCK_EX) | LOCK_NB, &tree_global_lock, &tree_local_lock);
|
||||||
|
if (r == -EBUSY) {
|
||||||
|
r = log_error_errno(r, "Disk image %s is currently busy.", arg_image);
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
if (r < 0) {
|
||||||
|
r = log_error_errno(r, "Failed to create image lock: %m");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mkdtemp(template)) {
|
if (!mkdtemp(template)) {
|
||||||
log_error_errno(errno, "Failed to create temporary directory: %m");
|
r = log_error_errno(errno, "Failed to create temporary directory: %m");
|
||||||
r = -errno;
|
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4255,6 +4276,10 @@ int main(int argc, char *argv[]) {
|
||||||
&secondary);
|
&secondary);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
|
/* Now that we mounted the image, let's try to remove it again, if it is ephemeral */
|
||||||
|
if (remove_image && unlink(arg_image) >= 0)
|
||||||
|
remove_image = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = custom_mounts_prepare();
|
r = custom_mounts_prepare();
|
||||||
|
@ -4337,6 +4362,11 @@ finish:
|
||||||
log_warning_errno(k, "Cannot remove subvolume '%s', ignoring: %m", arg_directory);
|
log_warning_errno(k, "Cannot remove subvolume '%s', ignoring: %m", arg_directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (remove_image && arg_image) {
|
||||||
|
if (unlink(arg_image) < 0)
|
||||||
|
log_warning_errno(errno, "Can't remove image file '%s', ignoring: %m", arg_image);
|
||||||
|
}
|
||||||
|
|
||||||
if (arg_machine) {
|
if (arg_machine) {
|
||||||
const char *p;
|
const char *p;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue