11//! The dereference step in the DruidCluster controller
2- //!
3- //! Fetches all Kubernetes objects referenced by the DruidCluster spec and returns them in
4- //! [`DereferencedObjects`]. AuthenticationClasses are fetched raw here
5- //! ([`fetch_authentication_classes`]) and validated later in the validate step. The remaining
6- //! helpers (`DruidCluster::get_s3_connection`, `S3Bucket::resolve`,
7- //! `OpaConfig::full_document_url_from_config_map`) still mix fetching and validation; their
8- //! outputs are treated as "dereferenced" for now. Splitting those is a follow-up.
92
103use snafu:: { OptionExt , ResultExt , Snafu } ;
114use stackable_operator:: {
@@ -50,11 +43,13 @@ pub enum Error {
5043 cm_name : String ,
5144 } ,
5245
53- #[ snafu( display( "failed to get valid S3 connection" ) ) ]
54- GetS3Connection { source : crate :: crd:: Error } ,
46+ #[ snafu( display( "failed to resolve the ingestion S3 connection" ) ) ]
47+ ResolveS3Connection {
48+ source : stackable_operator:: crd:: s3:: v1alpha1:: ConnectionError ,
49+ } ,
5550
56- #[ snafu( display( "failed to get deep storage bucket" ) ) ]
57- GetDeepStorageBucket {
51+ #[ snafu( display( "failed to resolve the deep storage S3 bucket" ) ) ]
52+ ResolveS3Bucket {
5853 source : stackable_operator:: crd:: s3:: v1alpha1:: BucketError ,
5954 } ,
6055
@@ -66,13 +61,19 @@ pub enum Error {
6661
6762type Result < T , E = Error > = std:: result:: Result < T , E > ;
6863
69- /// Kubernetes objects referenced from the DruidCluster spec, already fetched (and, for now,
70- /// partly validated by the existing helper functions) .
64+ /// Kubernetes objects referenced from the DruidCluster spec, already fetched. Validation and
65+ /// derivation of final values happens in the validate step .
7166pub struct DereferencedObjects {
7267 pub zookeeper_connection_string : String ,
73- pub opa_connection_string : Option < String > ,
74- pub s3_connection : Option < s3:: v1alpha1:: ConnectionSpec > ,
75- pub deep_storage_bucket_name : Option < String > ,
68+ /// The rule-agnostic OPA document URL (package level, no rule). The validate step appends the
69+ /// concrete authorization rule to produce the connection string.
70+ pub opa_base_document_url : Option < String > ,
71+ /// The resolved ingestion S3 connection (if any). The validate step checks it against the deep
72+ /// storage connection.
73+ pub s3_ingestion_connection : Option < s3:: v1alpha1:: ConnectionSpec > ,
74+ /// The resolved deep storage S3 bucket (if deep storage uses S3). Carries both the bucket name
75+ /// and its connection.
76+ pub s3_deep_storage_bucket : Option < s3:: v1alpha1:: ResolvedBucket > ,
7677 /// The raw, fetched `AuthenticationClass` objects (in spec order). Validation of these happens
7778 /// in the validate step via [`AuthenticationClassesResolved::from_fetched`].
7879 pub authentication_classes : Vec < core:: v1alpha1:: AuthenticationClass > ,
@@ -106,12 +107,14 @@ pub async fn dereference(
106107 cm_name : zk_confmap. clone ( ) ,
107108 } ) ?;
108109
109- let opa_connection_string = if let Some ( DruidAuthorization { opa : opa_config } ) =
110+ // Fetch the rule-agnostic OPA document URL (package level, no rule). The validate step appends
111+ // the concrete authorization rule.
112+ let opa_base_document_url = if let Some ( DruidAuthorization { opa : opa_config } ) =
110113 & druid. spec . cluster_config . authorization
111114 {
112115 Some (
113116 opa_config
114- . full_document_url_from_config_map ( client, druid, Some ( "allow" ) , & OpaApiVersion :: V1 )
117+ . full_document_url_from_config_map ( client, druid, None , & OpaApiVersion :: V1 )
115118 . await
116119 . context ( GetOpaConnStringSnafu {
117120 cm_name : opa_config. config_map_name . clone ( ) ,
@@ -121,20 +124,34 @@ pub async fn dereference(
121124 None
122125 } ;
123126
124- let s3_connection = druid
125- . get_s3_connection ( client)
126- . await
127- . context ( GetS3ConnectionSnafu ) ?;
127+ // Resolve the ingestion and deep storage S3 references separately. Checking that they are
128+ // compatible (and extracting the bucket name) is done in the validate step.
129+ let s3_ingestion_connection = if let Some ( ingestion_connection) = druid
130+ . spec
131+ . cluster_config
132+ . ingestion
133+ . as_ref ( )
134+ . and_then ( |ingestion| ingestion. s3connection . as_ref ( ) )
135+ {
136+ Some (
137+ ingestion_connection
138+ . clone ( )
139+ . resolve ( client, namespace)
140+ . await
141+ . context ( ResolveS3ConnectionSnafu ) ?,
142+ )
143+ } else {
144+ None
145+ } ;
128146
129- let deep_storage_bucket_name = match & druid. spec . cluster_config . deep_storage {
147+ let s3_deep_storage_bucket = match & druid. spec . cluster_config . deep_storage {
130148 DeepStorageSpec :: S3 ( s3_spec) => Some (
131149 s3_spec
132150 . bucket
133151 . clone ( )
134152 . resolve ( client, namespace)
135153 . await
136- . context ( GetDeepStorageBucketSnafu ) ?
137- . bucket_name ,
154+ . context ( ResolveS3BucketSnafu ) ?,
138155 ) ,
139156 _ => None ,
140157 } ;
@@ -145,9 +162,9 @@ pub async fn dereference(
145162
146163 Ok ( DereferencedObjects {
147164 zookeeper_connection_string,
148- opa_connection_string ,
149- s3_connection ,
150- deep_storage_bucket_name ,
165+ opa_base_document_url ,
166+ s3_ingestion_connection ,
167+ s3_deep_storage_bucket ,
151168 authentication_classes,
152169 } )
153170}
0 commit comments