Merge pull request #2434 from cgwalters/custom-remote

Add support for "custom remotes"
This commit is contained in:
Colin Walters 2021-09-08 09:27:26 -04:00 committed by GitHub
commit ce36e05d38
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 93 additions and 22 deletions

View File

@ -355,6 +355,14 @@ Boston, MA 02111-1307, USA.
<listitem><para>If set, pulls from this remote will fail with the configured text. This is intended for OS vendors which have a subscription process to access content.</para></listitem> <listitem><para>If set, pulls from this remote will fail with the configured text. This is intended for OS vendors which have a subscription process to access content.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>custom-backend</varname></term>
<listitem><para>If set, pulls from this remote via libostree will fail with an error that mentions the value.
It is recommended to make this a software identifier token (e.g. "examplecorp-fetcher"), not freeform text ("ExampleCorp Fetcher").
This is intended to be used by higher level software that wants to fetch ostree commits via some other mechanism, while still reusing the core libostree infrastructure around e.g. signatures.
</para></listitem>
</varlistentry>
</variablelist> </variablelist>
</refsect1> </refsect1>

View File

@ -3965,6 +3965,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
else else
{ {
g_autofree char *unconfigured_state = NULL; g_autofree char *unconfigured_state = NULL;
g_autofree char *custom_backend = NULL;
g_free (pull_data->remote_name); g_free (pull_data->remote_name);
pull_data->remote_name = g_strdup (remote_name_or_baseurl); pull_data->remote_name = g_strdup (remote_name_or_baseurl);
@ -3996,6 +3997,20 @@ ostree_repo_pull_with_options (OstreeRepo *self,
"remote unconfigured-state: %s", unconfigured_state); "remote unconfigured-state: %s", unconfigured_state);
goto out; goto out;
} }
if (!ostree_repo_get_remote_option (self, pull_data->remote_name,
"custom-backend", NULL,
&custom_backend,
error))
goto out;
if (custom_backend)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Cannot fetch via libostree - remote '%s' uses custom backend '%s'",
pull_data->remote_name, custom_backend);
goto out;
}
} }
if (pull_data->remote_name && !(disable_sign_verify && disable_sign_verify_summary)) if (pull_data->remote_name && !(disable_sign_verify && disable_sign_verify_summary))

View File

