Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ All notable changes to this project will be documented in this file.
- Internal operator refactoring: introduce a build() step in the reconciler that
assembles all relevant Kubernetes resources before anything is applied ([#852]).
- Bump `stackable-operator` to 0.114.0 ([#867]).
- The RBAC ServiceAccount and RoleBinding are now built with the operator-rs `v2::rbac`
functions and carry the full set of recommended labels ([#861]).

[#852]: https://github.com/stackabletech/opa-operator/pull/852
[#861]: https://github.com/stackabletech/opa-operator/pull/861
[#867]: https://github.com/stackabletech/opa-operator/pull/867

## [26.7.0] - 2026-07-21
Expand Down
40 changes: 36 additions & 4 deletions rust/operator-binary/src/controller/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,19 @@
use std::str::FromStr;

use snafu::{ResultExt, Snafu};
use stackable_operator::{utils::cluster_info::KubernetesClusterInfo, v2::types::common::Port};
use stackable_operator::{
builder::meta::ObjectMetaBuilder,
utils::cluster_info::KubernetesClusterInfo,
v2::{builder::meta::ownerreference_from_resource, types::common::Port},
};

use crate::controller::{
KubernetesResources, RoleGroupName, ValidatedCluster,
build::resource::{
config_map::build_rolegroup_config_map,
daemonset::build_server_rolegroup_daemonset,
discovery::build_discovery_config_map,
rbac::{build_role_binding, build_service_account},
service::{
build_rolegroup_headless_service, build_rolegroup_metrics_service,
build_server_role_service,
Expand Down Expand Up @@ -51,7 +56,6 @@ pub enum Error {
/// Kubernetes cluster domain used in the discovery URL and the sidecar environment.
pub fn build(
cluster: &ValidatedCluster,
service_account_name: &str,
opa_bundle_builder_image: &str,
user_info_fetcher_image: &str,
cluster_info: &KubernetesClusterInfo,
Expand Down Expand Up @@ -81,7 +85,6 @@ pub fn build(
role_group,
opa_bundle_builder_image,
user_info_fetcher_image,
service_account_name,
cluster_info,
)
.context(DaemonSetSnafu {
Expand All @@ -98,6 +101,8 @@ pub fn build(
daemon_sets,
services,
config_maps,
service_accounts: vec![build_service_account(cluster)],
role_bindings: vec![build_role_binding(cluster)],
})
}

Expand All @@ -113,6 +118,25 @@ stackable_operator::constant!(pub(crate) PLACEHOLDER_ROLE_LEVEL_ROLE_GROUP: Role
// cluster-level object not bound to a single role group.
stackable_operator::constant!(pub(crate) PLACEHOLDER_DISCOVERY_ROLE_GROUP: RoleGroupName = "discovery");

/// Returns an [`ObjectMetaBuilder`] pre-filled with the namespace, an owner reference back to
/// the cluster, and the recommended labels for a resource named `name` in `role_group_name`.
///
/// Consolidates the metadata chain repeated by the child-resource builders. Call sites that
/// need extra labels/annotations chain them onto the returned builder before calling `build()`.
pub(crate) fn object_meta(
cluster: &ValidatedCluster,
name: impl Into<String>,
role_group_name: &RoleGroupName,
) -> ObjectMetaBuilder {
let mut builder = ObjectMetaBuilder::new();
builder
.name_and_namespace(cluster)
.name(name)
.ownerreference(ownerreference_from_resource(cluster, None, Some(true)))
.with_labels(cluster.recommended_labels(role_group_name));
builder
}

#[cfg(test)]
mod tests {
use serde_json::json;
Expand Down Expand Up @@ -152,7 +176,6 @@ mod tests {
fn build_produces_expected_resource_names() {
let resources = build(
&cluster(),
"test-opa-serviceaccount",
"bundle-builder-image",
"user-info-fetcher-image",
&cluster_info(),
Expand All @@ -178,5 +201,14 @@ mod tests {
sorted_names(&resources.config_maps),
["test-opa", "test-opa-server-default"]
);
// The cluster-shared RBAC pair.
assert_eq!(
sorted_names(&resources.service_accounts),
["test-opa-serviceaccount"]
);
assert_eq!(
sorted_names(&resources.role_bindings),
["test-opa-rolebinding"]
);
}
}
15 changes: 15 additions & 0 deletions rust/operator-binary/src/controller/build/properties/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,23 @@ pub(crate) mod test_support {
crd::v1alpha2,
};

/// The expected `app.kubernetes.io/version` label value for the given product version.
///
/// The `-stackable` suffix carries the operator's own version, which is `0.0.0-dev` on main
/// but rewritten by the release process — so tests must derive it rather than hardcode it,
/// or they fail on release branches.
pub fn app_version_label(product_version: &str) -> String {
format!(
"{product_version}-stackable{}",
crate::built_info::PKG_VERSION
)
}

/// Builds an `OpaCluster` from the given `spec` JSON and runs the validate step, returning the
/// resulting [`ValidatedCluster`].
///
/// The cluster name (`test-opa`) deliberately differs from the product name (`opa`), so tests
/// asserting recommended labels catch swapped `name`/`instance` values.
pub fn validated_cluster_from_spec(spec: Value) -> ValidatedCluster {
let opa: v1alpha2::OpaCluster = serde_json::from_value(json!({
"apiVersion": "opa.stackable.tech/v1alpha2",
Expand Down
23 changes: 13 additions & 10 deletions rust/operator-binary/src/controller/build/resource/config_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ use stackable_operator::{

use crate::controller::{
OpaRoleGroupConfig, RoleGroupName, ValidatedCluster,
build::properties::{ConfigFileName, config_json, product_logging, user_info_fetcher},
build::{
object_meta,
properties::{ConfigFileName, config_json, product_logging, user_info_fetcher},
},
};

#[derive(Snafu, Debug)]
Expand Down Expand Up @@ -41,15 +44,15 @@ pub fn build_rolegroup_config_map(
) -> Result<ConfigMap> {
let mut cm_builder = ConfigMapBuilder::new();

let metadata = cluster
.object_meta(
cluster
.resource_names(role_group_name)
.role_group_config_map()
.to_string(),
role_group_name,
)
.build();
let metadata = object_meta(
cluster,
cluster
.role_group_resource_names(role_group_name)
.role_group_config_map()
.to_string(),
role_group_name,
)
.build();

cm_builder.metadata(metadata).add_data(
ConfigFileName::ConfigJson.to_string(),
Expand Down
35 changes: 19 additions & 16 deletions rust/operator-binary/src/controller/build/resource/daemonset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,6 @@ pub fn build_server_rolegroup_daemonset(
role_group: &OpaRoleGroupConfig,
opa_bundle_builder_image: &str,
user_info_fetcher_image: &str,
service_account_name: &str,
cluster_info: &KubernetesClusterInfo,
) -> Result<DaemonSet> {
let resolved_product_image = &cluster.image;
Expand Down Expand Up @@ -376,7 +375,7 @@ pub fn build_server_rolegroup_daemonset(
VolumeBuilder::new(CONFIG_VOLUME_NAME.as_ref())
.with_config_map(
cluster
.resource_names(role_group_name)
.role_group_resource_names(role_group_name)
.role_group_config_map()
.to_string(),
)
Expand Down Expand Up @@ -404,7 +403,12 @@ pub fn build_server_rolegroup_daemonset(
.build(),
)
.context(AddVolumeSnafu)?
.service_account_name(service_account_name)
.service_account_name(
cluster
.cluster_resource_names()
.service_account_name()
.to_string(),
)
.security_context(PodSecurityContextBuilder::new().fs_group(1000).build());

if let Some(tls) = &cluster.cluster_config.tls {
Expand All @@ -419,13 +423,13 @@ pub fn build_server_rolegroup_daemonset(
.with_service_scope(cluster.server_role_service_name())
.with_service_scope(
cluster
.resource_names(role_group_name)
.role_group_resource_names(role_group_name)
.headless_service_name()
.to_string(),
)
.with_service_scope(
cluster
.resource_names(role_group_name)
.role_group_resource_names(role_group_name)
.metrics_service_name()
.to_string(),
)
Expand Down Expand Up @@ -568,7 +572,7 @@ pub fn build_server_rolegroup_daemonset(
&container_name(&Container::Vector),
resolved_product_image,
vector_log_config,
&cluster.resource_names(role_group_name),
&cluster.role_group_resource_names(role_group_name),
&CONFIG_VOLUME_NAME,
&LOG_VOLUME_NAME,
EnvVarSet::new(),
Expand All @@ -580,15 +584,15 @@ pub fn build_server_rolegroup_daemonset(
let mut pod_template = pb.build_template();
pod_template.merge_from(rolegroup_config.pod_overrides.clone());

let metadata = cluster
.object_meta(
cluster
.resource_names(role_group_name)
.daemon_set_name()
.to_string(),
role_group_name,
)
.build();
let metadata = build::object_meta(
cluster,
cluster
.role_group_resource_names(role_group_name)
.daemon_set_name()
.to_string(),
role_group_name,
)
.build();

let daemonset_spec = DaemonSetSpec {
selector: LabelSelector {
Expand Down Expand Up @@ -870,7 +874,6 @@ mod tests {
role_group,
"bundle-builder-image",
"user-info-fetcher-image",
"test-opa-serviceaccount",
&cluster_info(),
)
.expect("the daemonset should build")
Expand Down
14 changes: 10 additions & 4 deletions rust/operator-binary/src/controller/build/resource/discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ use stackable_operator::{
};

use super::service::{APP_PORT, APP_TLS_PORT};
use crate::controller::{ValidatedCluster, build::PLACEHOLDER_DISCOVERY_ROLE_GROUP};
use crate::controller::{
ValidatedCluster,
build::{PLACEHOLDER_DISCOVERY_ROLE_GROUP, object_meta},
};

#[derive(Snafu, Debug)]
pub enum Error {
Expand Down Expand Up @@ -39,9 +42,12 @@ pub fn build_discovery_config_map(

// Discovery is a cluster-level object (named after the cluster); `discovery` is used as a
// placeholder role-group name for the recommended labels.
let metadata = cluster
.object_meta(cluster.name.to_string(), &PLACEHOLDER_DISCOVERY_ROLE_GROUP)
.build();
let metadata = object_meta(
cluster,
cluster.name.to_string(),
&PLACEHOLDER_DISCOVERY_ROLE_GROUP,
)
.build();

let mut cm_builder = ConfigMapBuilder::new();
cm_builder.metadata(metadata).add_data("OPA", url);
Expand Down
1 change: 1 addition & 0 deletions rust/operator-binary/src/controller/build/resource/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
pub mod config_map;
pub mod daemonset;
pub mod discovery;
pub mod rbac;
pub mod service;
Loading
Loading