Move some small daemon layering lookup into Rust

Prep for more oxidation work.  One notable improvement here is that about half
of the callers of the mega function `rpmostree_deployment_get_layered_info`
only wanted the base information, not the layered package lists
for example - so we were passing 4 `NULL`s to ignore those.

This Rust API returns a simple shared struct instead for those
cases.  I also changed things so that `base_commit` is always
set, avoiding the callers needing to do that.
This commit is contained in:
Colin Walters 2021-03-08 22:37:26 +00:00
parent 3041d648bb
commit e02fff3d5a
6 changed files with 87 additions and 44 deletions

View File

@ -4,7 +4,7 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT
use crate::cxxrsutil::*;
use crate::{cxxrsutil::*, variant_utils};
use std::pin::Pin;
/// Get a currently unique (for this host) identifier for the
@ -74,3 +74,54 @@ pub(crate) fn deployment_populate_variant(
Ok(())
}
/// Load basic layering metadata about a deployment commit.
pub(crate) fn deployment_layeredmeta_from_commit(
mut deployment: Pin<&mut crate::FFIOstreeDeployment>,
mut commit: Pin<&mut crate::FFIGVariant>,
) -> CxxResult<crate::ffi::DeploymentLayeredMeta> {
let deployment = deployment.gobj_wrap();
let commit = &commit.gobj_wrap();
let metadata = &variant_utils::variant_tuple_get(commit, 0).expect("commit metadata");
let dict = &glib::VariantDict::new(Some(metadata));
// More recent versions have an explicit clientlayer attribute (which
// realistically will always be TRUE). For older versions, we just
// rely on the treespec being present. */
let is_layered = variant_utils::variant_dict_lookup_bool(dict, "rpmostree.clientlayer")
.unwrap_or_else(|| dict.contains("rpmostree.spec"));
if !is_layered {
Ok(crate::ffi::DeploymentLayeredMeta {
is_layered,
base_commit: deployment.get_csum().unwrap().into(),
clientlayer_version: 0,
})
} else {
let base_commit = ostree::commit_get_parent(commit)
.expect("commit parent")
.into();
let clientlayer_version = dict
.lookup_value("rpmostree.clientlayer_version", Some(&*variant_utils::TY_U))
.map(|u| u.get().unwrap())
.unwrap_or_default();
Ok(crate::ffi::DeploymentLayeredMeta {
is_layered,
base_commit,
clientlayer_version,
})
}
}
/// Load basic layering metadata about a deployment
pub(crate) fn deployment_layeredmeta_load(
mut repo: Pin<&mut crate::FFIOstreeRepo>,
mut deployment: Pin<&mut crate::FFIOstreeDeployment>,
) -> CxxResult<crate::ffi::DeploymentLayeredMeta> {
let repo = repo.gobj_wrap();
let deployment = deployment.gobj_wrap();
let commit = &repo.load_variant(
ostree::ObjectType::Commit,
deployment.get_csum().unwrap().as_str(),
)?;
deployment_layeredmeta_from_commit(deployment.gobj_rewrap(), commit.gobj_rewrap())
}

View File

@ -90,6 +90,15 @@ pub mod ffi {
fn compose_postprocess_final(rootfs_dfd: i32) -> Result<()>;
}
// A grab-bag of metadata from the deployment's ostree commit
// around layering/derivation
#[derive(Default)]
struct DeploymentLayeredMeta {
is_layered: bool,
base_commit: String,
clientlayer_version: u32,
}
// daemon.rs
extern "Rust" {
fn deployment_generate_id(deployment: Pin<&mut OstreeDeployment>) -> String;
@ -98,6 +107,14 @@ pub mod ffi {
mut deployment: Pin<&mut OstreeDeployment>,
mut dict: Pin<&mut GVariantDict>,
) -> Result<()>;
fn deployment_layeredmeta_from_commit(
mut deployment: Pin<&mut OstreeDeployment>,
mut commit: Pin<&mut GVariant>,
) -> Result<DeploymentLayeredMeta>;
fn deployment_layeredmeta_load(
mut repo: Pin<&mut OstreeRepo>,
mut deployment: Pin<&mut OstreeDeployment>,
) -> Result<DeploymentLayeredMeta>;
}
// initramfs.rs

View File

@ -12,6 +12,9 @@ lazy_static::lazy_static! {
pub(crate) static ref TY_B: &'static glib::VariantTy = {
glib::VariantTy::new("b").unwrap()
};
pub(crate) static ref TY_U: &'static glib::VariantTy = {
glib::VariantTy::new("u").unwrap()
};
}
pub(crate) fn new_variant_tuple<'a>(

View File