@ -1589,7 +1589,6 @@ impl_repo_remote_add (OstreeRepo *self,
GError **error) GError **error)
{ {
g_return_val_if_fail (name != NULL, FALSE); g_return_val_if_fail (name != NULL, FALSE);
g_return_val_if_fail (url != NULL, FALSE);
g_return_val_if_fail (options == NULL || g_variant_is_of_type (options, G_VARIANT_TYPE ("a{sv}")), FALSE); g_return_val_if_fail (options == NULL || g_variant_is_of_type (options, G_VARIANT_TYPE ("a{sv}")), FALSE);
if (!ostree_validate_remote_name (name, error)) if (!ostree_validate_remote_name (name, error))
@ -1637,10 +1636,13 @@ impl_repo_remote_add (OstreeRepo *self,
remote->file = g_file_get_child (etc_ostree_remotes_d, basename); remote->file = g_file_get_child (etc_ostree_remotes_d, basename);
} }
if (url)
{
if (g_str_has_prefix (url, "metalink=")) if (g_str_has_prefix (url, "metalink="))
g_key_file_set_string (remote->options, remote->group, "metalink", url + strlen ("metalink=")); g_key_file_set_string (remote->options, remote->group, "metalink", url + strlen ("metalink="));
else else
g_key_file_set_string (remote->options, remote->group, "url", url); g_key_file_set_string (remote->options, remote->group, "url", url);
}
if (options) if (options)
keyfile_set_from_vardict (remote->options, remote->group, options); keyfile_set_from_vardict (remote->options, remote->group, options);
@ -1676,7 +1678,7 @@ impl_repo_remote_add (OstreeRepo *self,
* ostree_repo_remote_add: * ostree_repo_remote_add:
* @self: Repo * @self: Repo
* @name: Name of remote * @name: Name of remote
* @url: URL for remote (if URL begins with metalink=, it will be used as such) * @url: (allow-none): URL for remote (if URL begins with metalink=, it will be used as such)
* @options: (allow-none): GVariant of type a{sv} * @options: (allow-none): GVariant of type a{sv}
* @cancellable: Cancellable * @cancellable: Cancellable
* @error: Error * @error: Error
@ -1789,7 +1791,6 @@ impl_repo_remote_replace (OstreeRepo *self,
GError **error) GError **error)
{ {
g_return_val_if_fail (name != NULL, FALSE); g_return_val_if_fail (name != NULL, FALSE);
g_return_val_if_fail (url != NULL, FALSE);
g_return_val_if_fail (options == NULL || g_variant_is_of_type (options, G_VARIANT_TYPE ("a{sv}")), FALSE); g_return_val_if_fail (options == NULL || g_variant_is_of_type (options, G_VARIANT_TYPE ("a{sv}")), FALSE);
if (!ostree_validate_remote_name (name, error)) if (!ostree_validate_remote_name (name, error))
@ -1815,11 +1816,14 @@ impl_repo_remote_replace (OstreeRepo *self,
if (!g_key_file_remove_group (remote->options, remote->group, error)) if (!g_key_file_remove_group (remote->options, remote->group, error))
return FALSE; return FALSE;
if (url)
{
if (g_str_has_prefix (url, "metalink=")) if (g_str_has_prefix (url, "metalink="))
g_key_file_set_string (remote->options, remote->group, "metalink", g_key_file_set_string (remote->options, remote->group, "metalink",
url + strlen ("metalink=")); url + strlen ("metalink="));
else else
g_key_file_set_string (remote->options, remote->group, "url", url); g_key_file_set_string (remote->options, remote->group, "url", url);
}
if (options != NULL) if (options != NULL)
keyfile_set_from_vardict (remote->options, remote->group, options); keyfile_set_from_vardict (remote->options, remote->group, options);
@ -1866,7 +1870,7 @@ impl_repo_remote_replace (OstreeRepo *self,
* @sysroot: (allow-none): System root * @sysroot: (allow-none): System root
* @changeop: Operation to perform * @changeop: Operation to perform
* @name: Name of remote * @name: Name of remote
* @url: URL for remote (if URL begins with metalink=, it will be used as such) * @url: (allow-none): URL for remote (if URL begins with metalink=, it will be used as such)
* @options: (allow-none): GVariant of type a{sv} * @options: (allow-none): GVariant of type a{sv}
* @cancellable: Cancellable * @cancellable: Cancellable
* @error: Error * @error: Error

View File

@ -35,6 +35,7 @@ static char *opt_gpg_import;
static char **opt_sign_verify; static char **opt_sign_verify;
static char *opt_contenturl; static char *opt_contenturl;
static char *opt_collection_id; static char *opt_collection_id;
static char *opt_custom_backend;
static char *opt_sysroot; static char *opt_sysroot;
static char *opt_repo; static char *opt_repo;
@ -51,6 +52,7 @@ static GOptionEntry option_entries[] = {
{ "if-not-exists", 0, 0, G_OPTION_ARG_NONE, &opt_if_not_exists, "Do nothing if the provided remote exists", NULL }, { "if-not-exists", 0, 0, G_OPTION_ARG_NONE, &opt_if_not_exists, "Do nothing if the provided remote exists", NULL },
{ "force", 0, 0, G_OPTION_ARG_NONE, &opt_force, "Replace the provided remote if it exists", NULL }, { "force", 0, 0, G_OPTION_ARG_NONE, &opt_force, "Replace the provided remote if it exists", NULL },
{ "gpg-import", 0, 0, G_OPTION_ARG_FILENAME, &opt_gpg_import, "Import GPG key from FILE", "FILE" }, { "gpg-import", 0, 0, G_OPTION_ARG_FILENAME, &opt_gpg_import, "Import GPG key from FILE", "FILE" },
{ "custom-backend", 0, 0, G_OPTION_ARG_STRING, &opt_custom_backend, "This remote has content not fetched via libostree", "NAME" },
{ "contenturl", 0, 0, G_OPTION_ARG_STRING, &opt_contenturl, "Use URL when fetching content", "URL" }, { "contenturl", 0, 0, G_OPTION_ARG_STRING, &opt_contenturl, "Use URL when fetching content", "URL" },
{ "collection-id", 0, 0, G_OPTION_ARG_STRING, &opt_collection_id, { "collection-id", 0, 0, G_OPTION_ARG_STRING, &opt_collection_id,
"Globally unique ID for this repository as an collection of refs for redistribution to other repositories", "COLLECTION-ID" }, "Globally unique ID for this repository as an collection of refs for redistribution to other repositories", "COLLECTION-ID" },
@ -103,7 +105,7 @@ ot_remote_builtin_add (int argc, char **argv, OstreeCommandInvocation *invocatio
g_autoptr(OstreeRepo) repo = NULL; g_autoptr(OstreeRepo) repo = NULL;
g_autoptr(GString) sign_verify = NULL; g_autoptr(GString) sign_verify = NULL;
const char *remote_name; const char *remote_name;
const char *remote_url; const char *remote_url = NULL;
g_autoptr(GVariantBuilder) optbuilder = NULL; g_autoptr(GVariantBuilder) optbuilder = NULL;
g_autoptr(GVariant) options = NULL; g_autoptr(GVariant) options = NULL;
gboolean ret = FALSE; gboolean ret = FALSE;
@ -119,11 +121,26 @@ ot_remote_builtin_add (int argc, char **argv, OstreeCommandInvocation *invocatio
cancellable, error)) cancellable, error))
goto out; goto out;
if (opt_custom_backend)
{
if (argc < 2)
{
ot_util_usage_error (context, "NAME must be specified", error);
goto out;
}
if (argc >= 3)
remote_url = argv[2];
}
else
{
if (argc < 3) if (argc < 3)
{ {
ot_util_usage_error (context, "NAME and URL must be specified", error); ot_util_usage_error (context, "NAME and URL must be specified", error);
goto out; goto out;
} }
remote_url = argv[2];
}
remote_name = argv[1];
if (opt_if_not_exists && opt_force) if (opt_if_not_exists && opt_force)
{ {
@ -133,9 +150,6 @@ ot_remote_builtin_add (int argc, char **argv, OstreeCommandInvocation *invocatio
goto out; goto out;
} }
remote_name = argv[1];
remote_url = argv[2];
optbuilder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); optbuilder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
if (argc > 3) if (argc > 3)
@ -159,6 +173,9 @@ ot_remote_builtin_add (int argc, char **argv, OstreeCommandInvocation *invocatio
if (opt_contenturl != NULL) if (opt_contenturl != NULL)
g_variant_builder_add (optbuilder, "{s@v}", g_variant_builder_add (optbuilder, "{s@v}",
"contenturl", g_variant_new_variant (g_variant_new_string (opt_contenturl))); "contenturl", g_variant_new_variant (g_variant_new_string (opt_contenturl)));
if (opt_custom_backend != NULL)
g_variant_builder_add (optbuilder, "{s@v}",
"custom-backend", g_variant_new_variant (g_variant_new_string (opt_custom_backend)));
for (char **iter = opt_set; iter && *iter; iter++) for (char **iter = opt_set; iter && *iter; iter++)
{ {

View File

@ -55,10 +55,10 @@ function verify_initial_contents() {
} }
if has_gpgme; then if has_gpgme; then
echo "1..37" echo "1..38"
else else
# 3 tests needs GPG support # 3 tests needs GPG support
echo "1..34" echo "1..35"
fi fi
# Try both syntaxes # Try both syntaxes
@ -598,6 +598,33 @@ assert_file_has_content err.txt "ONE BILLION DOLLARS"
echo "ok unconfigured" echo "ok unconfigured"
cd ${test_tmpdir}
${CMD_PREFIX} ostree --repo=repo remote add --custom-backend=ostree-rs-ext fromcontainer
if ${CMD_PREFIX} ostree --repo=repo pull fromcontainer 2>err.txt; then
assert_not_reached "pull unexpectedly succeeded?"
fi
assert_file_has_content err.txt "remote 'fromcontainer' uses custom backend 'ostree-rs-ext'"
for x in show-url refs; do
if ${CMD_PREFIX} ostree --repo=repo remote "$x" fromcontainer 2>err.txt; then
assert_file_has_content err.txt "remote 'fromcontainer' uses custom backend 'ostree-rs-ext'"
assert_not_reached "no url expected"
fi
assert_file_has_content err.txt "No \"url\" option in remote"
done
${CMD_PREFIX} ostree --repo=repo remote delete fromcontainer
${CMD_PREFIX} ostree --repo=repo remote add --custom-backend=ostree-rs-ext fromcontainer2 docker://quay.io/examplecorp/foo
if ${CMD_PREFIX} ostree --repo=repo pull fromcontainer2 main 2>err.txt; then
assert_not_reached "pull unexpectedly succeeded?"
fi
assert_file_has_content err.txt "remote 'fromcontainer2' uses custom backend 'ostree-rs-ext'"
${CMD_PREFIX} ostree --repo=repo remote show-url fromcontainer2 >out.txt
assert_file_has_content out.txt docker://quay.io/examplecorp/foo
${CMD_PREFIX} ostree --repo=repo remote delete fromcontainer2
echo "ok custom backend"
cd ${test_tmpdir} cd ${test_tmpdir}
repo_init repo_init
${CMD_PREFIX} ostree --repo=repo remote add origin-bad $(cat httpd-address)/ostree/noent ${CMD_PREFIX} ostree --repo=repo remote add origin-bad $(cat httpd-address)/ostree/noent