Skip to content

Commit fc56f72

Browse files
authored
feat: olm deployment helper (#279)
* Added olm-deployer crate. * Update changelog. * pass in deployer name * replace unwrap() calls with context() * regenerate-nix
1 parent 7f66b1d commit fc56f72

File tree

12 files changed

+1122
-1
lines changed

12 files changed

+1122
-1
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ All notable changes to this project will be documented in this file.
77
### Added
88

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

1112
### Changed
1213

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

1516
[#267]: https://github.com/stackabletech/listener-operator/pull/267
1617
[#268]: https://github.com/stackabletech/listener-operator/pull/268
18+
[#279]: https://github.com/stackabletech/listener-operator/pull/279
1719

1820
## [24.11.1] - 2025-01-10
1921

Cargo.lock

Lines changed: 44 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.nix

Lines changed: 131 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[workspace]
2-
members = ["rust/operator-binary", "rust/csi-grpc"]
2+
members = ["rust/operator-binary", "rust/csi-grpc", "rust/olm-deployer"]
33
resolver = "2"
44

55
[workspace.package]
@@ -21,6 +21,8 @@ pin-project = "1.1"
2121
prost = "0.13"
2222
prost-types = "0.13"
2323
serde = "1.0"
24+
serde_json = "1.0"
25+
serde_yaml = "0.9"
2426
snafu = "0.8"
2527
stackable-operator = { git = "https://github.com/stackabletech/operator-rs.git", tag = "stackable-operator-0.85.0" }
2628
strum = { version = "0.26", features = ["derive"] }
@@ -31,6 +33,7 @@ tonic = "0.12"
3133
tonic-build = "0.12"
3234
tonic-reflection = "0.12"
3335
tracing = "0.1.40"
36+
walkdir = "2.5.0"
3437

3538
[patch."https://github.com/stackabletech/operator-rs.git"]
3639
# stackable-operator = { path = "../operator-rs/crates/stackable-operator" }

rust/olm-deployer/Cargo.toml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[package]
2+
name = "olm-deployer"
3+
description = "OLM deployment helper."
4+
version.workspace = true
5+
authors.workspace = true
6+
license.workspace = true
7+
edition.workspace = true
8+
repository.workspace = true
9+
publish = false
10+
11+
[dependencies]
12+
anyhow.workspace = true
13+
clap.workspace = true
14+
tokio.workspace = true
15+
tracing.workspace = true
16+
stackable-operator.workspace = true
17+
serde.workspace = true
18+
serde_json.workspace = true
19+
serde_yaml.workspace = true
20+
walkdir.workspace = true
21+
22+
[build-dependencies]
23+
built.workspace = true

rust/olm-deployer/build.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fn main() {
2+
built::write_built_file().unwrap();
3+
}

rust/olm-deployer/src/data.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
use anyhow::{anyhow, Context};
2+
use stackable_operator::kube::{api::DynamicObject, ResourceExt};
3+
4+
pub fn container<'a>(
5+
target: &'a mut DynamicObject,
6+
container_name: &str,
7+
) -> anyhow::Result<&'a mut serde_json::Value> {
8+
let tname = target.name_any();
9+
let path = "template/spec/containers".split("/");
10+
match get_or_create(
11+
target
12+
.data
13+
.pointer_mut("/spec")
14+
.context(anyhow!("object [{tname}] has no .spec property"))?,
15+
path,
16+
)? {
17+
serde_json::Value::Array(containers) => {
18+
for c in containers {
19+
if c.is_object() {
20+
if let Some(serde_json::Value::String(name)) = c.get("name") {
21+
if container_name == name {
22+
return Ok(c);
23+
}
24+
}
25+
} else {
26+
anyhow::bail!("container is not a object: {:?}", c);
27+
}
28+
}
29+
anyhow::bail!("container named {container_name} not found");
30+
}
31+
_ => anyhow::bail!("no containers found in object {tname}"),
32+
}
33+
}
34+
35+
/// Returns the object nested in `root` by traversing the `path` of nested keys.
36+
/// Creates any missing objects in path.
37+
/// In case of success, the returned value is either the existing object or
38+
/// serde_json::Value::Null.
39+
/// Returns an error if any of the nested objects has a type other than map.
40+
pub fn get_or_create<'a, 'b, I>(
41+
root: &'a mut serde_json::Value,
42+
path: I,
43+
) -> anyhow::Result<&'a mut serde_json::Value>
44+
where
45+
I: IntoIterator<Item = &'b str>,
46+
{
47+
let mut iter = path.into_iter();
48+
match iter.next() {
49+
None => Ok(root),
50+
Some(first) => {
51+
let new_root = get_or_insert_default_object(root, first)?;
52+
get_or_create(new_root, iter)
53+
}
54+
}
55+
}
56+
57+
/// Given a map object create or return the object corresponding to the given `key`.
58+
fn get_or_insert_default_object<'a>(
59+
value: &'a mut serde_json::Value,
60+
key: &str,
61+
) -> anyhow::Result<&'a mut serde_json::Value> {
62+
let map = match value {
63+
serde_json::Value::Object(map) => map,
64+
x @ serde_json::Value::Null => {
65+
*x = serde_json::json!({});
66+
x.as_object_mut()
67+
.context(anyhow!("expected an empty map for [{key}] but found null"))?
68+
}
69+
x => anyhow::bail!("invalid type {x:?}, expected map"),
70+
};
71+
Ok(map.entry(key).or_insert_with(|| serde_json::Value::Null))
72+
}

0 commit comments

Comments
 (0)