@@ -38,7 +38,7 @@ use stackable_operator::{
3838 apps:: v1:: { DaemonSet , DaemonSetSpec } ,
3939 core:: v1:: {
4040 ConfigMap , EmptyDirVolumeSource , EnvVar , HTTPGetAction , Probe , SecretVolumeSource ,
41- Service , ServiceAccount , ServicePort , ServiceSpec ,
41+ ServiceAccount ,
4242 } ,
4343 } ,
4444 apimachinery:: pkg:: { apis:: meta:: v1:: LabelSelector , util:: intstr:: IntOrString } ,
@@ -49,7 +49,7 @@ use stackable_operator::{
4949 runtime:: { controller:: Action , reflector:: ObjectRef } ,
5050 Resource as KubeResource , ResourceExt ,
5151 } ,
52- kvp:: { Label , LabelError , Labels , ObjectLabels } ,
52+ kvp:: { LabelError , Labels , ObjectLabels } ,
5353 logging:: controller:: ReconcilerError ,
5454 memory:: { BinaryMultiple , MemoryQuantity } ,
5555 product_config_utils:: { transform_all_roles_to_config, validate_all_roles_and_groups_config} ,
@@ -79,6 +79,7 @@ use crate::{
7979 product_logging:: {
8080 extend_role_group_config_map, resolve_vector_aggregator_address, BundleBuilderLogLevel ,
8181 } ,
82+ service:: { build_discoverable_services, build_rolegroup_service, ServiceConfig } ,
8283} ;
8384
8485pub const OPA_CONTROLLER_NAME : & str = "opacluster" ;
@@ -318,6 +319,9 @@ pub enum Error {
318319 AddVolumeMount {
319320 source : builder:: pod:: container:: Error ,
320321 } ,
322+
323+ #[ snafu( display( "failed to build required services" ) ) ]
324+ BuildRequiredServices { source : crate :: service:: Error } ,
321325}
322326type Result < T , E = Error > = std:: result:: Result < T , E > ;
323327
@@ -447,21 +451,58 @@ pub async fn reconcile_opa(
447451 . await
448452 . context ( ResolveVectorAggregatorAddressSnafu ) ?;
449453
450- let server_role_service =
451- build_server_role_service_traffic_local ( opa, & resolved_product_image) ?;
452- // required for discovery config map later
453- let server_role_service = cluster_resources
454- . add ( client, server_role_service)
455- . await
456- . context ( ApplyRoleServiceSnafu ) ?;
454+ let required_services = vec ! [
455+ // The server-role service is the primary endpoint that should be used by clients that do
456+ // require local access - Deprecated, kept for downwards compatibility
457+ ServiceConfig {
458+ name: opa
459+ . server_role_service_name_itp_local_deprecated( )
460+ . context( RoleServiceNameNotFoundSnafu ) ?,
461+ internal_traffic_policy: "Local" . to_string( ) ,
462+ } ,
463+ // The server-role service is the primary endpoint that should be used by clients that do
464+ // require local access
465+ ServiceConfig {
466+ name: opa
467+ . server_role_service_name_itp_local( )
468+ . context( RoleServiceNameNotFoundSnafu ) ?,
469+ internal_traffic_policy: "Local" . to_string( ) ,
470+ } ,
471+ // The server-role service is the primary endpoint that should be used by clients that do
472+ // perform internal round robin
473+ ServiceConfig {
474+ name: opa
475+ . server_role_service_name_itp_cluster( )
476+ . context( RoleServiceNameNotFoundSnafu ) ?,
477+ internal_traffic_policy: "Cluster" . to_string( ) ,
478+ } ,
479+ ] ;
457480
458- let server_role_service_load_balanced =
459- build_server_role_service_traffic_cluster ( opa, & resolved_product_image) ?;
460- // required for discovery config map later
461- let server_role_service_load_balanced = cluster_resources
462- . add ( client, server_role_service_load_balanced)
463- . await
464- . context ( ApplyRoleServiceSnafu ) ?;
481+ let services = build_discoverable_services ( opa, & resolved_product_image, required_services)
482+ . context ( BuildRequiredServicesSnafu ) ?;
483+
484+ for svc in services {
485+ // required for discovery config map later
486+ let role_service = cluster_resources
487+ . add ( client, svc)
488+ . await
489+ . context ( ApplyRoleServiceSnafu ) ?;
490+
491+ let discovery_cm = build_discovery_configmap (
492+ & role_service. name_any ( ) ,
493+ opa,
494+ opa,
495+ & resolved_product_image,
496+ & role_service,
497+ & client. kubernetes_cluster_info ,
498+ )
499+ . context ( BuildDiscoveryConfigSnafu ) ?;
500+
501+ cluster_resources
502+ . add ( client, discovery_cm)
503+ . await
504+ . context ( ApplyDiscoveryConfigSnafu ) ?;
505+ }
465506
466507 let required_labels = cluster_resources
467508 . get_required_labels ( )
@@ -499,7 +540,8 @@ pub async fn reconcile_opa(
499540 & merged_config,
500541 vector_aggregator_address. as_deref ( ) ,
501542 ) ?;
502- let rg_service = build_rolegroup_service ( opa, & resolved_product_image, & rolegroup) ?;
543+ let rg_service = build_rolegroup_service ( opa, & resolved_product_image, & rolegroup)
544+ . context ( BuildRequiredServicesSnafu ) ?;
503545 let rg_daemonset = build_server_rolegroup_daemonset (
504546 opa,
505547 & resolved_product_image,
@@ -555,36 +597,6 @@ pub async fn reconcile_opa(
555597 . context ( ApplyPatchRoleGroupDaemonSetSnafu { rolegroup } ) ?;
556598 }
557599
558- let discovery_cm_traffic_local = build_discovery_configmap (
559- & server_role_service. name_any ( ) ,
560- opa,
561- opa,
562- & resolved_product_image,
563- & server_role_service,
564- & client. kubernetes_cluster_info ,
565- )
566- . context ( BuildDiscoveryConfigSnafu ) ?;
567-
568- cluster_resources
569- . add ( client, discovery_cm_traffic_local)
570- . await
571- . context ( ApplyDiscoveryConfigSnafu ) ?;
572-
573- let discovery_cm_traffic_cluster = build_discovery_configmap (
574- & server_role_service_load_balanced. name_any ( ) ,
575- opa,
576- opa,
577- & resolved_product_image,
578- & server_role_service_load_balanced,
579- & client. kubernetes_cluster_info ,
580- )
581- . context ( BuildDiscoveryConfigSnafu ) ?;
582-
583- cluster_resources
584- . add ( client, discovery_cm_traffic_cluster)
585- . await
586- . context ( ApplyDiscoveryConfigSnafu ) ?;
587-
588600 let cluster_operation_cond_builder =
589601 ClusterOperationsConditionBuilder :: new ( & opa. spec . cluster_operation ) ;
590602
@@ -605,131 +617,6 @@ pub async fn reconcile_opa(
605617 Ok ( Action :: await_change ( ) )
606618}
607619
608- /// The server-role service is the primary endpoint that should be used by clients that do not perform internal load balancing,
609- /// including targets outside of the cluster.
610- pub fn build_server_role_service_traffic_local (
611- opa : & v1alpha1:: OpaCluster ,
612- resolved_product_image : & ResolvedProductImage ,
613- ) -> Result < Service > {
614- let service_name = opa
615- . server_role_service_name ( )
616- . context ( RoleServiceNameNotFoundSnafu ) ?;
617- build_server_role_service (
618- opa,
619- resolved_product_image,
620- & service_name,
621- Some ( "Local" . to_string ( ) ) ,
622- )
623- }
624-
625- /// The server-role service is the endpoint that should be used by clients that do perform internal load balancing.
626- pub fn build_server_role_service_traffic_cluster (
627- opa : & v1alpha1:: OpaCluster ,
628- resolved_product_image : & ResolvedProductImage ,
629- ) -> Result < Service > {
630- let service_name = opa
631- . server_role_service_name_load_balanced ( )
632- . context ( RoleServiceNameNotFoundSnafu ) ?;
633- build_server_role_service (
634- opa,
635- resolved_product_image,
636- & service_name,
637- Some ( "Cluster" . to_string ( ) ) ,
638- )
639- }
640-
641- fn build_server_role_service (
642- opa : & v1alpha1:: OpaCluster ,
643- resolved_product_image : & ResolvedProductImage ,
644- service_name : & str ,
645- internal_traffic_policy : Option < String > ,
646- ) -> Result < Service > {
647- let role_name = v1alpha1:: OpaRole :: Server . to_string ( ) ;
648-
649- let metadata = ObjectMetaBuilder :: new ( )
650- . name_and_namespace ( opa)
651- . name ( service_name)
652- . ownerreference_from_resource ( opa, None , Some ( true ) )
653- . context ( ObjectMissingMetadataForOwnerRefSnafu ) ?
654- . with_recommended_labels ( build_recommended_labels (
655- opa,
656- & resolved_product_image. app_version_label ,
657- & role_name,
658- "global" ,
659- ) )
660- . context ( ObjectMetaSnafu ) ?
661- . build ( ) ;
662-
663- let service_selector_labels =
664- Labels :: role_selector ( opa, APP_NAME , & role_name) . context ( BuildLabelSnafu ) ?;
665-
666- let service_spec = ServiceSpec {
667- type_ : Some ( opa. spec . cluster_config . listener_class . k8s_service_type ( ) ) ,
668- ports : Some ( vec ! [ ServicePort {
669- name: Some ( APP_PORT_NAME . to_string( ) ) ,
670- port: APP_PORT . into( ) ,
671- protocol: Some ( "TCP" . to_string( ) ) ,
672- ..ServicePort :: default ( )
673- } ] ) ,
674- selector : Some ( service_selector_labels. into ( ) ) ,
675- internal_traffic_policy,
676- ..ServiceSpec :: default ( )
677- } ;
678-
679- Ok ( Service {
680- metadata,
681- spec : Some ( service_spec) ,
682- status : None ,
683- } )
684- }
685-
686- /// The rolegroup [`Service`] is a headless service that allows direct access to the instances of a certain rolegroup
687- ///
688- /// This is mostly useful for internal communication between peers, or for clients that perform client-side load balancing.
689- fn build_rolegroup_service (
690- opa : & v1alpha1:: OpaCluster ,
691- resolved_product_image : & ResolvedProductImage ,
692- rolegroup : & RoleGroupRef < v1alpha1:: OpaCluster > ,
693- ) -> Result < Service > {
694- let prometheus_label =
695- Label :: try_from ( ( "prometheus.io/scrape" , "true" ) ) . context ( BuildLabelSnafu ) ?;
696-
697- let metadata = ObjectMetaBuilder :: new ( )
698- . name_and_namespace ( opa)
699- . name ( rolegroup. object_name ( ) )
700- . ownerreference_from_resource ( opa, None , Some ( true ) )
701- . context ( ObjectMissingMetadataForOwnerRefSnafu ) ?
702- . with_recommended_labels ( build_recommended_labels (
703- opa,
704- & resolved_product_image. app_version_label ,
705- & rolegroup. role ,
706- & rolegroup. role_group ,
707- ) )
708- . context ( ObjectMetaSnafu ) ?
709- . with_label ( prometheus_label)
710- . build ( ) ;
711-
712- let service_selector_labels =
713- Labels :: role_group_selector ( opa, APP_NAME , & rolegroup. role , & rolegroup. role_group )
714- . context ( BuildLabelSnafu ) ?;
715-
716- let service_spec = ServiceSpec {
717- // Internal communication does not need to be exposed
718- type_ : Some ( "ClusterIP" . to_string ( ) ) ,
719- cluster_ip : Some ( "None" . to_string ( ) ) ,
720- ports : Some ( service_ports ( ) ) ,
721- selector : Some ( service_selector_labels. into ( ) ) ,
722- publish_not_ready_addresses : Some ( true ) ,
723- ..ServiceSpec :: default ( )
724- } ;
725-
726- Ok ( Service {
727- metadata,
728- spec : Some ( service_spec) ,
729- status : None ,
730- } )
731- }
732-
733620/// The rolegroup [`ConfigMap`] configures the rolegroup based on the configuration given by the administrator
734621fn build_server_rolegroup_config_map (
735622 opa : & v1alpha1:: OpaCluster ,
@@ -1353,24 +1240,6 @@ fn build_prepare_start_command(
13531240 prepare_container_args
13541241}
13551242
1356- fn service_ports ( ) -> Vec < ServicePort > {
1357- vec ! [
1358- ServicePort {
1359- name: Some ( APP_PORT_NAME . to_string( ) ) ,
1360- port: APP_PORT . into( ) ,
1361- protocol: Some ( "TCP" . to_string( ) ) ,
1362- ..ServicePort :: default ( )
1363- } ,
1364- ServicePort {
1365- name: Some ( METRICS_PORT_NAME . to_string( ) ) ,
1366- port: 9504 , // Arbitrary port number, this is never actually used anywhere
1367- protocol: Some ( "TCP" . to_string( ) ) ,
1368- target_port: Some ( IntOrString :: String ( APP_PORT_NAME . to_string( ) ) ) ,
1369- ..ServicePort :: default ( )
1370- } ,
1371- ]
1372- }
1373-
13741243/// Creates recommended `ObjectLabels` to be used in deployed resources
13751244pub fn build_recommended_labels < ' a , T > (
13761245 owner : & ' a T ,
0 commit comments