Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update_agent: support rebase to OCI pullspec #1241

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 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
10 changes: 10 additions & 0 deletions src/identity/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ pub(crate) struct Identity {
pub(crate) rollout_wariness: Option<NotNan<f64>>,
/// Stream label.
pub(crate) stream: String,
/// Wether the current deployment is from an OCI container or an ostree reference.
pub(crate) oci: bool,
}

impl Identity {
Expand Down Expand Up @@ -104,6 +106,9 @@ impl Identity {
let platform = platform::read_id("/proc/cmdline")?;
let stream = rpm_ostree::parse_booted_updates_stream(&status)
.context("failed to introspect OS updates stream")?;
let oci = rpm_ostree::parse_booted_oci_reference(&status)
.context("failed to introspect booted OCI reference")?
.is_some();

let id = Self {
basearch,
Expand All @@ -113,6 +118,7 @@ impl Identity {
group: DEFAULT_GROUP.to_string(),
node_uuid,
rollout_wariness: None,
oci,
};
Ok(id)
}
Expand All @@ -139,6 +145,9 @@ impl Identity {
vars.insert("node_uuid".to_string(), self.node_uuid.lower_hex());
vars.insert("platform".to_string(), self.platform.clone());
vars.insert("stream".to_string(), self.stream.clone());
if self.oci {
vars.insert("oci".to_string(), "true".to_string());
}
if let Some(rw) = self.rollout_wariness {
vars.insert("rollout_wariness".to_string(), format!("{:.06}", rw));
}
Expand All @@ -159,6 +168,7 @@ impl Identity {
platform: "mock-azure".to_string(),
rollout_wariness: Some(NotNan::new(0.5).unwrap()),
stream: "mock-stable".to_string(),
oci: false,
}
}

Expand Down
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));
jbtrystram marked this conversation as resolved.
Show resolved Hide resolved
} 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
19 changes: 13 additions & 6 deletions src/rpm_ostree/cli_status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,6 @@ impl Deployment {
/// Parse the booted deployment from status object.
pub fn parse_booted(status: &Status) -> Result<Release> {
let status = booted_status(status)?;
if let Some(img) = status.container_image_reference.as_ref() {
let msg = format!("Automatic updates disabled; booted into container image {img}");
crate::utils::notify_ready();
crate::utils::update_unit_status(&msg);
return Err(anyhow::Error::new(SystemInoperable(msg)));
}
Ok(status.into_release())
}

Expand All @@ -124,6 +118,11 @@ pub fn parse_booted_updates_stream(status: &Status) -> Result<String> {
fedora_coreos_stream_from_deployment(&json)
}

/// Parse oci image reference for booted deployment from status object.
pub fn parse_booted_oci_reference(status: &Status) -> Result<Option<String>> {
booted_status(status).map(|s| s.container_image_reference)
}

/// Parse pending deployment from status object.
pub fn parse_pending_deployment(status: &Status) -> Result<Option<(Release, String)>> {
// There can be at most one staged/pending rpm-ostree deployment,
Expand Down Expand Up @@ -258,6 +257,14 @@ mod tests {
let deployments = parse_local_deployments(&status, true);
assert_eq!(deployments.len(), 1);
}
{
let status = mock_status("tests/fixtures/rpm-ostree-oci-status.json").unwrap();
let deployments = parse_local_deployments(&status, false);
assert_eq!(deployments.len(), 1);
assert!(parse_booted_oci_reference(&status).unwrap().is_some());
assert_eq!(parse_booted_oci_reference(&status).unwrap().unwrap(),
"ostree-unverified-registry:quay.io/fedora/fedora-coreos@sha256:d12dd2fcb57ecfde0941be604f4dcd43ce0409b86e5ee4e362184c802b80fb84")
}
}

#[test]
Expand Down
7 changes: 4 additions & 3 deletions src/rpm_ostree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ mod cli_deploy;
mod cli_finalize;
mod cli_status;
pub use cli_status::{
invoke_cli_status, parse_booted, parse_booted_updates_stream, SystemInoperable,
invoke_cli_status, parse_booted, parse_booted_oci_reference, parse_booted_updates_stream,
SystemInoperable,
};

mod actor;
Expand All @@ -14,7 +15,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 +71,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
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.identity.oci,
};

self.rpm_ostree_actor
Expand Down
2 changes: 1 addition & 1 deletion tests/fixtures/00-config-sample.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ length_minutes = 120
[[updates.periodic.window]]
days = [ "Wed" ]
start_time = "23:30"
length_minutes = 25
length_minutes = 25
38 changes: 38 additions & 0 deletions tests/fixtures/rpm-ostree-oci-status.json

Large diffs are not rendered by default.

Loading