Skip to content

Commit

Permalink
Merge pull request #2155 from jlebon/pr/add-initrds
Browse files Browse the repository at this point in the history
lib/deploy: Add support for overlay initrds
  • Loading branch information
openshift-merge-robot authored Oct 2, 2020
2 parents 15878c9 + 81b13da commit 06a77bf
Show file tree
Hide file tree
Showing 13 changed files with 593 additions and 29 deletions.
5 changes: 5 additions & 0 deletions apidoc/ostree-sections.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ ostree_bootconfig_parser_write
ostree_bootconfig_parser_write_at
ostree_bootconfig_parser_set
ostree_bootconfig_parser_get
ostree_bootconfig_parser_set_overlay_initrds
ostree_bootconfig_parser_get_overlay_initrds
<SUBSECTION Standard>
OSTREE_BOOTCONFIG_PARSER
OSTREE_IS_BOOTCONFIG_PARSER
Expand Down Expand Up @@ -545,7 +547,10 @@ ostree_sysroot_write_deployments
ostree_sysroot_write_deployments_with_options
ostree_sysroot_write_origin_file
ostree_sysroot_stage_tree
ostree_sysroot_stage_tree_with_options
ostree_sysroot_stage_overlay_initrd
ostree_sysroot_deploy_tree
ostree_sysroot_deploy_tree_with_options
ostree_sysroot_get_merge_deployment
ostree_sysroot_query_deployments_for
ostree_sysroot_origin_new_from_refspec
Expand Down
5 changes: 5 additions & 0 deletions src/libostree/libostree-devel.sym
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ global:
*/
ostree_repo_static_delta_execute_offline_with_signature;
ostree_repo_static_delta_verify_signature;
ostree_bootconfig_parser_get_overlay_initrds;
ostree_bootconfig_parser_set_overlay_initrds;
ostree_sysroot_deploy_tree_with_options;
ostree_sysroot_stage_tree_with_options;
ostree_sysroot_stage_overlay_initrd;
} LIBOSTREE_2020.4;

/* Stub section for the stable release *after* this development one; don't
Expand Down
73 changes: 71 additions & 2 deletions src/libostree/ostree-bootconfig-parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ struct _OstreeBootconfigParser
const char *separators;

GHashTable *options;

/* Additional initrds; the primary initrd is in options. */
char **overlay_initrds;
};

typedef GObjectClass OstreeBootconfigParserClass;
Expand All @@ -50,6 +53,8 @@ ostree_bootconfig_parser_clone (OstreeBootconfigParser *self)
GLNX_HASH_TABLE_FOREACH_KV (self->options, const char*, k, const char*, v)
g_hash_table_replace (parser->options, g_strdup (k), g_strdup (v));

parser->overlay_initrds = g_strdupv (self->overlay_initrds);

return parser;
}

