Skip to content

Commit

Permalink
feat: olm deployment helper (#279)
Browse files Browse the repository at this point in the history
* Added olm-deployer crate.

* Update changelog.

* pass in deployer name

* replace unwrap() calls with context()

* regenerate-nix
  • Loading branch information
razvan authored Feb 11, 2025
1 parent 7f66b1d commit fc56f72
Show file tree
Hide file tree
Showing 12 changed files with 1,122 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ All notable changes to this project will be documented in this file.
### Added

- Aggregate emitted Kubernetes events on the CustomResources ([#267]).
- OLM deployment helper ([#279]).

### Changed

- Default to OCI for image metadata ([#268]).

[#267]: https://github.com/stackabletech/listener-operator/pull/267
[#268]: https://github.com/stackabletech/listener-operator/pull/268
[#279]: https://github.com/stackabletech/listener-operator/pull/279

## [24.11.1] - 2025-01-10

Expand Down
44 changes: 44 additions & 0 deletions Cargo.lock

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

131 changes: 131 additions & 0 deletions Cargo.nix

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

5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = ["rust/operator-binary", "rust/csi-grpc"]
members = ["rust/operator-binary", "rust/csi-grpc", "rust/olm-deployer"]
resolver = "2"

[workspace.package]
Expand All @@ -21,6 +21,8 @@ pin-project = "1.1"
prost = "0.13"
prost-types = "0.13"
serde = "1.0"
serde_json = "1.0"
serde_yaml = "0.9"
snafu = "0.8"
stackable-operator = { git = "https://github.com/stackabletech/operator-rs.git", tag = "stackable-operator-0.85.0" }
strum = { version = "0.26", features = ["derive"] }
Expand All @@ -31,6 +33,7 @@ tonic = "0.12"
tonic-build = "0.12"
tonic-reflection = "0.12"
tracing = "0.1.40"
walkdir = "2.5.0"

[patch."https://github.com/stackabletech/operator-rs.git"]
# stackable-operator = { path = "../operator-rs/crates/stackable-operator" }
Expand Down
23 changes: 23 additions & 0 deletions rust/olm-deployer/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[package]
name = "olm-deployer"
description = "OLM deployment helper."
version.workspace = true
authors.workspace = true
license.workspace = true
edition.workspace = true
repository.workspace = true
publish = false

[dependencies]
anyhow.workspace = true
clap.workspace = true
tokio.workspace = true
tracing.workspace = true
stackable-operator.workspace = true
serde.workspace = true
serde_json.workspace = true
serde_yaml.workspace = true
walkdir.workspace = true

[build-dependencies]
built.workspace = true
3 changes: 3 additions & 0 deletions rust/olm-deployer/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
built::write_built_file().unwrap();
}
72 changes: 72 additions & 0 deletions rust/olm-deployer/src/data.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use anyhow::{anyhow, Context};
use stackable_operator::kube::{api::DynamicObject, ResourceExt};

pub fn container<'a>(
target: &'a mut DynamicObject,
container_name: &str,
) -> anyhow::Result<&'a mut serde_json::Value> {
let tname = target.name_any();
let path = "template/spec/containers".split("/");
match get_or_create(
target
.data
.pointer_mut("/spec")
.context(anyhow!("object [{tname}] has no .spec property"))?,
path,
)? {
serde_json::Value::Array(containers) => {
for c in containers {
if c.is_object() {
if let Some(serde_json::Value::String(name)) = c.get("name") {
if container_name == name {
return Ok(c);
}
}
} else {
anyhow::bail!("container is not a object: {:?}", c);
}
}
anyhow::bail!("container named {container_name} not found");
}
_ => anyhow::bail!("no containers found in object {tname}"),
}
}

/// Returns the object nested in `root` by traversing the `path` of nested keys.
/// Creates any missing objects in path.
/// In case of success, the returned value is either the existing object or
/// serde_json::Value::Null.
/// Returns an error if any of the nested objects has a type other than map.
pub fn get_or_create<'a, 'b, I>(
root: &'a mut serde_json::Value,
path: I,
) -> anyhow::Result<&'a mut serde_json::Value>
where
I: IntoIterator<Item = &'b str>,
{
let mut iter = path.into_iter();
match iter.next() {
None => Ok(root),
Some(first) => {
let new_root = get_or_insert_default_object(root, first)?;
get_or_create(new_root, iter)
}
}
}

/// Given a map object create or return the object corresponding to the given `key`.
fn get_or_insert_default_object<'a>(
value: &'a mut serde_json::Value,
key: &str,
) -> anyhow::Result<&'a mut serde_json::Value> {
let map = match value {
serde_json::Value::Object(map) => map,
x @ serde_json::Value::Null => {
*x = serde_json::json!({});
x.as_object_mut()
.context(anyhow!("expected an empty map for [{key}] but found null"))?
}
x => anyhow::bail!("invalid type {x:?}, expected map"),
};
Ok(map.entry(key).or_insert_with(|| serde_json::Value::Null))
}
Loading

0 comments on commit fc56f72

Please sign in to comment.