compose: Support "preserve-passwd" option (enabled by default)
The checking code from #56 landed, and started triggering for me on the `dockerroot` user. It's nice to know it works. Then the issue is... "what now"? It turns out in the case of `dockerroot` it's actually unused, so we could fix this by deleting it. But in general we need to support dynamic uids/gids/. And we can't yet take a hard dep on #49. So this patch changes things so we take a copy of the passwd/group data from the previous commit. Any users subsequently added in the *new* commit will be additive. Closes: https://github.com/projectatomic/rpm-ostree/issues/78
This commit is contained in:
parent
fc1a4b05fa
commit
f9e9c06648
@ -61,6 +61,13 @@ Treefile
|
||||
|
||||
Note this does not alter the RPM database, so `rpm -V` will complain.
|
||||
|
||||
* `preserve-passwd`: boolean, optional: Defaults to `true`. If enabled,
|
||||
copy the `/etc/passwd` (and `/usr/lib/passwd`) files from the previous commit
|
||||
if they exist. This helps ensure consistent uid/gid allocations across
|
||||
builds. However, it does mean that removed users will exist in the `passwd`
|
||||
database forever. It also does not help clients switch between unrelated
|
||||
trees.
|
||||
|
||||
* `check-passwd`: Object, optional: Checks to run against the new passwd file
|
||||
before accepting the tree. All the entries specified should exist (unless
|
||||
ignored) and have the same values or the compose will fail. There are four
|
||||
|
@ -940,6 +940,23 @@ rpmostree_compose_builtin_tree (int argc,
|
||||
self->serialized_treefile = g_bytes_new_take (treefile_buf, len);
|
||||
}
|
||||
|
||||
{
|
||||
gboolean generate_from_previous = TRUE;
|
||||
|
||||
if (!_rpmostree_jsonutil_object_get_optional_boolean_member (treefile,
|
||||
"preserve-passwd",
|
||||
&generate_from_previous,
|
||||
error))
|
||||
goto out;
|
||||
|
||||
if (generate_from_previous)
|
||||
{
|
||||
if (!rpmostree_generate_passwd_from_previous (repo, yumroot, ref,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!yuminstall (self, treefile, yumroot,
|
||||
(char**)packages->pdata,
|
||||
cancellable, error))
|
||||
|
@ -133,6 +133,31 @@ _rpmostree_jsonutil_object_require_int_member (JsonObject *object,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
_rpmostree_jsonutil_object_get_optional_boolean_member (JsonObject *object,
|
||||
const char *member_name,
|
||||
gboolean *out_value,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
JsonNode *node = json_object_get_member (object, member_name);
|
||||
|
||||
if (node != NULL)
|
||||
{
|
||||
if (json_node_get_value_type (node) != G_TYPE_BOOLEAN)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Member '%s' is not a boolean", member_name);
|
||||
goto out;
|
||||
}
|
||||
*out_value = json_node_get_boolean (node);
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char *
|
||||
_rpmostree_jsonutil_array_require_string_element (JsonArray *array,
|
||||
guint i,
|
||||
|
@ -47,6 +47,12 @@ _rpmostree_jsonutil_object_require_int_member (JsonObject *object,
|
||||
gint64 *out_val,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
_rpmostree_jsonutil_object_get_optional_boolean_member (JsonObject *object,
|
||||
const char *member_name,
|
||||
gboolean *out_value,
|
||||
GError **error);
|
||||
|
||||
const char *
|
||||
_rpmostree_jsonutil_array_require_string_element (JsonArray *array,
|
||||
guint i,
|
||||
|
@ -667,3 +667,106 @@ rpmostree_check_groups (OstreeRepo *repo,
|
||||
return rpmostree_check_passwd_groups (TRUE, repo, yumroot, treefile_dirpath,
|
||||
treedata, cancellable, error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
concat_passwd_file (GFile *yumroot,
|
||||
GFile *previous_commit,
|
||||
const char *filename,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
gs_free char *etc_subpath = g_strconcat ("etc/", filename, NULL);
|
||||
gs_free char *usrlib_subpath = g_strconcat ("usr/lib/", filename, NULL);
|
||||
gs_unref_object GFile *yumroot_etc = g_file_resolve_relative_path (yumroot, "etc");
|
||||
gs_unref_object GFile *yumroot_dest = g_file_resolve_relative_path (yumroot, etc_subpath);
|
||||
gs_unref_object GFile *orig_etc_content = g_file_resolve_relative_path (previous_commit, etc_subpath);
|
||||
gs_unref_object GFile *orig_usrlib_content = g_file_resolve_relative_path (previous_commit, usrlib_subpath);
|
||||
gs_unref_object GFileOutputStream *out = NULL;
|
||||
gboolean have_etc, have_usr;
|
||||
|
||||
if (!gs_file_ensure_directory (yumroot_etc, TRUE, cancellable, error))
|
||||
goto out;
|
||||
|
||||
have_etc = g_file_query_exists (orig_etc_content, NULL);
|
||||
have_usr = g_file_query_exists (orig_usrlib_content, NULL);
|
||||
|
||||
if (!(have_etc || have_usr))
|
||||
{
|
||||
ret = TRUE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out = g_file_replace (yumroot_dest, NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION,
|
||||
cancellable, error);
|
||||
if (!out)
|
||||
goto out;
|
||||
|
||||
if (have_etc)
|
||||
{
|
||||
gs_unref_object GInputStream *src =
|
||||
(GInputStream*)g_file_read (orig_etc_content, cancellable, error);
|
||||
if (g_output_stream_splice ((GOutputStream*)out, src,
|
||||
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
|
||||
cancellable, error ) < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (have_usr)
|
||||
{
|
||||
gs_unref_object GInputStream *src =
|
||||
(GInputStream*)g_file_read (orig_usrlib_content, cancellable, error);
|
||||
if (g_output_stream_splice ((GOutputStream*)out, src,
|
||||
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
|
||||
cancellable, error ) < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!g_output_stream_flush ((GOutputStream*)out, cancellable, error))
|
||||
goto out;
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
gboolean
|
||||
rpmostree_generate_passwd_from_previous (OstreeRepo *repo,
|
||||
GFile *yumroot,
|
||||
const char *ref,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
GError *temp_error = NULL;
|
||||
gs_unref_object GFile *previous_root = NULL;
|
||||
gs_unref_object GFile *yumroot_etc_group = g_file_resolve_relative_path (yumroot, "etc/group");
|
||||
gs_unref_object GFile *out = NULL;
|
||||
|
||||
if (!ostree_repo_read_commit (repo, ref, &previous_root, NULL, NULL, &temp_error))
|
||||
{
|
||||
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
||||
{
|
||||
g_clear_error (&temp_error);
|
||||
ret = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_propagate_error (error, temp_error);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!concat_passwd_file (yumroot, previous_root, "passwd",
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (!concat_passwd_file (yumroot, previous_root, "group",
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
@ -39,3 +39,10 @@ rpmostree_check_groups (OstreeRepo *repo,
|
||||
JsonObject *treedata,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
rpmostree_generate_passwd_from_previous (OstreeRepo *repo,
|
||||
GFile *yumroot,
|
||||
const char *ref,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
Loading…
x
Reference in New Issue
Block a user