summaryrefslogtreecommitdiff
path: root/src/libostree/ostree-sysroot-deploy.c
diff options
context:
space:
mode:
authorJonathan Lebon <jonathan@jlebon.com>2020-08-17 09:48:18 -0400
committerJonathan Lebon <jonathan@jlebon.com>2020-09-30 13:29:32 -0400
commit81b13da8e35e18cfb445f66bf365420aa0e9fa0a (patch)
tree108985e5bdc16ca7b48ae0777fd8bb6e8ffd9193 /src/libostree/ostree-sysroot-deploy.c
parent40fea4c44390116095841ee11b4d336195e56330 (diff)
downloadostree-81b13da8e35e18cfb445f66bf365420aa0e9fa0a.tar.gz
lib/deploy: Add support for overlay initrds
In FCOS and RHCOS, the need to configure software in the initramfs has come up multiple times. Sometimes, using kernel arguments suffices. Other times, it really must be a configuration file. Rebuilding the initramfs on the client-side however is a costly operation. Not only does it add complexity to the update workflow, it also erodes a lot of the value obtained from using the baked "blessed" initramfs from the tree itself. One elegant way to address this is to allow specifying multiple initramfses. This is supported by most bootloaders (notably GRUB) and results in each initrd being overlayed on top of each other. This patch allows libostree clients to leverage this so that they can avoid regenerating the initramfs entirely. libostree itself is agnostic as to what kind and how much data overlay initrds contain. It's up to the clients to enforce such boundaries. To implement this, we add a new ostree_sysroot_stage_overlay_initrd which takes a file descriptor and returns a checksum. Then users can pass these checksums when calling the deploy APIs via the new array option `overlay_initrds`. We copy these files into `/boot` and add them to the BLS as another `initrd` entry.
Diffstat (limited to 'src/libostree/ostree-sysroot-deploy.c')
-rw-r--r--src/libostree/ostree-sysroot-deploy.c112
1 files changed, 112 insertions, 0 deletions
diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c
index 9425316f..1c4fb5dc 100644
--- a/src/libostree/ostree-sysroot-deploy.c
+++ b/src/libostree/ostree-sysroot-deploy.c
@@ -1859,6 +1859,47 @@ install_deployment_kernel (OstreeSysroot *sysroot,
}
}
+ g_autoptr(GPtrArray) overlay_initrds = NULL;
+ for (char **it = _ostree_deployment_get_overlay_initrds (deployment); it && *it; it++)
+ {
+ char *checksum = *it;
+
+ /* Overlay initrds are not part of the bootcsum dir; they're not part of the tree
+ * proper. Instead they're in /boot/ostree/initramfs-overlays/ named by their csum.
+ * Doing it this way allows sharing the same bootcsum dir for multiple deployments
+ * with the only change being in overlay initrds (or conversely, the same overlay
+ * across different boocsums). Eventually, it'd be nice to have an OSTree repo in
+ * /boot itself and drop the boocsum dir concept entirely. */
+
+ g_autofree char *destpath =
+ g_strdup_printf ("/" _OSTREE_SYSROOT_BOOT_INITRAMFS_OVERLAYS "/%s.img", checksum);
+ const char *rel_destpath = destpath + 1;
+
+ /* lazily allocate array and create dir so we don't pollute /boot if not needed */
+ if (overlay_initrds == NULL)
+ {
+ overlay_initrds = g_ptr_array_new_with_free_func (g_free);
+
+ if (!glnx_shutil_mkdir_p_at (boot_dfd, _OSTREE_SYSROOT_BOOT_INITRAMFS_OVERLAYS,
+ 0755, cancellable, error))
+ return FALSE;
+ }
+
+ if (!glnx_fstatat_allow_noent (boot_dfd, rel_destpath, NULL, 0, error))
+ return FALSE;
+ if (errno == ENOENT)
+ {
+ g_autofree char *srcpath =
+ g_strdup_printf (_OSTREE_SYSROOT_RUNSTATE_STAGED_INITRDS_DIR "/%s", checksum);
+ if (!install_into_boot (repo, sepolicy, AT_FDCWD, srcpath, boot_dfd, rel_destpath,
+ cancellable, error))
+ return FALSE;
+ }
+
+ /* these are used lower down to populate the bootconfig */
+ g_ptr_array_add (overlay_initrds, g_steal_pointer (&destpath));
+ }
+
g_autofree char *contents = NULL;
if (!glnx_fstatat_allow_noent (deployment_dfd, "usr/lib/os-release", &stbuf, 0, error))
return FALSE;
@@ -1938,6 +1979,12 @@ install_deployment_kernel (OstreeSysroot *sysroot,
g_autofree char * initrd_boot_relpath =
g_strconcat ("/", bootcsumdir, "/", kernel_layout->initramfs_namever, NULL);
ostree_bootconfig_parser_set (bootconfig, "initrd", initrd_boot_relpath);
+
+ if (overlay_initrds)
+ {
+ g_ptr_array_add (overlay_initrds, NULL);
+ ostree_bootconfig_parser_set_overlay_initrds (bootconfig, (char**)overlay_initrds->pdata);
+ }
}
else
{
@@ -2135,6 +2182,10 @@ deployment_bootconfigs_equal (OstreeRepo *repo,
if (strcmp (a_bootcsum, b_bootcsum) != 0)
return FALSE;
+ /* same initrd overlays? */
+ if (g_strcmp0 (a->overlay_initrds_id, b->overlay_initrds_id) != 0)
+ return FALSE;
+
/* same kargs? */
g_autofree char *a_boot_options_without_ostree = get_deployment_nonostree_kargs (a);
g_autofree char *b_boot_options_without_ostree = get_deployment_nonostree_kargs (b);
@@ -2722,6 +2773,7 @@ sysroot_initialize_deployment (OstreeSysroot *self,
_ostree_deployment_set_bootcsum (new_deployment, kernel_layout->bootcsum);
_ostree_deployment_set_bootconfig_from_kargs (new_deployment, opts ? opts->override_kernel_argv : NULL);
+ _ostree_deployment_set_overlay_initrds (new_deployment, opts ? opts->overlay_initrds : NULL);
if (!prepare_deployment_etc (self, repo, new_deployment, deployment_dfd,
cancellable, error))
@@ -2992,6 +3044,63 @@ _ostree_sysroot_deserialize_deployment_from_variant (GVariant *v,
/**
+ * ostree_sysroot_stage_overlay_initrd:
+ * @self: Sysroot
+ * @fd: (transfer none): File descriptor to overlay initrd
+ * @out_checksum: (out) (transfer full): Overlay initrd checksum
+ * @cancellable: Cancellable
+ * @error: Error
+ *
+ * Stage an overlay initrd to be used in an upcoming deployment. Returns a checksum which
+ * can be passed to ostree_sysroot_deploy_tree_with_options() or
+ * ostree_sysroot_stage_tree_with_options() via the `overlay_initrds` array option.
+ *
+ * Since: 2020.7
+ */
+gboolean
+ostree_sysroot_stage_overlay_initrd (OstreeSysroot *self,
+ int fd,
+ char **out_checksum,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_return_val_if_fail (fd != -1, FALSE);
+ g_return_val_if_fail (out_checksum != NULL, FALSE);
+
+ if (!glnx_shutil_mkdir_p_at (AT_FDCWD, _OSTREE_SYSROOT_RUNSTATE_STAGED_INITRDS_DIR,
+ 0755, cancellable, error))
+ return FALSE;
+
+ glnx_autofd int staged_initrds_dfd = -1;
+ if (!glnx_opendirat (AT_FDCWD, _OSTREE_SYSROOT_RUNSTATE_STAGED_INITRDS_DIR, FALSE,
+ &staged_initrds_dfd, error))
+ return FALSE;
+
+ g_auto(GLnxTmpfile) overlay_initrd = { 0, };
+ if (!glnx_open_tmpfile_linkable_at (staged_initrds_dfd, ".", O_WRONLY | O_CLOEXEC,
+ &overlay_initrd, error))
+ return FALSE;
+
+ char checksum[_OSTREE_SHA256_STRING_LEN+1];
+ {
+ g_autoptr(GOutputStream) output = g_unix_output_stream_new (overlay_initrd.fd, FALSE);
+ g_autoptr(GInputStream) input = g_unix_input_stream_new (fd, FALSE);
+ g_autofree guchar *digest = NULL;
+ if (!ot_gio_splice_get_checksum (output, input, &digest, cancellable, error))
+ return FALSE;
+ ot_bin2hex (checksum, (guint8*)digest, _OSTREE_SHA256_DIGEST_LEN);
+ }
+
+ if (!glnx_link_tmpfile_at (&overlay_initrd, GLNX_LINK_TMPFILE_REPLACE,
+ staged_initrds_dfd, checksum, error))
+ return FALSE;
+
+ *out_checksum = g_strdup (checksum);
+ return TRUE;
+}
+
+
+/**
* ostree_sysroot_stage_tree:
* @self: Sysroot
* @osname: (allow-none): osname to use for merge deployment
@@ -3122,6 +3231,9 @@ ostree_sysroot_stage_tree_with_options (OstreeSysroot *self,
if (opts && opts->override_kernel_argv)
g_variant_builder_add (builder, "{sv}", "kargs",
g_variant_new_strv ((const char *const*)opts->override_kernel_argv, -1));
+ if (opts && opts->overlay_initrds)
+ g_variant_builder_add (builder, "{sv}", "overlay-initrds",
+ g_variant_new_strv ((const char *const*)opts->overlay_initrds, -1));
const char *parent = dirname (strdupa (_OSTREE_SYSROOT_RUNSTATE_STAGED));
if (!glnx_shutil_mkdir_p_at (AT_FDCWD, parent, 0755, cancellable, error))