11//! The validate step in the NifiCluster controller
22//!
3- //! Synchronously validates inputs that don't require a Kubernetes client . Produces
3+ //! Synchronously validates inputs that don't require Kubernetes API calls . Produces
44//! [`ValidatedInputs`], consumed by the rest of `reconcile_nifi`.
55
6+ use std:: collections:: HashSet ;
7+
68use product_config:: ProductConfigManager ;
79use snafu:: { OptionExt , ResultExt , Snafu } ;
810use stackable_operator:: {
911 cli:: OperatorEnvironmentOptions ,
1012 commons:: product_image_selection:: { self , ResolvedProductImage } ,
1113 product_config_utils:: ValidatedRoleConfigByPropertyKind ,
14+ utils:: cluster_info:: KubernetesClusterInfo ,
1215} ;
1316use strum:: { EnumDiscriminants , IntoStaticStr } ;
1417
1518use crate :: {
1619 config:: { self , validated_product_config} ,
1720 controller:: dereference:: DereferencedObjects ,
18- crd:: v1alpha1,
21+ crd:: { HTTPS_PORT , v1alpha1} ,
22+ reporting_task,
1923 security:: {
2024 authentication:: { self , NifiAuthenticationConfig } ,
2125 authorization:: ResolvedNifiAuthorizationConfig ,
@@ -42,6 +46,11 @@ pub enum Error {
4246 #[ snafu( source( from( config:: Error , Box :: new) ) ) ]
4347 source : Box < config:: Error > ,
4448 } ,
49+
50+ #[ snafu( display( "failed to build reporting task service name" ) ) ]
51+ ReportingTask {
52+ source : crate :: reporting_task:: Error ,
53+ } ,
4554}
4655
4756type Result < T , E = Error > = std:: result:: Result < T , E > ;
@@ -52,6 +61,11 @@ pub struct ValidatedInputs {
5261 pub authentication_config : NifiAuthenticationConfig ,
5362 pub authorization_config : ResolvedNifiAuthorizationConfig ,
5463 pub validated_role_config : ValidatedRoleConfigByPropertyKind ,
64+ /// Comma-separated NiFi proxy hosts, or `"*"` if
65+ /// `spec.clusterConfig.hostHeaderCheck.allowAll` is set. Computed here so all derived
66+ /// inputs live in one place; previously this ran once per rolegroup inside the
67+ /// reconcile loop.
68+ pub proxy_hosts : String ,
5569}
5670
5771/// Validates the cluster spec and the dereferenced inputs.
@@ -60,6 +74,7 @@ pub fn validate(
6074 dereferenced_objects : & DereferencedObjects ,
6175 operator_environment : & OperatorEnvironmentOptions ,
6276 product_config : & ProductConfigManager ,
77+ cluster_info : & KubernetesClusterInfo ,
6378) -> Result < ValidatedInputs > {
6479 let image = nifi
6580 . spec
@@ -88,10 +103,52 @@ pub fn validate(
88103 )
89104 . context ( ProductConfigLoadFailedSnafu ) ?;
90105
106+ let proxy_hosts = compute_proxy_hosts ( nifi, cluster_info) ?;
107+
91108 Ok ( ValidatedInputs {
92109 image,
93110 authentication_config,
94111 authorization_config,
95112 validated_role_config,
113+ proxy_hosts,
96114 } )
97115}
116+
117+ fn compute_proxy_hosts (
118+ nifi : & v1alpha1:: NifiCluster ,
119+ cluster_info : & KubernetesClusterInfo ,
120+ ) -> Result < String > {
121+ let host_header_check = & nifi. spec . cluster_config . host_header_check ;
122+
123+ if host_header_check. allow_all {
124+ tracing:: info!(
125+ "spec.clusterConfig.hostHeaderCheck.allowAll is set to true. All proxy hosts will be allowed."
126+ ) ;
127+ if !host_header_check. additional_allowed_hosts . is_empty ( ) {
128+ tracing:: info!(
129+ "spec.clusterConfig.hostHeaderCheck.additionalAllowedHosts is ignored and only '*' is added to the allow-list."
130+ )
131+ }
132+ return Ok ( "*" . to_string ( ) ) ;
133+ }
134+
135+ // Address and port are injected from the listener volume during the prepare container
136+ let mut proxy_hosts = HashSet :: from ( [
137+ "${env:LISTENER_DEFAULT_ADDRESS}:${env:LISTENER_DEFAULT_PORT_HTTPS}" . to_string ( ) ,
138+ ] ) ;
139+ proxy_hosts. extend ( host_header_check. additional_allowed_hosts . iter ( ) . cloned ( ) ) ;
140+
141+ // Reporting task only exists for NiFi 1.x
142+ if nifi. spec . image . product_version ( ) . starts_with ( "1." ) {
143+ let reporting_task_service_name =
144+ reporting_task:: build_reporting_task_fqdn_service_name ( nifi, cluster_info)
145+ . context ( ReportingTaskSnafu ) ?;
146+
147+ proxy_hosts. insert ( format ! ( "{reporting_task_service_name}:{HTTPS_PORT}" ) ) ;
148+ }
149+
150+ let mut proxy_hosts = Vec :: from_iter ( proxy_hosts) ;
151+ proxy_hosts. sort ( ) ;
152+
153+ Ok ( proxy_hosts. join ( "," ) )
154+ }
0 commit comments