@ -618,21 +618,14 @@ try_load_base_rsack_from_pending (RpmOstreeSysrootUpgrader *self,
if (is_live)
return TRUE;
guint layer_version;
g_autofree char *base_rev_owned = NULL;
if (!rpmostree_deployment_get_layered_info (self->repo, self->origin_merge_deployment,
NULL, &layer_version, &base_rev_owned, NULL,
NULL, NULL, error))
return FALSE;
auto repo = ostree_sysroot_repo(self->sysroot);
auto layeredmeta = rpmostreecxx::deployment_layeredmeta_load(*repo, *self->origin_merge_deployment);
/* older client layers have a bug blocking us from using their base rpmdb:
* https://github.com/projectatomic/rpm-ostree/pull/1560 */
if (base_rev_owned && layer_version < 4)
if (layeredmeta.is_layered && layeredmeta.clientlayer_version < 4)
return TRUE;
const char *base_rev =
base_rev_owned ?: ostree_deployment_get_csum (self->origin_merge_deployment);
const char *base_rev = layeredmeta.base_commit.c_str();
/* it's no longer the base layer we're looking for (e.g. likely pulled a fresh one) */
if (!g_str_equal (self->base_revision, base_rev))
return TRUE;

View File

@ -2583,12 +2583,8 @@ finalize_deployment_transaction_execute (RpmostreedTransaction *transaction,
if (!g_str_equal (ostree_deployment_get_osname (default_deployment), self->osname))
return glnx_throw (error, "Staged deployment is not for osname '%s'", self->osname);
gboolean is_layered = FALSE;
g_autofree char *base_checksum = NULL;
if (!rpmostree_deployment_get_layered_info (repo, default_deployment, &is_layered, NULL,
&base_checksum, NULL, NULL, NULL, error))
return FALSE;
const char *checksum = base_checksum ?: ostree_deployment_get_csum (default_deployment);
auto layeredmeta = rpmostreecxx::deployment_layeredmeta_load(*repo, *default_deployment);
const char *checksum = layeredmeta.base_commit.c_str();
auto expected_checksum =
(char*)vardict_lookup_ptr (self->options, "checksum", "&s");

View File

@ -520,36 +520,19 @@ rpmostree_deployment_get_layered_info (OstreeRepo *repo,
if (!ostree_repo_load_commit (repo, csum, &commit, NULL, error))
return FALSE;
auto layeredmeta = rpmostreecxx::deployment_layeredmeta_from_commit(*deployment, *commit);
g_autoptr(GVariant) metadata = g_variant_get_child_value (commit, 0);
g_autoptr(GVariantDict) dict = g_variant_dict_new (metadata);
/* More recent versions have an explicit clientlayer attribute (which
* realistically will always be TRUE). For older versions, we just
* rely on the treespec being present. */
gboolean is_layered = FALSE;
if (!g_variant_dict_lookup (dict, "rpmostree.clientlayer", "b", &is_layered))
is_layered = g_variant_dict_contains (dict, "rpmostree.spec");
guint clientlayer_version = 0;
g_variant_dict_lookup (dict, "rpmostree.clientlayer_version", "u",
&clientlayer_version);
/* only fetch base if we have to */
g_autofree char *base_layer = NULL;
if (is_layered && out_base_layer != NULL)
{
base_layer = ostree_commit_get_parent (commit);
g_assert (base_layer);
}
/* only fetch pkgs if we have to */
g_auto(GStrv) layered_pkgs = NULL;
g_autoptr(GVariant) removed_base_pkgs = NULL;
g_autoptr(GVariant) replaced_base_pkgs = NULL;
if (is_layered && (out_layered_pkgs != NULL || out_removed_base_pkgs != NULL))
if (layeredmeta.is_layered && (out_layered_pkgs != NULL || out_removed_base_pkgs != NULL))
{
/* starting from v1, we no longer embed a treespec in client layers */
if (clientlayer_version >= 1)
if (layeredmeta.clientlayer_version >= 1)
{
g_assert (g_variant_dict_lookup (dict, "rpmostree.packages", "^as",
&layered_pkgs));
@ -572,7 +555,7 @@ rpmostree_deployment_get_layered_info (OstreeRepo *repo,
&layered_pkgs));
}
if (clientlayer_version >= 2)
if (layeredmeta.clientlayer_version >= 2)
{
removed_base_pkgs =
g_variant_dict_lookup_value (dict, "rpmostree.removed-base-packages",
@ -589,11 +572,11 @@ rpmostree_deployment_get_layered_info (OstreeRepo *repo,
/* canonicalize outputs to empty array */
if (out_is_layered != NULL)
*out_is_layered = is_layered;
*out_is_layered = layeredmeta.is_layered;
if (out_layer_version != NULL)
*out_layer_version = clientlayer_version;
if (out_base_layer != NULL)
*out_base_layer = util::move_nullify (base_layer);
*out_layer_version = layeredmeta.clientlayer_version;
if (out_base_layer != NULL && layeredmeta.is_layered)
*out_base_layer = util::ruststr_dup_c_optempty(layeredmeta.base_commit);
if (out_layered_pkgs != NULL)
{
if (!layered_pkgs)