Skip to content

Commit

Permalink
WIP: Allow rebase to OSTree commits in container images
Browse files Browse the repository at this point in the history
Still need to add tests and possibly handle write new ostree ref
in `deploy_transaction_execute()`(?).

NB: current method of guessing the refspec type may also not be ideal.
  • Loading branch information
kelvinfan001 committed Jun 30, 2021
1 parent 726ec79 commit 3745416
Show file tree
Hide file tree
Showing 13 changed files with 201 additions and 30 deletions.
4 changes: 3 additions & 1 deletion rust/rpmostree-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ pub struct Deployment {
pub staged: Option<bool>,
pub booted: bool,
pub serial: u32,
pub origin: String,
pub ostree_refspec: Option<String>,
pub ostree_checksum: Option<String>,
pub container_image_reference: Option<String>,
pub version: Option<String>,
}

Expand Down
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
14 changes: 11 additions & 3 deletions src/app/rpmostree-builtin-status.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -559,14 +559,17 @@ 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;
g_autoptr(GVariant) origin_base_removals = NULL;
g_autofree const gchar **origin_requested_base_removals = NULL;
g_autoptr(GVariant) origin_base_local_replacements = NULL;
g_autofree const gchar **origin_requested_base_local_replacements = NULL;
if (g_variant_dict_lookup (dict, "origin", "&s", &origin_refspec))
if (g_variant_dict_lookup (dict, "ostree-refspec", "&s", &origin_refspec) ||
g_variant_dict_lookup (dict, "ostree-checksum", "&s", &origin_refspec) ||
g_variant_dict_lookup (dict, "container-image-reference", "&s", &origin_refspec))
{
origin_packages =
lookup_array_and_canonicalize (dict, "packages");
Expand Down Expand Up @@ -606,7 +609,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 All @@ -617,6 +619,7 @@ print_one_deployment (RPMOSTreeSysroot *sysroot_proxy,
{
case RPMOSTREE_REFSPEC_TYPE_CHECKSUM:
{
g_print ("ostree-checksum: ");
g_variant_dict_lookup (dict, "custom-origin", "(&s&s)",
&custom_origin_url,
&custom_origin_description);
Expand All @@ -634,9 +637,14 @@ print_one_deployment (RPMOSTreeSysroot *sysroot_proxy,
break;
case RPMOSTREE_REFSPEC_TYPE_OSTREE:
{
g_print ("%s", origin_refspec);
g_print ("ostree-refspec: %s", origin_refspec);
}
break;
case RPMOSTREE_REFSPEC_TYPE_CONTAINER:
{
g_print ("container-image-reference: %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-image-reference type refspecs 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 reference");

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
23 changes: 23 additions & 0 deletions src/libpriv/rpmostree-core.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,24 @@

static OstreeRepo * get_pkgcache_repo (RpmOstreeContext *self);

/* Infer whether refspec if is a container image reference.
* Currently, we are simply relying on the fact that there
* cannot be multiple colons in TYPE_OSTREE or TYPE_COMMIT. */
static gboolean
is_container_image_reference (const char *refspec)
{
const char *first_colon = NULL;
first_colon = strchr (refspec, ':');
if (first_colon != NULL)
{
const char *second_colon = NULL;
second_colon = strchr (first_colon + 1, ':');
if (second_colon != NULL)
return TRUE;
}
return FALSE;
}

/* Given a string, infer its type and return it in `out_type`.
* Could be either an ostree refspec (TYPE_OSTREE)
* or a bare commit (TYPE_COMMIT).
Expand All @@ -59,6 +77,11 @@ rpmostree_refspec_classify (const char *refspec,
RpmOstreeRefspecType *out_type,
GError **error)
{
if (is_container_image_reference (refspec))
{
*out_type = RPMOSTREE_REFSPEC_TYPE_CONTAINER;
return TRUE;
}
/* Fall back to TYPE_OSTREE if we cannot infer type */
*out_type = RPMOSTREE_REFSPEC_TYPE_OSTREE;
if (ostree_validate_checksum_string (refspec, 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
Loading

0 comments on commit 3745416

Please sign in to comment.