rebase: Add support for "custom origin" descriptions
We're looking to embed an ostree commit inside a container image,
to make it easier to transport around with other images.
Conceptually here the host system is tracking a container (just
like for rojig we're tracking an RPM). This is the first step
towards making that support nicer; tooling can do
`rebase --custom-origin-url oscontainer://quay.io/exampleos@sha256:...`
and have that show up in `rpm-ostree status`.
There are two values, one intended to be machine readable (like
the `ostree://` and `rojig://` and one for humans which we
display when an admin types `rpm-ostree upgrade`.
This builds on prior work in
27bd7b97bb
from #1396 .
Closes: #1406
Approved by: jlebon
This commit is contained in:
parent
95de58c29d
commit
096004426c
@ -36,6 +36,8 @@ static gboolean opt_reboot;
|
||||
static gboolean opt_skip_purge;
|
||||
static char * opt_branch;
|
||||
static char * opt_remote;
|
||||
static char * opt_custom_origin_url;
|
||||
static char * opt_custom_origin_description;
|
||||
static gboolean opt_cache_only;
|
||||
static gboolean opt_download_only;
|
||||
static gboolean opt_experimental;
|
||||
@ -48,6 +50,8 @@ static GOptionEntry option_entries[] = {
|
||||
{ "skip-purge", 0, 0, G_OPTION_ARG_NONE, &opt_skip_purge, "Keep previous refspec after rebase", NULL },
|
||||
{ "cache-only", 'C', 0, G_OPTION_ARG_NONE, &opt_cache_only, "Do not download latest ostree and RPM data", NULL },
|
||||
{ "download-only", 0, 0, G_OPTION_ARG_NONE, &opt_download_only, "Just download latest ostree and RPM data, don't deploy", NULL },
|
||||
{ "custom-origin-description", 0, 0, G_OPTION_ARG_STRING, &opt_custom_origin_description, "Human-readable description of custom origin", NULL },
|
||||
{ "custom-origin-url", 0, 0, G_OPTION_ARG_STRING, &opt_custom_origin_url, "Machine-readable description of custom origin", NULL },
|
||||
{ "experimental", 0, 0, G_OPTION_ARG_NONE, &opt_experimental, "Enable experimental features", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
@ -138,6 +142,14 @@ rpmostree_builtin_rebase (int argc,
|
||||
g_variant_dict_insert (&dict, "cache-only", "b", opt_cache_only);
|
||||
g_variant_dict_insert (&dict, "download-only", "b", opt_download_only);
|
||||
g_variant_dict_insert (&dict, "skip-purge", "b", opt_skip_purge);
|
||||
if (opt_custom_origin_url)
|
||||
{
|
||||
if (!opt_custom_origin_description)
|
||||
return glnx_throw (error, "--custom-origin-description must be supplied with --custom-origin-url");
|
||||
g_variant_dict_insert (&dict, "custom-origin", "(ss)",
|
||||
opt_custom_origin_url,
|
||||
opt_custom_origin_description);
|
||||
}
|
||||
g_autoptr(GVariant) options = g_variant_ref_sink (g_variant_dict_end (&dict));
|
||||
|
||||
/* Use newer D-Bus API only if we have to. */
|
||||
|
@ -480,6 +480,8 @@ print_one_deployment (RPMOSTreeSysroot *sysroot_proxy,
|
||||
g_print ("%s ", is_booted ? libsd_special_glyph (BLACK_CIRCLE) : " ");
|
||||
|
||||
RpmOstreeRefspecType refspectype = RPMOSTREE_REFSPEC_TYPE_OSTREE;
|
||||
const char *custom_origin_url = NULL;
|
||||
const char *custom_origin_description = NULL;
|
||||
if (origin_refspec)
|
||||
{
|
||||
const char *refspec_data;
|
||||
@ -489,6 +491,22 @@ print_one_deployment (RPMOSTreeSysroot *sysroot_proxy,
|
||||
switch (refspectype)
|
||||
{
|
||||
case RPMOSTREE_REFSPEC_TYPE_CHECKSUM:
|
||||
{
|
||||
g_variant_dict_lookup (dict, "custom-origin", "(&s&s)",
|
||||
&custom_origin_url,
|
||||
&custom_origin_description);
|
||||
/* Canonicalize the empty string to NULL */
|
||||
if (custom_origin_url && !*custom_origin_url)
|
||||
custom_origin_url = NULL;
|
||||
if (custom_origin_url)
|
||||
{
|
||||
g_assert (custom_origin_description && *custom_origin_description);
|
||||
g_print ("%s", custom_origin_url);
|
||||
}
|
||||
else
|
||||
g_print ("%s", canonrefspec);
|
||||
}
|
||||
break;
|
||||
case RPMOSTREE_REFSPEC_TYPE_OSTREE:
|
||||
{
|
||||
g_print ("%s", canonrefspec);
|
||||
@ -526,6 +544,9 @@ print_one_deployment (RPMOSTreeSysroot *sysroot_proxy,
|
||||
g_print ("%s", checksum);
|
||||
g_print ("\n");
|
||||
|
||||
if (custom_origin_description)
|
||||
rpmostree_print_kv ("CustomOrigin", max_key_len, custom_origin_description);
|
||||
|
||||
const char *remote_not_found = NULL;
|
||||
g_variant_dict_lookup (dict, "remote-error", "s", &remote_not_found);
|
||||
if (remote_not_found)
|
||||
|
@ -291,6 +291,7 @@
|
||||
"override-reset-packages" (type 'as')
|
||||
"override-replace-packages" (type 'as')
|
||||
"override-replace-local-packages" (type 'ah')
|
||||
"custom-origin" (type '(ss)')
|
||||
|
||||
Available options:
|
||||
"reboot" (type 'b')
|
||||
|
@ -304,7 +304,16 @@ rpmostreed_deployment_generate_variant (OstreeSysroot *sysroot,
|
||||
switch (refspec_type)
|
||||
{
|
||||
case RPMOSTREE_REFSPEC_TYPE_CHECKSUM:
|
||||
/* Nothing to do here */
|
||||
{
|
||||
g_autofree char *custom_origin_url = NULL;
|
||||
g_autofree char *custom_origin_description = NULL;
|
||||
rpmostree_origin_get_custom_description (origin, &custom_origin_url,
|
||||
&custom_origin_description);
|
||||
if (custom_origin_url)
|
||||
g_variant_dict_insert (&dict, "custom-origin", "(ss)",
|
||||
custom_origin_url,
|
||||
custom_origin_description);
|
||||
}
|
||||
break;
|
||||
case RPMOSTREE_REFSPEC_TYPE_OSTREE:
|
||||
{
|
||||
|
@ -42,7 +42,8 @@ vardict_lookup_bool (GVariantDict *dict,
|
||||
gboolean dfault);
|
||||
|
||||
static gboolean
|
||||
change_origin_refspec (OstreeSysroot *sysroot,
|
||||
change_origin_refspec (GVariantDict *options,
|
||||
OstreeSysroot *sysroot,
|
||||
RpmOstreeOrigin *origin,
|
||||
const gchar *src_refspec,
|
||||
GCancellable *cancellable,
|
||||
@ -101,9 +102,35 @@ change_origin_refspec (OstreeSysroot *sysroot,
|
||||
if (strcmp (current_refspec, new_refspec) == 0)
|
||||
return glnx_throw (error, "Old and new refs are equal: %s", new_refspec);
|
||||
|
||||
if (!rpmostree_origin_set_rebase (origin, new_refspec, error))
|
||||
/* Re-classify after canonicalization to ensure we handle TYPE_CHECKSUM */
|
||||
if (!rpmostree_refspec_classify (new_refspec, &refspectype, &refspecdata, error))
|
||||
return FALSE;
|
||||
|
||||
if (refspectype == RPMOSTREE_REFSPEC_TYPE_CHECKSUM)
|
||||
{
|
||||
const char *custom_origin_url = NULL;
|
||||
const char *custom_origin_description = NULL;
|
||||
g_variant_dict_lookup (options, "custom-origin", "(&s&s)",
|
||||
&custom_origin_url,
|
||||
&custom_origin_description);
|
||||
if (custom_origin_url && *custom_origin_url)
|
||||
{
|
||||
g_assert (custom_origin_description);
|
||||
if (!*custom_origin_description)
|
||||
return glnx_throw (error, "Invalid custom-origin");
|
||||
}
|
||||
if (!rpmostree_origin_set_rebase_custom (origin, new_refspec,
|
||||
custom_origin_url,
|
||||
custom_origin_description,
|
||||
error))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!rpmostree_origin_set_rebase (origin, new_refspec, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_autofree gchar *current_remote = NULL;
|
||||
g_autofree gchar *current_branch = NULL;
|
||||
g_assert (ostree_parse_refspec (current_refspec, ¤t_remote, ¤t_branch, NULL));
|
||||
@ -305,7 +332,7 @@ package_diff_transaction_execute (RpmostreedTransaction *transaction,
|
||||
|
||||
if (self->refspec != NULL)
|
||||
{
|
||||
if (!change_origin_refspec (sysroot, origin, self->refspec,
|
||||
if (!change_origin_refspec (NULL, sysroot, origin, self->refspec,
|
||||
cancellable, NULL, NULL, error))
|
||||
return FALSE;
|
||||
}
|
||||
@ -828,7 +855,7 @@ deploy_transaction_execute (RpmostreedTransaction *transaction,
|
||||
g_autofree gchar *old_refspec = NULL;
|
||||
if (self->refspec)
|
||||
{
|
||||
if (!change_origin_refspec (sysroot, origin, self->refspec, cancellable,
|
||||
if (!change_origin_refspec (self->options, sysroot, origin, self->refspec, cancellable,
|
||||
&old_refspec, &new_refspec, error))
|
||||
return FALSE;
|
||||
}
|
||||
@ -1304,7 +1331,16 @@ deploy_transaction_execute (RpmostreedTransaction *transaction,
|
||||
{
|
||||
if (refspec_type == RPMOSTREE_REFSPEC_TYPE_CHECKSUM
|
||||
&& layering_type < RPMOSTREE_SYSROOT_UPGRADER_LAYERING_RPMMD_REPOS)
|
||||
rpmostree_output_message ("Pinned to commit; no upgrade available");
|
||||
{
|
||||
g_autofree char *custom_origin_url = NULL;
|
||||
g_autofree char *custom_origin_description = NULL;
|
||||
rpmostree_origin_get_custom_description (origin, &custom_origin_url,
|
||||
&custom_origin_description);
|
||||
if (custom_origin_description)
|
||||
rpmostree_output_message ("Pinned to commit by custom origin: %s", custom_origin_description);
|
||||
else
|
||||
rpmostree_output_message ("Pinned to commit; no upgrade available");
|
||||
}
|
||||
else if (is_upgrade)
|
||||
rpmostree_output_message ("No upgrade available.");
|
||||
else
|
||||
|
@ -265,6 +265,25 @@ rpmostree_origin_get_rojig_description (RpmOstreeOrigin *origin)
|
||||
return g_variant_builder_end (builder);
|
||||
}
|
||||
|
||||
static char *
|
||||
keyfile_get_nonempty_string (GKeyFile *kf, const char *section, const char *key)
|
||||
{
|
||||
char *ret = g_key_file_get_string (kf, section, key, NULL);
|
||||
if (ret && !*ret)
|
||||
g_clear_pointer (&ret, g_free);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
rpmostree_origin_get_custom_description (RpmOstreeOrigin *origin,
|
||||
char **custom_type,
|
||||
char **custom_description)
|
||||
{
|
||||
*custom_type = keyfile_get_nonempty_string (origin->kf, "origin", "custom-url");
|
||||
if (*custom_type)
|
||||
*custom_description = keyfile_get_nonempty_string (origin->kf, "origin", "custom-description");
|
||||
}
|
||||
|
||||
GHashTable *
|
||||
rpmostree_origin_get_packages (RpmOstreeOrigin *origin)
|
||||
{
|
||||
@ -469,11 +488,20 @@ rpmostree_origin_set_rojig_description (RpmOstreeOrigin *origin,
|
||||
}
|
||||
|
||||
gboolean
|
||||
rpmostree_origin_set_rebase (RpmOstreeOrigin *origin,
|
||||
const char *new_refspec,
|
||||
GError **error)
|
||||
rpmostree_origin_set_rebase_custom (RpmOstreeOrigin *origin,
|
||||
const char *new_refspec,
|
||||
const char *custom_origin_url,
|
||||
const char *custom_origin_description,
|
||||
GError **error)
|
||||
{
|
||||
/* We don't want to carry any commit overrides or version pinning during a
|
||||
/* Require non-empty strings */
|
||||
if (custom_origin_url)
|
||||
{
|
||||
g_return_val_if_fail (*custom_origin_url, FALSE);
|
||||
g_return_val_if_fail (custom_origin_description && *custom_origin_description, FALSE);
|
||||
}
|
||||
|
||||
/* We don't want to carry any commit overrides or version pinning during a
|
||||
* rebase by default.
|
||||
*/
|
||||
rpmostree_origin_set_override_commit (origin, NULL, NULL);
|
||||
@ -497,13 +525,29 @@ rpmostree_origin_set_rebase (RpmOstreeOrigin *origin,
|
||||
g_key_file_has_key (origin->kf, "origin", "baserefspec", NULL) ?
|
||||
"baserefspec" : "refspec";
|
||||
g_key_file_set_string (origin->kf, "origin", refspec_key, origin->cached_refspec);
|
||||
if (!custom_origin_url)
|
||||
{
|
||||
g_key_file_remove_key (origin->kf, "origin", "custom-url", NULL);
|
||||
g_key_file_remove_key (origin->kf, "origin", "custom-description", NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Custom origins have to be checksums */
|
||||
g_assert_cmpint (origin->refspec_type, ==, RPMOSTREE_REFSPEC_TYPE_CHECKSUM);
|
||||
g_key_file_set_string (origin->kf, "origin", "custom-url", custom_origin_url);
|
||||
if (custom_origin_description)
|
||||
g_key_file_set_string (origin->kf, "origin", "custom-description", custom_origin_description);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case RPMOSTREE_REFSPEC_TYPE_ROJIG:
|
||||
{
|
||||
g_assert (!custom_origin_url);
|
||||
origin->cached_refspec = g_strdup (refspecdata);
|
||||
g_key_file_remove_key (origin->kf, "origin", "refspec", NULL);
|
||||
g_key_file_remove_key (origin->kf, "origin", "baserefspec", NULL);
|
||||
g_key_file_remove_key (origin->kf, "origin", "custom-url", NULL);
|
||||
g_key_file_remove_key (origin->kf, "origin", "custom-description", NULL);
|
||||
/* Peeled */
|
||||
g_key_file_set_string (origin->kf, "origin", "rojig", origin->cached_refspec);
|
||||
}
|
||||
@ -513,6 +557,14 @@ rpmostree_origin_set_rebase (RpmOstreeOrigin *origin,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
rpmostree_origin_set_rebase (RpmOstreeOrigin *origin,
|
||||
const char *new_refspec,
|
||||
GError **error)
|
||||
{
|
||||
return rpmostree_origin_set_rebase_custom (origin, new_refspec, NULL, NULL, error);
|
||||
}
|
||||
|
||||
/* Like g_key_file_set_string(), but remove the key if @value is NULL */
|
||||
static void
|
||||
set_or_unset_str (GKeyFile *kf,
|
||||
|
@ -75,6 +75,11 @@ rpmostree_origin_get_rojig_version (RpmOstreeOrigin *origin);
|
||||
GVariant *
|
||||
rpmostree_origin_get_rojig_description (RpmOstreeOrigin *origin);
|
||||
|
||||
void
|
||||
rpmostree_origin_get_custom_description (RpmOstreeOrigin *origin,
|
||||
char **custom_type,
|
||||
char **custom_description);
|
||||
|
||||
GHashTable *
|
||||
rpmostree_origin_get_packages (RpmOstreeOrigin *origin);
|
||||
|
||||
@ -136,6 +141,12 @@ gboolean
|
||||
rpmostree_origin_set_rebase (RpmOstreeOrigin *origin,
|
||||
const char *new_refspec,
|
||||
GError **error);
|
||||
gboolean
|
||||
rpmostree_origin_set_rebase_custom (RpmOstreeOrigin *origin,
|
||||
const char *new_refspec,
|
||||
const char *custom_origin_url,
|
||||
const char *custom_origin_description,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
rpmostree_origin_add_packages (RpmOstreeOrigin *origin,
|
||||
|
@ -26,6 +26,24 @@ set -x
|
||||
|
||||
# More miscellaneous tests
|
||||
|
||||
# Custom origin https://github.com/projectatomic/rpm-ostree/pull/1406
|
||||
booted_csum=$(vm_get_booted_csum)
|
||||
oscontainer_source="oscontainer://quay.io/exampleos@sha256:98ea6e4f216f2fb4b69fff9b3a44842c38686ca685f3f55dc48c5d3fb1107be4"
|
||||
if vm_rpmostree rebase --skip-purge --custom-origin-url "${oscontainer_source}" \
|
||||
:${booted_csum} 2>err.txt; then
|
||||
fatal "rebased without description"
|
||||
fi
|
||||
assert_file_has_content_literal err.txt '--custom-origin-description must be supplied'
|
||||
vm_rpmostree rebase --skip-purge --custom-origin-description "'Updated via pivot'" \
|
||||
--custom-origin-url "${oscontainer_source}" \
|
||||
:${booted_csum}
|
||||
vm_rpmostree status > status.txt
|
||||
assert_file_has_content_literal status.txt 'CustomOrigin: Updated via pivot'
|
||||
assert_file_has_content_literal status.txt "${oscontainer_source}"
|
||||
vm_rpmostree upgrade >out.txt
|
||||
assert_file_has_content_literal out.txt 'Pinned to commit by custom origin: Updated via pivot'
|
||||
vm_rpmostree cleanup -p
|
||||
|
||||
# Add metadata string containing EnfOfLife attribtue
|
||||
META_ENDOFLIFE_MESSAGE="this is a test for metadata message"
|
||||
commit=$(vm_cmd ostree commit -b vmcheck \
|
||||
|
Loading…
Reference in New Issue
Block a user