Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
Still missing some guesswork logic in rpm_ostreerefspec_classify().
Alternatively (ideally), guess once and store the type in origin,
then pass origin around to all places that currently needs to call
rpmostree_refspec_classify(), e.g.  rpmostree_origin_set_rebase_custom()
and change_origin_refspec() ... or smth along these lines, will need to
investigate a bit more.

Also need to write new ostree ref in deploy_transaction_execute()
  • Loading branch information
kelvinfan001 committed Jun 30, 2021
1 parent 726ec79 commit c8b1487
Show file tree
Hide file tree
Showing 9 changed files with 169 additions and 25 deletions.
7 changes: 7 additions & 0 deletions rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,11 @@ pub mod ffi {
fn cliwrap_destdir() -> String;
}

// sysroot_upgrade.rs
extern "Rust" {
fn import_container(sysroot: Pin<&mut OstreeSysroot>, imgref: String) -> Result<String>;
}

// core.rs
extern "Rust" {
type TempEtcGuard;
Expand Down Expand Up @@ -583,6 +588,8 @@ pub(crate) use self::console_progress::*;
mod progress;
mod scripts;
pub(crate) use self::scripts::*;
mod sysroot_upgrade;
pub(crate) use crate::sysroot_upgrade::*;
mod rpmutils;
pub(crate) use self::rpmutils::*;
mod testutils;
Expand Down
28 changes: 28 additions & 0 deletions rust/src/sysroot_upgrade.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//! Rust portion of `rpmostree-sysroot-upgrader.cxx`.
// SPDX-License-Identifier: Apache-2.0 OR MIT

use crate::cxxrsutil::*;
use anyhow::{Context, Result};
use std::convert::TryInto;
use std::pin::Pin;

/// Import ostree commit in container image using ostree-rs-ext's API.
pub fn import_container(
mut sysroot: Pin<&mut crate::FFIOstreeSysroot>,
imgref: String,
) -> Result<String> {
let sysroot = &sysroot.gobj_wrap();
let repo = &sysroot.get_repo(gio::NONE_CANCELLABLE)?;
let imgref = imgref.as_str().try_into()?;
let commit = build_runtime()?
.block_on(async { ostree_ext::container::import(&repo, &imgref, None).await })?;
Ok(commit.ostree_commit)
}

fn build_runtime() -> Result<tokio::runtime::Runtime> {
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.context("Failed to build tokio runtime")
}
5 changes: 5 additions & 0 deletions src/app/rpmostree-builtin-rebase.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@ rpmostree_builtin_rebase (int argc,
if (strlen (new_provided_refspec) == 0)
return glnx_throw (error, "Refspec is empty");

/* When using the container:// refspec type, if rebasing to a specific commit, we expect a
* specific digest tag in the refspec, not in a separate argument */
if (revision && refspectype == RPMOSTREE_REFSPEC_TYPE_CONTAINER)
return glnx_throw (error, "Unexpected ostree revision alongside container refspec type");

/* Check if remote refers to a local repo */
g_autofree char *local_repo_remote = NULL;
if (G_IN_SET (refspectype, RPMOSTREE_REFSPEC_TYPE_OSTREE,
Expand Down
8 changes: 7 additions & 1 deletion src/app/rpmostree-builtin-status.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,7 @@ print_one_deployment (RPMOSTreeSysroot *sysroot_proxy,
return TRUE;

const gchar *origin_refspec;
RpmOstreeRefspecType refspectype = RPMOSTREE_REFSPEC_TYPE_OSTREE;
g_autofree const gchar **origin_packages = NULL;
g_autofree const gchar **origin_requested_packages = NULL;
g_autofree const gchar **origin_requested_local_packages = NULL;
Expand All @@ -568,6 +569,7 @@ print_one_deployment (RPMOSTreeSysroot *sysroot_proxy,
g_autofree const gchar **origin_requested_base_local_replacements = NULL;
if (g_variant_dict_lookup (dict, "origin", "&s", &origin_refspec))
{
g_variant_dict_lookup (dict, "refspec-type", "%u", &refspectype);
origin_packages =
lookup_array_and_canonicalize (dict, "packages");
origin_requested_packages =
Expand Down Expand Up @@ -606,7 +608,6 @@ 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)
Expand Down Expand Up @@ -637,6 +638,11 @@ print_one_deployment (RPMOSTreeSysroot *sysroot_proxy,
g_print ("%s", origin_refspec);
}
break;
case RPMOSTREE_REFSPEC_TYPE_CONTAINER:
{
g_print ("%s", origin_refspec);
}
break;
}
}
else
Expand Down
10 changes: 10 additions & 0 deletions src/daemon/rpmostree-sysroot-upgrader.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,16 @@ rpmostree_sysroot_upgrader_pull_base (RpmOstreeSysrootUpgrader *self,

switch (refspec_type)
{
case RPMOSTREE_REFSPEC_TYPE_CONTAINER:
{
if (override_commit)
return glnx_throw (error, "Specifying commit overrides for container:// is not supported");

auto commit = rpmostreecxx::import_container(*self->sysroot, std::string(refspec));

new_base_rev = strdup (commit.c_str());
break;
}
case RPMOSTREE_REFSPEC_TYPE_CHECKSUM:
case RPMOSTREE_REFSPEC_TYPE_OSTREE:
{
Expand Down
9 changes: 6 additions & 3 deletions src/daemon/rpmostreed-deployment-utils.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ rpmostreed_deployment_generate_variant (OstreeSysroot *sysroot,

RpmOstreeRefspecType refspec_type;
g_autofree char *refspec = rpmostree_origin_get_full_refspec (origin, &refspec_type);
g_assert (refspec);

gboolean is_layered = FALSE;
g_autofree char *base_checksum = NULL;
Expand Down Expand Up @@ -301,8 +302,12 @@ rpmostreed_deployment_generate_variant (OstreeSysroot *sysroot,

switch (refspec_type)
{
case RPMOSTREE_REFSPEC_TYPE_CONTAINER:
g_variant_dict_insert (dict, "container-image-reference", "s", refspec);
break;
case RPMOSTREE_REFSPEC_TYPE_CHECKSUM:
{
g_variant_dict_insert (dict, "ostree-checksum", "s", refspec);
g_autofree char *custom_origin_url = NULL;
g_autofree char *custom_origin_description = NULL;
rpmostree_origin_get_custom_description (origin, &custom_origin_url,
Expand All @@ -315,6 +320,7 @@ rpmostreed_deployment_generate_variant (OstreeSysroot *sysroot,
break;
case RPMOSTREE_REFSPEC_TYPE_OSTREE:
{
g_variant_dict_insert (dict, "ostree-refspec", "s", refspec);
if (!variant_add_remote_status (repo, refspec, base_checksum, dict, error))
return NULL;

Expand All @@ -339,9 +345,6 @@ rpmostreed_deployment_generate_variant (OstreeSysroot *sysroot,
break;
}

if (refspec)
g_variant_dict_insert (dict, "origin", "s", refspec);

variant_add_from_hash_table (dict, "requested-packages",
rpmostree_origin_get_packages (origin));
variant_add_from_hash_table (dict, "requested-local-packages",
Expand Down
44 changes: 42 additions & 2 deletions src/daemon/rpmostreed-transaction-types.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,37 @@ change_origin_refspec (GVariantDict *options,
gchar **out_new_refspec,
GError **error)
{
RpmOstreeRefspecType refspectype;
if (!rpmostree_refspec_classify (refspec, &refspectype, error))
return FALSE;

RpmOstreeRefspecType current_refspectype;
g_autofree gchar *current_refspec = rpmostree_origin_get_full_refspec (origin, &current_refspectype);


switch (refspectype)
{
case RPMOSTREE_REFSPEC_TYPE_CONTAINER:
{
if (!rpmostree_origin_set_rebase (origin, refspec, error))
return FALSE;

if (current_refspectype == RPMOSTREE_REFSPEC_TYPE_CONTAINER
&& strcmp (current_refspec, refspec) == 0)
return glnx_throw (error, "Old and new refs are equal: %s", refspec);

if (out_old_refspec != NULL)
*out_old_refspec = current_refspec;
if (out_new_refspec != NULL)
*out_new_refspec = g_strdup (refspec);
return TRUE;
}
case RPMOSTREE_REFSPEC_TYPE_OSTREE:
break;
case RPMOSTREE_REFSPEC_TYPE_CHECKSUM:
break;
}

/* The rest of the code assumes TYPE_OSTREE refspec */
g_autofree gchar *new_refspec = NULL;
if (!rpmostreed_refspec_parse_partial (refspec,
current_refspec,
Expand Down Expand Up @@ -149,7 +177,12 @@ apply_revision_override (RpmostreedTransaction *transaction,
rpmostree_origin_classify_refspec (origin, &refspectype, NULL);

if (refspectype == RPMOSTREE_REFSPEC_TYPE_CHECKSUM)
return glnx_throw (error, "Cannot look up version while pinned to commit");
return glnx_throw (error, "Cannot look up version/checksum while pinned to commit");

if (refspectype == RPMOSTREE_REFSPEC_TYPE_CONTAINER)
/* NB: Not supported for now, but We can perhaps support this if we allow `revision` to
* possibly be a tag or digest */
return glnx_throw (error, "Cannot look up version/checksum while tracking a container image");

g_autofree char *checksum = NULL;
g_autofree char *version = NULL;
Expand All @@ -160,6 +193,8 @@ apply_revision_override (RpmostreedTransaction *transaction,
{
switch (refspectype)
{
case RPMOSTREE_REFSPEC_TYPE_CONTAINER:
g_assert_not_reached (); /* Handled above */
case RPMOSTREE_REFSPEC_TYPE_OSTREE:
{
/* Perhaps down the line we'll drive history traversal into libostree */
Expand All @@ -183,6 +218,8 @@ apply_revision_override (RpmostreedTransaction *transaction,

switch (refspectype)
{
case RPMOSTREE_REFSPEC_TYPE_CONTAINER:
g_assert_not_reached (); /* Handled above */
case RPMOSTREE_REFSPEC_TYPE_OSTREE:
if (!skip_branch_check)
{
Expand Down Expand Up @@ -1486,6 +1523,9 @@ deploy_transaction_execute (RpmostreedTransaction *transaction,
{
g_autofree char *remote = NULL;
g_autofree char *ref = NULL;

/* TODO: Handle `container-image-reference` refspectype. Currently, a new OSTree ref is not
* written if refspecdata is e.g. `registry:quay.io/fcos` */

/* The actual rebase has already succeeded, so ignore errors. */
if (ostree_parse_refspec (old_refspec, &remote, &ref, NULL))
Expand Down
5 changes: 5 additions & 0 deletions src/libpriv/rpmostree-core.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,13 @@ G_DECLARE_FINAL_TYPE (RpmOstreeTreespec, rpmostree_treespec, RPMOSTREE, TREESPEC
typedef enum {
RPMOSTREE_REFSPEC_TYPE_OSTREE,
RPMOSTREE_REFSPEC_TYPE_CHECKSUM,
RPMOSTREE_REFSPEC_TYPE_CONTAINER,
} RpmOstreeRefspecType;

#define RPMOSTREE_REFSPEC_OSTREE_ORIGIN_KEY "refspec"
#define RPMOSTREE_REFSPEC_OSTREE_BASE_ORIGIN_KEY "baserefspec"
#define RPMOSTREE_REFSPEC_CONTAINER_ORIGIN_KEY "container-image-reference"

gboolean rpmostree_refspec_classify (const char *refspec,
RpmOstreeRefspecType *out_type,
GError **error);
Expand Down
78 changes: 59 additions & 19 deletions src/libpriv/rpmostree-origin.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -115,23 +115,45 @@ rpmostree_origin_parse_keyfile (GKeyFile *origin,

ret->cached_unconfigured_state = g_key_file_get_string (ret->kf, "origin", "unconfigured-state", NULL);

g_autofree char *refspec = g_key_file_get_string (ret->kf, "origin", "refspec", NULL);
if (!refspec)
/* Note that the refspec type can be inferred from the key in the orgin file, where
* the `RPMOSTREE_REFSPEC_OSTREE_ORIGIN_KEY` and `RPMOSTREE_REFSPEC_OSTREE_BASE_ORIGIN_KEY` keys
* may correspond to either TYPE_OSTREE or TYPE_CHECKSUM (further classification is required), and
* `RPMOSTREE_REFSPEC_CONTAINER_ORIGIN_KEY` always only corresponds to TYPE_CONTAINER. */
g_autofree char *ost_refspec = g_key_file_get_string (ret->kf, "origin", RPMOSTREE_REFSPEC_OSTREE_ORIGIN_KEY, NULL);
g_autofree char *imgref = g_key_file_get_string (ret->kf, "origin", RPMOSTREE_REFSPEC_CONTAINER_ORIGIN_KEY, NULL);
if (!ost_refspec)
{
refspec = g_key_file_get_string (ret->kf, "origin", "baserefspec", NULL);
if (!refspec)
return (RpmOstreeOrigin *)glnx_null_throw (error, "No origin/refspec, or origin/baserefspec in current deployment origin; cannot handle via rpm-ostree");
/* See if refspec if of TYPE_CHECKSUM */
ost_refspec = g_key_file_get_string (ret->kf, "origin", RPMOSTREE_REFSPEC_OSTREE_BASE_ORIGIN_KEY, NULL);
if (!ost_refspec && !imgref)
return (RpmOstreeOrigin *)glnx_null_throw (error,
"No origin/%s, origin/%s, or origin/%s "
"in current deployment origin; cannot handle via rpm-ostree",
RPMOSTREE_REFSPEC_OSTREE_ORIGIN_KEY,
RPMOSTREE_REFSPEC_OSTREE_BASE_ORIGIN_KEY,
RPMOSTREE_REFSPEC_CONTAINER_ORIGIN_KEY);
}
if (ost_refspec && imgref)
return (RpmOstreeOrigin *)glnx_null_throw (error,
"Refspec expressed by multiple keys in deployment origin");
else if (ost_refspec)
{
/* Classify to distinguish between TYPE_CHECKSUM and TYPE_OSTREE */
if (!rpmostree_refspec_classify (ost_refspec, &ret->refspec_type, error))
return FALSE;
ret->cached_refspec = util::move_nullify (ost_refspec);
ret->cached_override_commit =
g_key_file_get_string (ret->kf, "origin", "override-commit", NULL);
}
else if (imgref)
{
ret->refspec_type = RPMOSTREE_REFSPEC_TYPE_CONTAINER;
ret->cached_refspec = util::move_nullify (imgref);
}
else
{
g_assert_not_reached ();
}

if (!rpmostree_refspec_classify (refspec, &ret->refspec_type, error))
return FALSE;
/* Note the lack of a prefix here so that code that just calls
* rpmostree_origin_get_refspec() in the ostree:// case
* sees it without the prefix for compatibility.
*/
ret->cached_refspec = util::move_nullify (refspec);
ret->cached_override_commit =
g_key_file_get_string (ret->kf, "origin", "override-commit", NULL);

if (!parse_packages_strv (ret->kf, "packages", "requested", FALSE,
ret->cached_packages, error))
Expand Down Expand Up @@ -495,23 +517,29 @@ rpmostree_origin_set_rebase_custom (RpmOstreeOrigin *origin,
}

/* We don't want to carry any commit overrides or version pinning during a
* rebase by default.
*/
* rebase by default. */
rpmostree_origin_set_override_commit (origin, NULL, NULL);

/* See related code in rpmostree_origin_parse_keyfile() */
if (!rpmostree_refspec_classify (new_refspec, &origin->refspec_type, error))
return FALSE;
g_free (origin->cached_refspec);
origin->cached_refspec = g_strdup (new_refspec);
/* Note the following code sets different keys depending on the type of refspec;
* TYPE_OSTREE and TYPE_CHECKSUM may set either `RPMOSTREE_REFSPEC_OSTREE_BASE_ORIGIN_KEY`
* or `RPMOSTREE_REFSPEC_OSTREE_ORIGIN_KEY`, while TYPE_CONTAINER will set the
* `RPMOSTREE_REFSPEC_CONTAINER_ORIGIN_KEY` key. */
switch (origin->refspec_type)
{
case RPMOSTREE_REFSPEC_TYPE_CHECKSUM:
case RPMOSTREE_REFSPEC_TYPE_OSTREE:
{
/* Remove `TYPE_CONTAINER`-related keys */
g_key_file_remove_key (origin->kf, "origin", RPMOSTREE_REFSPEC_CONTAINER_ORIGIN_KEY, NULL);

const char *refspec_key =
g_key_file_has_key (origin->kf, "origin", "baserefspec", NULL) ?
"baserefspec" : "refspec";
g_key_file_has_key (origin->kf, "origin", , NULL) ?
RPMOSTREE_REFSPEC_OSTREE_BASE_ORIGIN_KEY : RPMOSTREE_REFSPEC_OSTREE_ORIGIN_KEY;
g_key_file_set_string (origin->kf, "origin", refspec_key, origin->cached_refspec);
if (!custom_origin_url)
{
Expand All @@ -528,6 +556,18 @@ rpmostree_origin_set_rebase_custom (RpmOstreeOrigin *origin,
}
}
break;
case RPMOSTREE_REFSPEC_TYPE_CONTAINER:
{
/* Remove `TYPE_OSTREE` and `TYPE_CHECKSUM`-related keys */
g_assert (!custom_origin_url);
g_key_file_remove_key (origin->kf, "origin", RPMOSTREE_REFSPEC_OSTREE_ORIGIN_KEY, NULL);
g_key_file_remove_key (origin->kf, "origin", RPMOSTREE_REFSPEC_OSTREE_BASE_ORIGIN_KEY, NULL);
g_key_file_remove_key (origin->kf, "origin", "custom-url", NULL);
g_key_file_remove_key (origin->kf, "origin", "custom-description", NULL);

g_key_file_set_string (origin->kf, "origin", RPMOSTREE_REFSPEC_CONTAINER_ORIGIN_KEY, origin->cached_refspec);
}
break;
}

return TRUE;
Expand Down

0 comments on commit c8b1487

Please sign in to comment.