Skip to content

Commit

Permalink
Exit if booted into a container image
Browse files Browse the repository at this point in the history
This is part of coreos/fedora-coreos-tracker#1263

We don't yet have an official stance on how zincati and custom
container images interact.  Today, zincati just crash loops.
This changes things so that we exit (but still with an error) if we detect
the booted system is using a container image origin.

One nicer thing here is that the unit status is also updated, e.g.
`systemctl status zincati` will show:

`Status: "Automatic updates disabled; booted into container image ..."`
  • Loading branch information
cgwalters committed Nov 21, 2022
1 parent ebb241c commit de798dd
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 9 deletions.
2 changes: 2 additions & 0 deletions dist/systemd/system/zincati.service
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ Environment=ZINCATI_VERBOSITY="-v"
Type=notify
ExecStart=/usr/libexec/zincati agent ${ZINCATI_VERBOSITY}
Restart=on-failure
# This status signals a non-restartable condition
RestartPreventExitStatus=7
RestartSec=10s

[Install]
Expand Down
15 changes: 11 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,20 +56,27 @@ fn run() -> i32 {
match cli_opts.run() {
Ok(_) => libc::EXIT_SUCCESS,
Err(e) => {
log_error_chain(e);
libc::EXIT_FAILURE
log_error_chain(&e);
if e.root_cause()
.downcast_ref::<crate::rpm_ostree::FatalError>()
.is_some()
{
7
} else {
libc::EXIT_FAILURE
}
}
}
}

/// Pretty-print a chain of errors, as a series of error-priority log messages.
fn log_error_chain(err_chain: anyhow::Error) {
fn log_error_chain(err_chain: &anyhow::Error) {
let mut chain_iter = err_chain.chain();
let top_err = match chain_iter.next() {
Some(e) => e.to_string(),
None => "(unspecified failure)".to_string(),
};
log::error!("critical error: {}", top_err);
log::error!("error: {}", top_err);
for err in chain_iter {
log::error!(" -> {}", err);
}
Expand Down
30 changes: 26 additions & 4 deletions src/rpm_ostree/cli_status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,18 @@ lazy_static::lazy_static! {
)).unwrap();
}

/// An error which should not result in a retry/restart.
#[derive(Debug, Clone)]
pub struct FatalError(String);

impl std::fmt::Display for FatalError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}

impl std::error::Error for FatalError {}

/// JSON output from `rpm-ostree status --json`
#[derive(Clone, Debug, Deserialize)]
pub struct StatusJson {
Expand All @@ -48,6 +60,7 @@ pub struct StatusJson {
#[serde(rename_all = "kebab-case")]
pub struct DeploymentJson {
booted: bool,
container_image_reference: Option<String>,
base_checksum: Option<String>,
#[serde(rename = "base-commit-meta")]
base_metadata: BaseCommitMetaJson,
Expand All @@ -62,7 +75,7 @@ pub struct DeploymentJson {
#[derive(Clone, Debug, Deserialize)]
struct BaseCommitMetaJson {
#[serde(rename = "fedora-coreos.stream")]
stream: String,
stream: Option<String>,
}

impl DeploymentJson {
Expand All @@ -85,12 +98,21 @@ impl DeploymentJson {

/// Parse the booted deployment from status object.
pub fn parse_booted(status: &StatusJson) -> Result<Release> {
let json = booted_json(status)?;
Ok(json.into_release())
let status = booted_json(status)?;
if let Some(img) = status.container_image_reference.as_ref() {
let msg = format!("Automatic updates disabled; booted into container image {img}");
crate::utils::update_unit_status(&msg);
return Err(anyhow::Error::new(FatalError(msg)));
}
Ok(status.into_release())
}

fn fedora_coreos_stream_from_deployment(deploy: &DeploymentJson) -> Result<String> {
let stream = deploy.base_metadata.stream.as_str();
let stream = deploy
.base_metadata
.stream
.as_ref()
.ok_or_else(|| anyhow!("Missing `fedora-coreos.stream` in commit metadata"))?;
ensure!(!stream.is_empty(), "empty stream value");
Ok(stream.to_string())
}
Expand Down
2 changes: 1 addition & 1 deletion src/rpm_ostree/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
mod cli_deploy;
mod cli_finalize;
mod cli_status;
pub use cli_status::{invoke_cli_status, parse_booted, parse_booted_updates_stream};
pub use cli_status::{invoke_cli_status, parse_booted, parse_booted_updates_stream, FatalError};

mod actor;
pub use actor::{
Expand Down

0 comments on commit de798dd

Please sign in to comment.