11use stackable_operator:: {
2- builder:: { meta:: ObjectMetaBuilder , pod:: container:: ContainerBuilder } ,
2+ builder:: {
3+ meta:: ObjectMetaBuilder ,
4+ pod:: {
5+ container:: ContainerBuilder ,
6+ volume:: { ListenerOperatorVolumeSourceBuilder , ListenerReference } ,
7+ } ,
8+ } ,
9+ crd:: listener:: { self } ,
310 k8s_openapi:: {
411 DeepMerge ,
512 api:: {
613 apps:: v1:: { StatefulSet , StatefulSetSpec } ,
714 core:: v1:: {
815 Affinity , ConfigMap , ConfigMapVolumeSource , Container , ContainerPort ,
9- PodSecurityContext , PodSpec , PodTemplateSpec , Probe , Service , ServicePort ,
10- ServiceSpec , TCPSocketAction , Volume , VolumeMount ,
16+ PersistentVolumeClaim , PodSecurityContext , PodSpec , PodTemplateSpec , Probe ,
17+ Service , ServicePort , ServiceSpec , TCPSocketAction , Volume , VolumeMount ,
1118 } ,
1219 } ,
1320 apimachinery:: pkg:: { apis:: meta:: v1:: LabelSelector , util:: intstr:: IntOrString } ,
@@ -36,8 +43,11 @@ pub const TRANSPORT_PORT: u16 = 9300;
3643const CONFIG_VOLUME_NAME : & str = "config" ;
3744const DATA_VOLUME_NAME : & str = "data" ;
3845
46+ const LISTENER_VOLUME_NAME : & str = "listener" ;
47+ const LISTENER_VOLUME_DIR : & str = "/stackable/listener" ;
48+
3949// Path in opensearchproject/opensearch:3.0.0
40- const OPENSEARCH_BASE_PATH : & str = "/usr/share/ opensearch" ;
50+ const OPENSEARCH_BASE_PATH : & str = "/stackable/ opensearch/ " ;
4151
4252pub struct RoleGroupBuilder < ' a > {
4353 service_account_name : String ,
@@ -107,6 +117,27 @@ impl<'a> RoleGroupBuilder<'a> {
107117 . data
108118 . build_pvc ( DATA_VOLUME_NAME , Some ( vec ! [ "ReadWriteOnce" ] ) ) ;
109119
120+ let listener_group_name = self . resource_names . listener_service_name ( ) ;
121+
122+ // Listener endpoints for the all rolegroups will use persistent
123+ // volumes so that load balancers can hard-code the target
124+ // addresses. This will be the case even when no class is set (and
125+ // the value defaults to cluster-internal) as the address should
126+ // still be consistent.
127+ let listener_volume_claim_template = ListenerOperatorVolumeSourceBuilder :: new (
128+ & ListenerReference :: ListenerName ( listener_group_name) ,
129+ // TODO should be unversioned
130+ & self . recommended_labels ( ) ,
131+ )
132+ . expect ( "should be a listener group name" )
133+ . build_pvc ( LISTENER_VOLUME_NAME . to_string ( ) )
134+ . expect ( "should be a valid annotation" ) ;
135+
136+ let pvcs: Option < Vec < PersistentVolumeClaim > > = Some ( vec ! [
137+ data_volume_claim_template,
138+ listener_volume_claim_template,
139+ ] ) ;
140+
110141 let spec = StatefulSetSpec {
111142 // Order does not matter for OpenSearch
112143 pod_management_policy : Some ( "Parallel" . to_string ( ) ) ,
@@ -117,7 +148,7 @@ impl<'a> RoleGroupBuilder<'a> {
117148 } ,
118149 service_name : Some ( self . resource_names . headless_service_name ( ) ) ,
119150 template,
120- volume_claim_templates : Some ( vec ! [ data_volume_claim_template ] ) ,
151+ volume_claim_templates : pvcs ,
121152 ..StatefulSetSpec :: default ( )
122153 } ;
123154
@@ -271,6 +302,11 @@ impl<'a> RoleGroupBuilder<'a> {
271302 name : DATA_VOLUME_NAME . to_owned ( ) ,
272303 ..VolumeMount :: default ( )
273304 } ,
305+ VolumeMount {
306+ mount_path : LISTENER_VOLUME_DIR . to_owned ( ) ,
307+ name : LISTENER_VOLUME_NAME . to_owned ( ) ,
308+ ..VolumeMount :: default ( )
309+ } ,
274310 ] )
275311 . expect ( "The mount paths are statically defined and there should be no duplicates." )
276312 . add_container_ports ( vec ! [
@@ -337,6 +373,33 @@ impl<'a> RoleGroupBuilder<'a> {
337373 }
338374 }
339375
376+ pub fn build_listener ( & self ) -> listener:: v1alpha1:: Listener {
377+ let metadata =
378+ self . common_metadata ( self . resource_names . listener_service_name ( ) , Labels :: new ( ) ) ;
379+
380+ let listener_class = self . role_group_config . config . listener_class . to_owned ( ) ;
381+
382+ listener:: v1alpha1:: Listener {
383+ metadata,
384+ spec : listener:: v1alpha1:: ListenerSpec {
385+ class_name : Some ( listener_class) ,
386+ ports : Some ( self . listener_ports ( ) ) ,
387+ ..listener:: v1alpha1:: ListenerSpec :: default ( )
388+ } ,
389+ status : None ,
390+ }
391+ }
392+
393+ /// We only use the http port here and intentionally omit
394+ /// the metrics one.
395+ fn listener_ports ( & self ) -> Vec < listener:: v1alpha1:: ListenerPort > {
396+ vec ! [ listener:: v1alpha1:: ListenerPort {
397+ name: HTTP_PORT_NAME . to_string( ) ,
398+ port: HTTP_PORT . into( ) ,
399+ protocol: Some ( "TCP" . to_string( ) ) ,
400+ } ]
401+ }
402+
340403 fn common_metadata (
341404 & self ,
342405 resource_name : impl Into < String > ,
0 commit comments