Skip to content

Commit

Permalink
update_agent: support rebaseing to OCI pullspec
Browse files Browse the repository at this point in the history
Add a configuration knob in `update` to optionnaly use OCI pullspec
instead of ostree checksums.

This will default to false.
Requires coreos/fedora-coreos-cincinnati#99
and coreos/rpm-ostree#5120
  • Loading branch information
jbtrystram committed Dec 4, 2024
1 parent ee1579f commit 1ca8a87
Show file tree
Hide file tree
Showing 13 changed files with 65 additions and 18 deletions.
1 change: 1 addition & 0 deletions src/cincinnati/mock_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ fn test_empty_graph() {
let id = Identity::mock_default();
let client = Cincinnati {
base_url: server.url(),
oci_param: false,
};
let update = runtime.block_on(client.next_update(&id, BTreeSet::new(), false));
m_graph.assert();
Expand Down
21 changes: 18 additions & 3 deletions src/cincinnati/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ pub static DEADEND_REASON_KEY: &str = "org.fedoraproject.coreos.updates.deadend_
/// Metadata value for "checksum" payload scheme.
pub static CHECKSUM_SCHEME: &str = "checksum";

/// Metadata value for "oci" payload scheme.
pub static OCI_SCHEME: &str = "oci";

lazy_static::lazy_static! {
static ref GRAPH_NODES: IntGauge = register_int_gauge!(opts!(
"zincati_cincinnati_graph_nodes_count",
Expand Down Expand Up @@ -102,12 +105,18 @@ impl DeadEndState {
pub struct Cincinnati {
/// Service base URL.
pub base_url: String,
/// Wether to pass `oci` query parameter
pub oci_param: bool,
}

impl Cincinnati {
/// Process Cincinnati configuration.
#[context("failed to validate cincinnati configuration")]
pub(crate) fn with_config(cfg: inputs::CincinnatiInput, id: &Identity) -> Result<Self> {
pub(crate) fn with_config(
cfg: inputs::CincinnatiInput,
id: &Identity,
use_oci: bool,
) -> Result<Self> {
if cfg.base_url.is_empty() {
anyhow::bail!("empty Cincinnati base URL");
}
Expand All @@ -122,7 +131,10 @@ impl Cincinnati {
};
log::info!("Cincinnati service: {}", &base_url);

let c = Self { base_url };
let c = Self {
base_url,
oci_param: use_oci,
};
Ok(c)
}

Expand Down Expand Up @@ -156,7 +168,10 @@ impl Cincinnati {
allow_downgrade: bool,
) -> Pin<Box<dyn Future<Output = Result<Option<Release>, CincinnatiError>>>> {
let booted = id.current_os.clone();
let params = id.cincinnati_params();
let mut params = id.cincinnati_params();
if self.oci_param {
let _ = params.insert(String::from("oci"), String::from("true"));
}
let client = client::ClientBuilder::new(self.base_url.to_string())
.query_params(Some(params))
.build()
Expand Down
3 changes: 3 additions & 0 deletions src/config/fragments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ pub(crate) struct UpdateFragment {
pub(crate) fleet_lock: Option<UpdateFleetLock>,
/// `periodic` strategy config.
pub(crate) periodic: Option<UpdatePeriodic>,
/// Wether to pull updates from OCI images
pub(crate) use_oci: Option<bool>,
}

/// Config fragment for `fleet_lock` update strategy.
Expand Down Expand Up @@ -141,6 +143,7 @@ mod tests {
]),
time_zone: Some("localtime".to_string()),
}),
use_oci: Some(false),
}),
};

Expand Down
7 changes: 7 additions & 0 deletions src/config/inputs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ pub(crate) struct UpdateInput {
pub(crate) fleet_lock: FleetLockInput,
/// `periodic` strategy config.
pub(crate) periodic: PeriodicInput,
/// Wether to pull updates from OCI images
pub(crate) use_oci: bool,
}

/// Config for "fleet_lock" strategy.
Expand Down Expand Up @@ -201,6 +203,7 @@ impl UpdateInput {
intervals: vec![],
time_zone: "UTC".to_string(),
};
let mut use_oci = false;

for snip in fragments {
if let Some(a) = snip.allow_downgrade {
Expand Down Expand Up @@ -234,6 +237,9 @@ impl UpdateInput {
}
}
}
if let Some(oci) = snip.use_oci {
use_oci = oci;
}
}

Self {
Expand All @@ -242,6 +248,7 @@ impl UpdateInput {
strategy,
fleet_lock,
periodic,
use_oci,
}
}
}
6 changes: 5 additions & 1 deletion src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ pub(crate) struct Settings {
pub(crate) identity: Identity,
/// Agent update strategy.
pub(crate) strategy: UpdateStrategy,
/// Wether to pull updates from OCI images
pub(crate) use_oci: bool,
}

