Skip to content

Commit

Permalink
Add an rpmostree-client sub-crate
Browse files Browse the repository at this point in the history
This is intended to be published to https://crates.io/crates/rpmostree-client
Part of coreos#2389

This directly imports the code from
https://github.com/ostreedev/ostree/blob/5551c54c6e6eba8145b95bd3b28223f1941a9e8d/tests/inst/src/rpmostree.rs

Once merged and released I'll try converting the ostree test suite
over as well as Zincati.

Internally add a testutils helper to validate it works.
  • Loading branch information
cgwalters authored and openshift-merge-robot committed Feb 17, 2021
1 parent 7bf885e commit e6c045c
Show file tree
Hide file tree
Showing 8 changed files with 537 additions and 1 deletion.
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ libdnf-sys = { path = "rust/libdnf-sys", version = "0.1.0" }
memfd = "0.3.0"
rust-ini = "0.16.1"
os-release = "0.1.0"
rpmostree-client = { path = "rust/rpmostree-client", version = "0.1.0" }

[build-dependencies]
cbindgen = "0.16.0"
Expand Down
16 changes: 16 additions & 0 deletions rust/rpmostree-client/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "rpmostree-client"
description = "Client side bindings for rpm-ostree"
version = "0.1.0"
edition = "2018"
license = "Apache-2.0"
keywords = ["ostree", "rpm-ostree"]
documentation = "http://docs.rs/rpmostree-client"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
anyhow = "1.0.38"
serde = { version = "1.0.123", features = ["derive"] }
serde_derive = "1.0.118"
serde_json = "1.0.62"
64 changes: 64 additions & 0 deletions rust/rpmostree-client/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//! APIs for interacting with rpm-ostree client side.

use anyhow::Context;
use serde_derive::Deserialize;
use std::process::Command;

/// Our generic catchall fatal error, expected to be converted
/// to a string to output to a terminal or logs.
type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync + 'static>>;

/// Representation of the rpm-ostree client-side state; this
/// can be parsed directly from the output of `rpm-ostree status --json`.
/// Currently not all fields are here, but that is a bug.
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct Status {
pub deployments: Vec<Deployment>,
}

/// A single deployment, i.e. a bootable ostree commit
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct Deployment {
pub unlocked: Option<String>,
pub osname: String,
pub pinned: bool,
pub checksum: String,
pub staged: Option<bool>,
pub booted: bool,
pub serial: u32,
pub origin: String,
}

/// Gather a snapshot of the system status.
pub fn query_status() -> Result<Status> {
// Retry on temporary activation failures, see
// https://github.com/coreos/rpm-ostree/issues/2531
let pause = std::time::Duration::from_secs(1);
let max_retries = 10;
let mut retries = 0;
let cmd_res = loop {
retries += 1;
let res = Command::new("rpm-ostree")
.args(&["status", "--json"])
.output()
.context("failed to spawn 'rpm-ostree status'")?;

if res.status.success() || retries >= max_retries {
break res;
}
std::thread::sleep(pause);
};

if !cmd_res.status.success() {
return Err(format!(
"running 'rpm-ostree status' failed: {}",
String::from_utf8_lossy(&cmd_res.stderr)
)
.into());
}

Ok(serde_json::from_slice(&cmd_res.stdout)
.context("failed to parse 'rpm-ostree status' output")?)
}
Loading

0 comments on commit e6c045c

Please sign in to comment.