@@ -45,15 +45,46 @@ pub async fn get_endpoints(
45
45
object_name : & str ,
46
46
object_namespace : & str ,
47
47
) -> Result < IndexMap < String , String > , Error > {
48
- let service_list_params =
48
+ let list_params =
49
49
ListParams :: from_product ( product_name, Some ( object_name) , k8s:: ProductLabel :: Name ) ;
50
50
51
- let services = kube_client
52
- . list_services ( Some ( object_namespace) , & service_list_params )
51
+ let listeners = kube_client
52
+ . list_listeners ( Some ( object_namespace) , & list_params )
53
53
. await
54
54
. context ( KubeClientFetchSnafu ) ?;
55
55
56
56
let mut endpoints = IndexMap :: new ( ) ;
57
+ for listener in & listeners {
58
+ let Some ( display_name) = display_name_for_listener_name ( & listener. name_any ( ) , object_name)
59
+ else {
60
+ continue ;
61
+ } ;
62
+ let Some ( listener_status) = & listener. status else {
63
+ continue ;
64
+ } ;
65
+
66
+ for address in listener_status. ingress_addresses . iter ( ) . flatten ( ) {
67
+ for port in & address. ports {
68
+ let text = format ! ( "{display_name}-{port_name}" , port_name = port. 0 ) ;
69
+ let endpoint_url = endpoint_url ( & address. address , * port. 1 , port. 0 ) ;
70
+ endpoints. insert ( text, endpoint_url) ;
71
+ }
72
+ }
73
+ }
74
+
75
+ // Ideally we use listener-operator everywhere, afterwards we can remove the whole k8s Services handling below.
76
+ // Currently the Services created by listener-op are missing the recommended labels, so this early exit in case we
77
+ // find Listeners is currently not required. However, once we add the recommended labels to the k8s Services, we
78
+ // would have duplicated entries (one from the Listener and one from the Service). Because of this we don't look at
79
+ // the Services in case we found Listeners!
80
+ if !listeners. items . is_empty ( ) {
81
+ return Ok ( endpoints) ;
82
+ }
83
+
84
+ let services = kube_client
85
+ . list_services ( Some ( object_namespace) , & list_params)
86
+ . await
87
+ . context ( KubeClientFetchSnafu ) ?;
57
88
58
89
for service in services {
59
90
match get_endpoint_urls ( kube_client, & service, object_name) . await {
@@ -268,7 +299,7 @@ async fn get_node_name_ip_mapping(
268
299
}
269
300
270
301
fn endpoint_url ( endpoint_host : & str , endpoint_port : i32 , port_name : & str ) -> String {
271
- // TODO: Consolidate web-ui port names in operators based on decision in arch meeting from 2022/08/ 10
302
+ // TODO: Consolidate web-ui port names in operators based on decision in arch meeting from 2022-08- 10
272
303
// For Superset: https://github.com/stackabletech/superset-operator/issues/248
273
304
// For Airflow: https://github.com/stackabletech/airflow-operator/issues/146
274
305
// As we still support older operator versions we need to also include the "old" way of naming
@@ -285,3 +316,38 @@ fn endpoint_url(endpoint_host: &str, endpoint_port: i32, port_name: &str) -> Str
285
316
format ! ( "{endpoint_host}:{endpoint_port}" )
286
317
}
287
318
}
319
+
320
+ /// Listener names usually have the pattern `listener-simple-hdfs-namenode-default-0` or
321
+ /// `simple-hdfs-datanode-default-0-listener`, so we can strip everything before the first occurrence of
322
+ /// the stacklet name (`simple-hdfs` in this case). After that it actually get's pretty hard.
323
+ /// This truncation is *not* ideal, however we only have implemented listener-operator for HDFS so far,
324
+ /// so better to have support for that than nothing :)
325
+ fn display_name_for_listener_name ( listener_name : & str , object_name : & str ) -> Option < String > {
326
+ let Some ( ( _, display_name) ) = listener_name. split_once ( object_name) else {
327
+ return None ;
328
+ } ;
329
+ Some ( display_name. trim_start_matches ( '-' ) . to_owned ( ) )
330
+ }
331
+
332
+ #[ cfg( test) ]
333
+ mod tests {
334
+ use super :: * ;
335
+ use rstest:: rstest;
336
+
337
+ #[ rstest]
338
+ // These are all the listener names implemented so far (only HDFS is using listener-operator). In the future more
339
+ // test-case should be added.
340
+ #[ case( "listener-simple-hdfs-namenode-default-0" , "simple-hdfs" , Some ( "namenode-default-0" . to_string( ) ) ) ]
341
+ #[ case( "listener-simple-hdfs-namenode-default-1" , "simple-hdfs" , Some ( "namenode-default-1" . to_string( ) ) ) ]
342
+ // FIXME: Come up with a more clever strategy to remove the `-listener` suffix. I would prefer to wait until we
343
+ // actually have more products using listener-op to not accidentally strip to much.
344
+ #[ case( "simple-hdfs-datanode-default-0-listener" , "simple-hdfs" , Some ( "datanode-default-0-listener" . to_string( ) ) ) ]
345
+ fn test_display_name_for_listener_name (
346
+ #[ case] listener_name : & str ,
347
+ #[ case] object_name : & str ,
348
+ #[ case] expected : Option < String > ,
349
+ ) {
350
+ let output = display_name_for_listener_name ( listener_name, object_name) ;
351
+ assert_eq ! ( output, expected) ;
352
+ }
353
+ }
0 commit comments