impl Settings {
Expand Down Expand Up @@ -68,10 +70,11 @@ impl Settings {
fn validate(cfg: inputs::ConfigInput) -> Result<Self> {
let allow_downgrade = cfg.updates.allow_downgrade;
let enabled = cfg.updates.enabled;
let use_oci = cfg.updates.use_oci;
let steady_interval_secs = cfg.agent.steady_interval_secs;
let identity = Identity::with_config(cfg.identity)?;
let strategy = UpdateStrategy::with_config(cfg.updates, &identity)?;
let cincinnati = Cincinnati::with_config(cfg.cincinnati, &identity)?;
let cincinnati = Cincinnati::with_config(cfg.cincinnati, &identity, use_oci)?;

Ok(Self {
allow_downgrade,
Expand All @@ -80,6 +83,7 @@ impl Settings {
cincinnati,
identity,
strategy,
use_oci,
})
}
}
4 changes: 3 additions & 1 deletion src/rpm_ostree/actor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ pub struct StageDeployment {
pub allow_downgrade: bool,
/// Release to be staged.
pub release: Release,
/// If the release is an OCI image pullspec.
pub oci: bool,
}

impl Message for StageDeployment {
Expand All @@ -53,7 +55,7 @@ impl Handler<StageDeployment> for RpmOstreeClient {

fn handle(&mut self, msg: StageDeployment, _ctx: &mut Self::Context) -> Self::Result {
trace!("request to stage release: {:?}", msg.release);
let release = super::cli_deploy::deploy_locked(msg.release, msg.allow_downgrade);
let release = super::cli_deploy::deploy_locked(msg.release, msg.allow_downgrade, msg.oci);
trace!("rpm-ostree CLI returned: {:?}", release);
release
}
Expand Down
26 changes: 16 additions & 10 deletions src/rpm_ostree/cli_deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ static REGISTER_DRIVER_FAILURES: Lazy<IntCounter> = Lazy::new(|| {
});

/// Deploy an upgrade (by checksum) and leave the new deployment locked.
pub fn deploy_locked(release: Release, allow_downgrade: bool) -> Result<Release> {
pub fn deploy_locked(release: Release, allow_downgrade: bool, oci: bool) -> Result<Release> {
DEPLOY_ATTEMPTS.inc();

let result = invoke_cli_deploy(release, allow_downgrade);
let result = invoke_cli_deploy(release, allow_downgrade, oci);
if result.is_err() {
DEPLOY_FAILURES.inc();
}
Expand Down Expand Up @@ -94,16 +94,22 @@ fn invoke_cli_register() -> Result<()> {
}

/// CLI executor for deploying upgrades.
fn invoke_cli_deploy(release: Release, allow_downgrade: bool) -> Result<Release> {
fn invoke_cli_deploy(release: Release, allow_downgrade: bool, oci: bool) -> Result<Release> {
fail_point!("deploy_locked_err", |_| bail!("deploy_locked_err"));
fail_point!("deploy_locked_ok", |_| Ok(release.clone()));

let mut cmd = std::process::Command::new("rpm-ostree");
cmd.arg("deploy")
.arg("--lock-finalization")
.arg("--skip-branch-check")
.arg(format!("revision={}", release.checksum))
.env("RPMOSTREE_CLIENT_ID", "zincati");
if oci {
// TODO use --custom-origin-url and --custom-origin-description
cmd.arg("rebase")
.arg(format!("ostree-unverified-registry:{}", release.checksum));
} else {
cmd.arg("deploy")
.arg("--lock-finalization")
.arg("--skip-branch-check")
.arg(format!("revision={}", release.checksum));
}
cmd.env("RPMOSTREE_CLIENT_ID", "zincati");
if !allow_downgrade {
cmd.arg("--disallow-downgrade");
}
Expand Down Expand Up @@ -149,7 +155,7 @@ mod tests {
checksum: "bar".to_string(),
age_index: None,
};
let result = deploy_locked(release, true);
let result = deploy_locked(release, true, false);
assert!(result.is_err());
assert!(DEPLOY_ATTEMPTS.get() >= 1);
assert!(DEPLOY_FAILURES.get() >= 1);
Expand All @@ -166,7 +172,7 @@ mod tests {
checksum: "bar".to_string(),
age_index: None,
};
let result = deploy_locked(release.clone(), true).unwrap();
let result = deploy_locked(release.clone(), true, false).unwrap();
assert_eq!(result, release);
assert!(DEPLOY_ATTEMPTS.get() >= 1);
}
Expand Down
2 changes: 2 additions & 0 deletions src/rpm_ostree/mock_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ fn test_simple_graph() {
let id = Identity::mock_default();
let client = Cincinnati {
base_url: server.url(),
oci_param: false,
};
let update = runtime.block_on(client.fetch_update_hint(&id, BTreeSet::new(), false));
m_graph.assert();
Expand Down Expand Up @@ -99,6 +100,7 @@ fn test_downgrade() {
let id = Identity::mock_default();
let client = Cincinnati {
base_url: server.url(),
oci_param: false,
};

// Downgrades denied.
Expand Down
4 changes: 2 additions & 2 deletions src/rpm_ostree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub use actor::{
#[cfg(test)]
mod mock_tests;

use crate::cincinnati::{Node, AGE_INDEX_KEY, CHECKSUM_SCHEME, SCHEME_KEY};
use crate::cincinnati::{Node, AGE_INDEX_KEY, CHECKSUM_SCHEME, OCI_SCHEME, SCHEME_KEY};
use anyhow::{anyhow, ensure, Context, Result};
use serde::Serialize;
use std::cmp::Ordering;
Expand Down Expand Up @@ -70,7 +70,7 @@ impl Release {
.ok_or_else(|| anyhow!("missing metadata key: {}", SCHEME_KEY))?;

ensure!(
scheme == CHECKSUM_SCHEME,
scheme == CHECKSUM_SCHEME || scheme == OCI_SCHEME,
"unexpected payload scheme: {}",
scheme
);
Expand Down
2 changes: 2 additions & 0 deletions src/strategy/fleet_lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ mod tests {
intervals: vec![],
time_zone: "UTC".to_string(),
},
use_oci: false,
};

let res = StrategyFleetLock::new(input, &id);
Expand All @@ -127,6 +128,7 @@ mod tests {
intervals: vec![],
time_zone: "localtime".to_string(),
},
use_oci: false,
};

let res = StrategyFleetLock::new(input, &id);
Expand Down
1 change: 1 addition & 0 deletions src/update_agent/actor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ impl UpdateAgentInfo {
let msg = rpm_ostree::StageDeployment {
release,
allow_downgrade: self.allow_downgrade,
oci: self.use_oci,
};

self.rpm_ostree_actor
Expand Down
3 changes: 3 additions & 0 deletions src/update_agent/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,8 @@ pub(crate) struct UpdateAgentInfo {
rpm_ostree_actor: Addr<RpmOstreeClient>,
/// Update strategy.
strategy: UpdateStrategy,
/// Wether or not to use OCI for transport
use_oci: bool,
}

impl UpdateAgent {
Expand All @@ -448,6 +450,7 @@ impl UpdateAgent {
rpm_ostree_actor: rpm_ostree_addr,
steady_interval: Duration::from_secs(steady_secs),
strategy: cfg.strategy,
use_oci: cfg.use_oci,
},
}
}
Expand Down
3 changes: 2 additions & 1 deletion tests/fixtures/00-config-sample.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ base_url = "http://cincinnati.example.com:80/"
allow_downgrade = true
enabled = false
strategy = "fleet_lock"
use_oci = false

[updates.fleet_lock]
base_url = "http://fleet-lock.example.com:8080/"
Expand All @@ -28,4 +29,4 @@ length_minutes = 120
[[updates.periodic.window]]
days = [ "Wed" ]
start_time = "23:30"
length_minutes = 25
length_minutes = 25

0 comments on commit 1ca8a87

Please sign in to comment.