Skip to content

Commit e60e967

Browse files
authored
chore: update olm deployer (#648)
* fix: remove cluster info cli arguments from olm deployer * need to pass a domain name * copy subscription env to op deployment too * cannot patch the ns of the tls secret class anymore * set deployment tolerations too * patch deployment resources too * update changelog * updated olm deployer readme
1 parent 76936be commit e60e967

File tree

8 files changed

+87
-147
lines changed

8 files changed

+87
-147
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ All notable changes to this project will be documented in this file.
2929
- `kubeletDir` has been move to `csiNodeDriver.kubeletDir`.
3030
- Bump csi-node-driver-registrar to `v2.15.0` ([#642]).
3131
- Bump csi-provisioner to `v5.3.0` ([#643]).
32+
- OLM deployer: patch the new Deployment object too and other changes to align with the new operator structure ([#648]).
3233

3334
[#597]: https://github.com/stackabletech/secret-operator/pull/597
3435
[#636]: https://github.com/stackabletech/secret-operator/pull/636
@@ -37,6 +38,7 @@ All notable changes to this project will be documented in this file.
3738
[#643]: https://github.com/stackabletech/secret-operator/pull/643
3839
[#644]: https://github.com/stackabletech/secret-operator/pull/644
3940
[#645]: https://github.com/stackabletech/secret-operator/pull/645
41+
[#648]: https://github.com/stackabletech/secret-operator/pull/648
4042

4143
## [25.7.0] - 2025-07-23
4244

rust/olm-deployer/README.md

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,25 @@
1-
# How to test
1+
# Description
2+
3+
This is an deployment helper for the Operator Lifecycle Manager which is usually present on OpenShift environments.
4+
5+
It is needed to work around various OLM restrictions.
6+
7+
What it does:
8+
9+
- creates Security Context Constraints just for this operator (maybe remove in the future)
10+
- installs the Deployment and DaemonSet objects
11+
- installs the operator webhook service
12+
- installs the CSI driver and storage classes
13+
- assigns it's own deployment as owner of all the namespaced objects to ensure proper cleanup
14+
- patches the environment of all workload containers with any custom values provided in the Subscription object
15+
- patches the resources of all workload containers with any custom values provided in the Subscription object
16+
- patches the tolerations of all workload pods with any custom values provided in the Subscription object
17+
18+
## Usage
19+
20+
Users do not need to interact with the OLM deployer directly.
21+
22+
## How to Test
223

324
Requirements:
425

rust/olm-deployer/src/data.rs

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,12 @@
1-
use anyhow::{Result, bail};
21
use stackable_operator::kube::{ResourceExt, api::DynamicObject};
32

4-
pub fn data_field_as_mut<'a>(
5-
value: &'a mut serde_json::Value,
6-
pointer: &str,
7-
) -> Result<&'a mut serde_json::Value> {
8-
match value.pointer_mut(pointer) {
9-
Some(field) => Ok(field),
10-
x => bail!("invalid pointer {pointer} for object {x:?}"),
11-
}
12-
}
13-
14-
pub fn container<'a>(
3+
pub fn containers<'a>(
154
target: &'a mut DynamicObject,
16-
container_name: &str,
17-
) -> anyhow::Result<&'a mut serde_json::Value> {
5+
) -> anyhow::Result<&'a mut Vec<serde_json::Value>> {
186
let tname = target.name_any();
197
let path = "template/spec/containers".split("/");
208
match get_or_create(target.data.pointer_mut("/spec").unwrap(), path)? {
21-
serde_json::Value::Array(containers) => {
22-
for c in containers {
23-
if c.is_object() {
24-
if let Some(serde_json::Value::String(name)) = c.get("name") {
25-
if container_name == name {
26-
return Ok(c);
27-
}
28-
}
29-
} else {
30-
anyhow::bail!("container is not a object: {:?}", c);
31-
}
32-
}
33-
anyhow::bail!("container named {container_name} not found");
34-
}
9+
serde_json::Value::Array(containers) => Ok(containers),
3510
_ => anyhow::bail!("no containers found in object {tname}"),
3611
}
3712
}

rust/olm-deployer/src/env/mod.rs

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,41 +6,46 @@ use stackable_operator::{
66
},
77
};
88

9-
use crate::data::container;
9+
use crate::data::containers;
1010

1111
/// Copy the environment from the "secret-operator-deployer" container in `source`
12-
/// to the container "secret-operator" in `target`.
13-
/// The `target` must be a DaemonSet object otherwise this is a no-op.
12+
/// to *all* containers in target.
13+
/// The target must be a DaemonSet or Deployment, otherwise this function is a no-op.
14+
/// This function allows OLM Subscription objects to configure the environment
15+
/// of operator containers.
1416
pub(super) fn maybe_copy_env(
1517
source: &Deployment,
1618
target: &mut DynamicObject,
1719
target_gvk: &GroupVersionKind,
1820
) -> anyhow::Result<()> {
19-
if target_gvk.kind == "DaemonSet" {
21+
let target_kind_set = ["DaemonSet", "Deployment"];
22+
if target_kind_set.contains(&target_gvk.kind.as_str()) {
2023
if let Some(env) = deployer_env_var(source) {
21-
match container(target, "secret-operator")? {
22-
serde_json::Value::Object(c) => {
23-
let json_env = env
24-
.iter()
25-
.map(|e| serde_json::json!(e))
26-
.collect::<Vec<serde_json::Value>>();
27-
28-
match c.get_mut("env") {
29-
Some(env) => match env {
30-
v @ serde_json::Value::Null => {
31-
*v = serde_json::json!(json_env);
24+
for container in containers(target)? {
25+
match container {
26+
serde_json::Value::Object(c) => {
27+
let json_env = env
28+
.iter()
29+
.map(|e| serde_json::json!(e))
30+
.collect::<Vec<serde_json::Value>>();
31+
32+
match c.get_mut("env") {
33+
Some(env) => match env {
34+
v @ serde_json::Value::Null => {
35+
*v = serde_json::json!(json_env);
36+
}
37+
serde_json::Value::Array(container_env) => {
38+
container_env.extend_from_slice(&json_env)
39+
}
40+
_ => anyhow::bail!("env is not null or an array"),
41+
},
42+
None => {
43+
c.insert("env".to_string(), serde_json::json!(json_env));
3244
}
33-
serde_json::Value::Array(container_env) => {
34-
container_env.extend_from_slice(&json_env)
35-
}
36-
_ => anyhow::bail!("env is not null or an array"),
37-
},
38-
None => {
39-
c.insert("env".to_string(), serde_json::json!(json_env));
4045
}
4146
}
47+
_ => anyhow::bail!("no containers found in object {}", target.name_any()),
4248
}
43-
_ => anyhow::bail!("no containers found in object {}", target.name_any()),
4449
}
4550
}
4651
}
@@ -149,7 +154,9 @@ spec:
149154
},
150155
]);
151156
assert_eq!(
152-
container(&mut daemonset, "secret-operator")?
157+
containers(&mut daemonset)?
158+
.first()
159+
.expect("daemonset has no containers")
153160
.get("env")
154161
.unwrap(),
155162
&expected

rust/olm-deployer/src/main.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
///
1414
mod data;
1515
mod env;
16-
mod namespace;
1716
mod owner;
1817
mod resources;
1918
mod tolerations;
@@ -23,6 +22,7 @@ use clap::Parser;
2322
use stackable_operator::{
2423
cli::Command,
2524
client,
25+
commons::networking::DomainName,
2626
k8s_openapi::api::{apps::v1::Deployment, rbac::v1::ClusterRole},
2727
kube::{
2828
self,
@@ -71,9 +71,6 @@ struct OlmDeployerRun {
7171

7272
#[command(flatten)]
7373
pub telemetry: TelemetryOptions,
74-
75-
#[command(flatten)]
76-
pub cluster_info: KubernetesClusterInfoOptions,
7774
}
7875

7976
#[tokio::main]
@@ -85,7 +82,6 @@ async fn main() -> Result<()> {
8582
namespace,
8683
dir,
8784
telemetry,
88-
cluster_info,
8985
}) = opts.cmd
9086
{
9187
// NOTE (@NickLarsenNZ): Before stackable-telemetry was used:
@@ -104,7 +100,13 @@ async fn main() -> Result<()> {
104100
description = built_info::PKG_DESCRIPTION
105101
);
106102

107-
let client = client::initialize_operator(Some(APP_NAME.to_string()), &cluster_info).await?;
103+
let dummy_cluster_info = KubernetesClusterInfoOptions {
104+
kubernetes_cluster_domain: Some(DomainName::try_from("cluster.local")?),
105+
kubernetes_node_name: "".to_string(),
106+
};
107+
108+
let client =
109+
client::initialize_operator(Some(APP_NAME.to_string()), &dummy_cluster_info).await?;
108110

109111
let deployment = get_deployment(&csv, &namespace, &client).await?;
110112
let cluster_role = get_cluster_role(&csv, &client).await?;
@@ -143,7 +145,6 @@ async fn main() -> Result<()> {
143145
&deployment,
144146
&cluster_role,
145147
)?;
146-
namespace::maybe_patch_namespace(&namespace, &mut obj, &gvk)?;
147148
env::maybe_copy_env(&deployment, &mut obj, &gvk)?;
148149
resources::maybe_copy_resources(&deployment, &mut obj, &gvk)?;
149150
// ---------- apply

rust/olm-deployer/src/namespace/mod.rs

Lines changed: 0 additions & 76 deletions
This file was deleted.

rust/olm-deployer/src/resources/mod.rs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,28 @@ use stackable_operator::{
66
},
77
};
88

9-
use crate::data::container;
9+
use crate::data::containers;
1010

1111
/// Copies the resources of the container named "secret-operator-deployer" from `source`
12-
/// to the container "secret-operator" in `target`.
13-
/// Does nothing if there are no resources or if the `target` is not a DaemonSet.
12+
/// to *all* containers in `target`.
13+
/// Does nothing if there are no resources or if the `target` is not a DaemonSet or a Deployment.
14+
/// This function allows OLM Subscription objects to configure the resources
15+
/// of operator containers.
1416
pub(super) fn maybe_copy_resources(
1517
source: &Deployment,
1618
target: &mut DynamicObject,
1719
target_gvk: &GroupVersionKind,
1820
) -> anyhow::Result<()> {
19-
if target_gvk.kind == "DaemonSet" {
21+
let target_kind_set = ["DaemonSet", "Deployment"];
22+
if target_kind_set.contains(&target_gvk.kind.as_str()) {
2023
if let Some(res) = deployment_resources(source) {
21-
match container(target, "secret-operator")? {
22-
serde_json::Value::Object(c) => {
23-
c.insert("resources".to_string(), serde_json::json!(res));
24+
for container in containers(target)? {
25+
match container {
26+
serde_json::Value::Object(c) => {
27+
c.insert("resources".to_string(), serde_json::json!(res));
28+
}
29+
_ => anyhow::bail!("no containers found in object {}", target.name_any()),
2430
}
25-
_ => anyhow::bail!("no containers found in object {}", target.name_any()),
2631
}
2732
}
2833
}
@@ -150,7 +155,9 @@ spec:
150155
..ResourceRequirements::default()
151156
});
152157
assert_eq!(
153-
container(&mut daemonset, "secret-operator")?
158+
containers(&mut daemonset)?
159+
.first()
160+
.expect("daemonset has no containers")
154161
.get("resources")
155162
.unwrap(),
156163
&expected

rust/olm-deployer/src/tolerations/mod.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@ use crate::data::get_or_create;
77

88
/// Copies the pod tolerations from the `source` to the `target`.
99
/// Does nothing if there are no tolerations or if the `target` is not
10-
/// a DaemonSet.
10+
/// a DaemonSet or a Deployment.
11+
/// Admins can configure Subscription tolerations when installing the operator
12+
/// and these need to be copied over to the objects created by the deployer.
1113
pub(super) fn maybe_copy_tolerations(
1214
source: &Deployment,
1315
target: &mut DynamicObject,
1416
target_gvk: &GroupVersionKind,
1517
) -> anyhow::Result<()> {
16-
if target_gvk.kind == "DaemonSet" {
18+
let target_kind_set = ["DaemonSet", "Deployment"];
19+
if target_kind_set.contains(&target_gvk.kind.as_str()) {
1720
if let Some(tolerations) = deployment_tolerations(source) {
1821
let path = "template/spec/tolerations".split("/");
1922
*get_or_create(target.data.pointer_mut("/spec").unwrap(), path)? = serde_json::json!(

0 commit comments

Comments
 (0)