Expand All @@ -76,6 +81,8 @@ ostree_bootconfig_parser_parse_at (OstreeBootconfigParser *self,
if (!contents)
return FALSE;

g_autoptr(GPtrArray) overlay_initrds = NULL;

g_auto(GStrv) lines = g_strsplit (contents, "\n", -1);
for (char **iter = lines; *iter; iter++)
{
Expand All @@ -87,8 +94,19 @@ ostree_bootconfig_parser_parse_at (OstreeBootconfigParser *self,
items = g_strsplit_set (line, self->separators, 2);
if (g_strv_length (items) == 2 && items[0][0] != '\0')
{
g_hash_table_insert (self->options, items[0], items[1]);
g_free (items); /* Transfer ownership */
if (g_str_equal (items[0], "initrd") &&
g_hash_table_contains (self->options, "initrd"))
{
if (!overlay_initrds)
overlay_initrds = g_ptr_array_new_with_free_func (g_free);
g_ptr_array_add (overlay_initrds, items[1]);
g_free (items[0]);
}
else
{
g_hash_table_insert (self->options, items[0], items[1]);
}
g_free (items); /* Free container; we stole the elements */
}
else
{
Expand All @@ -97,6 +115,12 @@ ostree_bootconfig_parser_parse_at (OstreeBootconfigParser *self,
}
}

if (overlay_initrds)
{
g_ptr_array_add (overlay_initrds, NULL);
self->overlay_initrds = (char**)g_ptr_array_free (g_steal_pointer (&overlay_initrds), FALSE);
}

self->parsed = TRUE;

return TRUE;
Expand Down Expand Up @@ -127,6 +151,41 @@ ostree_bootconfig_parser_get (OstreeBootconfigParser *self,
return g_hash_table_lookup (self->options, key);
}

/**
* ostree_bootconfig_parser_set_overlay_initrds:
* @self: Parser
* @initrds: (array zero-terminated=1) (transfer none) (allow-none): Array of overlay
* initrds or %NULL to unset.
*
* These are rendered as additional `initrd` keys in the final bootloader configs. The
* base initrd is part of the primary keys.
*
* Since: 2020.7
*/
void
ostree_bootconfig_parser_set_overlay_initrds (OstreeBootconfigParser *self,
char **initrds)
{
g_assert (g_hash_table_contains (self->options, "initrd"));
g_strfreev (self->overlay_initrds);
self->overlay_initrds = g_strdupv (initrds);
}

/**
* ostree_bootconfig_parser_get_overlay_initrds:
* @self: Parser
*
* Returns: (array zero-terminated=1) (transfer none) (nullable): Array of initrds or %NULL
* if none are set.
*
* Since: 2020.7
*/
char**
ostree_bootconfig_parser_get_overlay_initrds (OstreeBootconfigParser *self)
{
return self->overlay_initrds;
}

static void
write_key (OstreeBootconfigParser *self,
GString *buf,
Expand Down Expand Up @@ -165,6 +224,15 @@ ostree_bootconfig_parser_write_at (OstreeBootconfigParser *self,
}
}

/* Write overlay initrds */
if (self->overlay_initrds && (g_strv_length (self->overlay_initrds) > 0))
{
/* we should've written the primary initrd already */
g_assert (g_hash_table_contains (keys_written, "initrd"));
for (char **it = self->overlay_initrds; it && *it; it++)
write_key (self, buf, "initrd", *it);
}

/* Write unknown fields */
GLNX_HASH_TABLE_FOREACH_KV (self->options, const char*, k, const char*, v)
{
Expand Down Expand Up @@ -197,6 +265,7 @@ ostree_bootconfig_parser_finalize (GObject *object)
{
OstreeBootconfigParser *self = OSTREE_BOOTCONFIG_PARSER (object);

g_strfreev (self->overlay_initrds);
g_hash_table_unref (self->options);

G_OBJECT_CLASS (ostree_bootconfig_parser_parent_class)->finalize (object);
Expand Down
6 changes: 6 additions & 0 deletions src/libostree/ostree-bootconfig-parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,11 @@ _OSTREE_PUBLIC
const char *ostree_bootconfig_parser_get (OstreeBootconfigParser *self,
const char *key);

_OSTREE_PUBLIC
void ostree_bootconfig_parser_set_overlay_initrds (OstreeBootconfigParser *self,
char **initrds);

_OSTREE_PUBLIC
char** ostree_bootconfig_parser_get_overlay_initrds (OstreeBootconfigParser *self);

G_END_DECLS
9 changes: 9 additions & 0 deletions src/libostree/ostree-deployment-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ G_BEGIN_DECLS
* @origin: How to construct an upgraded version of this tree
* @unlocked: The unlocked state
* @staged: TRUE iff this deployment is staged
* @overlay_initrds: Checksums of staged additional initrds for this deployment
* @overlay_initrds_id: Unique ID generated from initrd checksums; used to compare deployments
*/
struct _OstreeDeployment
{
Expand All @@ -52,8 +54,15 @@ struct _OstreeDeployment
GKeyFile *origin;
OstreeDeploymentUnlockedState unlocked;
gboolean staged;
char **overlay_initrds;
char *overlay_initrds_id;
};

void _ostree_deployment_set_bootcsum (OstreeDeployment *self, const char *bootcsum);

void _ostree_deployment_set_overlay_initrds (OstreeDeployment *self,
char **overlay_initrds);

char** _ostree_deployment_get_overlay_initrds (OstreeDeployment *self);

G_END_DECLS
32 changes: 32 additions & 0 deletions src/libostree/ostree-deployment.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,34 @@ _ostree_deployment_set_bootcsum (OstreeDeployment *self,
self->bootcsum = g_strdup (bootcsum);
}

void
_ostree_deployment_set_overlay_initrds (OstreeDeployment *self,
char **overlay_initrds)
{
g_clear_pointer (&self->overlay_initrds, g_strfreev);
g_clear_pointer (&self->overlay_initrds_id, g_free);

if (!overlay_initrds || g_strv_length (overlay_initrds) == 0)
return;

/* Generate a unique ID representing this combination of overlay initrds. This is so that
* ostree_sysroot_write_deployments_with_options() can easily compare initrds when
* comparing deployments for whether a bootswap is necessary. We could be fancier here but
* meh... this works. */
g_autoptr(GString) id = g_string_new (NULL);
for (char **it = overlay_initrds; it && *it; it++)
g_string_append (id, *it);

self->overlay_initrds = g_strdupv (overlay_initrds);
self->overlay_initrds_id = g_string_free (g_steal_pointer (&id), FALSE);
}

char**
_ostree_deployment_get_overlay_initrds (OstreeDeployment *self)
{
return self->overlay_initrds;
}

/**
* ostree_deployment_clone:
* @self: Deployment
Expand All @@ -175,6 +203,8 @@ ostree_deployment_clone (OstreeDeployment *self)
new_bootconfig = ostree_bootconfig_parser_clone (self->bootconfig);
ostree_deployment_set_bootconfig (ret, new_bootconfig);

_ostree_deployment_set_overlay_initrds (ret, self->overlay_initrds);

if (self->origin)
{
g_autoptr(GKeyFile) new_origin = NULL;
Expand Down Expand Up @@ -238,6 +268,8 @@ ostree_deployment_finalize (GObject *object)
g_free (self->bootcsum);
g_clear_object (&self->bootconfig);
g_clear_pointer (&self->origin, g_key_file_unref);
g_strfreev (self->overlay_initrds);
g_free (self->overlay_initrds_id);

G_OBJECT_CLASS (ostree_deployment_parent_class)->finalize (object);
}
Expand Down
43 changes: 43 additions & 0 deletions src/libostree/ostree-sysroot-cleanup.c
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,8 @@ cleanup_old_deployments (OstreeSysroot *self,
g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
g_autoptr(GHashTable) active_boot_checksums =
g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
g_autoptr(GHashTable) active_overlay_initrds =
g_hash_table_new (g_str_hash, g_str_equal); /* borrows from deployment's bootconfig */
for (guint i = 0; i < self->deployments->len; i++)
{
OstreeDeployment *deployment = self->deployments->pdata[i];
Expand All @@ -306,6 +308,11 @@ cleanup_old_deployments (OstreeSysroot *self,
/* Transfer ownership */
g_hash_table_replace (active_deployment_dirs, deployment_path, deployment_path);
g_hash_table_replace (active_boot_checksums, bootcsum, bootcsum);

OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (deployment);
char **initrds = ostree_bootconfig_parser_get_overlay_initrds (bootconfig);
for (char **it = initrds; it && *it; it++)
g_hash_table_add (active_overlay_initrds, (char*)glnx_basename (*it));
}

/* Find all deployment directories, both active and inactive */
Expand Down Expand Up @@ -349,6 +356,42 @@ cleanup_old_deployments (OstreeSysroot *self,
return FALSE;
}

/* Clean up overlay initrds */
glnx_autofd int overlays_dfd =
glnx_opendirat_with_errno (self->sysroot_fd, _OSTREE_SYSROOT_INITRAMFS_OVERLAYS, FALSE);
if (overlays_dfd < 0)
{
if (errno != ENOENT)
return glnx_throw_errno_prefix (error, "open(initrd_overlays)");
}
else
{
g_autoptr(GPtrArray) initrds_to_delete = g_ptr_array_new_with_free_func (g_free);
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
if (!glnx_dirfd_iterator_init_at (overlays_dfd, ".", TRUE, &dfd_iter, error))
return FALSE;
while (TRUE)
{
struct dirent *dent;
if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error))
return FALSE;
if (dent == NULL)
break;

/* there shouldn't be other file types there, but let's be conservative */
if (dent->d_type != DT_REG)
continue;

if (!g_hash_table_lookup (active_overlay_initrds, dent->d_name))
g_ptr_array_add (initrds_to_delete, g_strdup (dent->d_name));
}
for (guint i = 0; i < initrds_to_delete->len; i++)
{
if (!ot_ensure_unlinked_at (overlays_dfd, initrds_to_delete->pdata[i], error))
return FALSE;
}
}

return TRUE;
}

Expand Down
Loading

0 comments on commit 06a77bf

Please sign in to comment.