|
1 | 1 | //! Types and functions for exposing product endpoints via [listener::v1alpha1::Listener]. |
2 | 2 |
|
3 | | -use snafu::{ResultExt as _, Snafu}; |
| 3 | +use std::str::FromStr; |
| 4 | + |
4 | 5 | use stackable_operator::{ |
5 | | - builder::meta::ObjectMetaBuilder, commons::product_image_selection::ResolvedProductImage, |
6 | | - crd::listener, kube::ResourceExt as _, |
| 6 | + builder::meta::ObjectMetaBuilder, |
| 7 | + crd::listener, |
| 8 | + v2::{builder::meta::ownerreference_from_resource, types::operator::RoleGroupName}, |
7 | 9 | }; |
8 | 10 |
|
9 | 11 | use crate::{ |
10 | | - crd::{ZOOKEEPER_SERVER_PORT_NAME, ZookeeperRole, security::ZookeeperSecurity, v1alpha1}, |
11 | | - utils::build_recommended_labels, |
12 | | - zk_controller::ZK_CONTROLLER_NAME, |
| 12 | + crd::{ZOOKEEPER_SERVER_PORT_NAME, ZookeeperRole, security::ZookeeperSecurity}, |
| 13 | + zk_controller::validate::ValidatedCluster, |
13 | 14 | }; |
14 | 15 |
|
15 | | -type Result<T, E = Error> = std::result::Result<T, E>; |
16 | | - |
17 | | -#[derive(Snafu, Debug)] |
18 | | -pub enum Error { |
19 | | - #[snafu(display("Role {zk_role:?} is not defined in the ZooKeeperCluster spec"))] |
20 | | - InvalidRole { |
21 | | - source: crate::crd::Error, |
22 | | - zk_role: String, |
23 | | - }, |
24 | | - |
25 | | - #[snafu(display("object is missing metadata to build owner reference"))] |
26 | | - ObjectMissingMetadataForOwnerRef { |
27 | | - source: stackable_operator::builder::meta::Error, |
28 | | - }, |
29 | | - |
30 | | - #[snafu(display("failed to build recommended labels"))] |
31 | | - RecommendedLabels { |
32 | | - source: stackable_operator::builder::meta::Error, |
33 | | - }, |
34 | | -} |
35 | | - |
| 16 | +/// Builds the role-level [`Listener`](listener::v1alpha1::Listener) exposing the ZooKeeper servers. |
| 17 | +/// |
| 18 | +/// The listener is owned by, labelled and named from the [`ValidatedCluster`]; the ListenerClass |
| 19 | +/// and security settings are taken from its validated cluster config. |
36 | 20 | pub fn build_role_listener( |
37 | | - zk: &v1alpha1::ZookeeperCluster, |
| 21 | + cluster: &ValidatedCluster, |
38 | 22 | zk_role: &ZookeeperRole, |
39 | | - resolved_product_image: &ResolvedProductImage, |
40 | | - zookeeper_security: &ZookeeperSecurity, |
41 | | -) -> Result<listener::v1alpha1::Listener> { |
42 | | - let listener_name = role_listener_name(zk, zk_role); |
43 | | - let listener_class = &zk |
44 | | - .role(zk_role) |
45 | | - .with_context(|_| InvalidRoleSnafu { |
46 | | - zk_role: zk_role.to_string(), |
47 | | - })? |
48 | | - .role_config |
49 | | - .listener_class; |
| 23 | +) -> listener::v1alpha1::Listener { |
| 24 | + // The listener is a role-level resource, so it has no role group. The recommended labels |
| 25 | + // require a role-group value, so a constant "none" is used (matching the previous behaviour). |
| 26 | + let role_group_name = |
| 27 | + RoleGroupName::from_str("none").expect("'none' is a valid role group name"); |
50 | 28 |
|
51 | | - let listener = listener::v1alpha1::Listener { |
| 29 | + listener::v1alpha1::Listener { |
52 | 30 | metadata: ObjectMetaBuilder::new() |
53 | | - .name_and_namespace(zk) |
54 | | - .name(listener_name) |
55 | | - .ownerreference_from_resource(zk, None, Some(true)) |
56 | | - .context(ObjectMissingMetadataForOwnerRefSnafu)? |
57 | | - // Since we only make a listener for the role, which labels should we use? |
58 | | - // We can't use with_recommended_labels because it requires an ObjectLabels which |
59 | | - // in turn requires RoleGroup stuff) |
60 | | - // TODO (@NickLarsenNZ): Make separate functions for with_recommended_labels with/without rolegroups |
61 | | - // .with_labels(manual_labels).build() |
62 | | - .with_recommended_labels(&build_recommended_labels( |
63 | | - zk, |
64 | | - ZK_CONTROLLER_NAME, |
65 | | - &resolved_product_image.app_version_label_value, |
66 | | - &zk_role.to_string(), |
67 | | - "none", // TODO (@NickLarsenNZ): update build_recommended_labels to have an optional role_group |
68 | | - )) |
69 | | - .context(RecommendedLabelsSnafu)? |
| 31 | + .name_and_namespace(cluster) |
| 32 | + .name(role_listener_name(cluster.name.as_ref(), zk_role)) |
| 33 | + .ownerreference(ownerreference_from_resource(cluster, None, Some(true))) |
| 34 | + .with_labels(cluster.recommended_labels(&role_group_name)) |
70 | 35 | .build(), |
71 | 36 | spec: listener::v1alpha1::ListenerSpec { |
72 | | - class_name: Some(listener_class.to_owned()), |
73 | | - ports: Some(listener_ports(zookeeper_security)), |
| 37 | + class_name: Some(cluster.cluster_config.listener_class.clone()), |
| 38 | + ports: Some(listener_ports(&cluster.cluster_config.zookeeper_security)), |
74 | 39 | ..listener::v1alpha1::ListenerSpec::default() |
75 | 40 | }, |
76 | 41 | status: None, |
77 | | - }; |
78 | | - |
79 | | - Ok(listener) |
| 42 | + } |
80 | 43 | } |
81 | 44 |
|
82 | | -// TODO (@NickLarsenNZ): This could be a method we can put on a Resource that takes a role_name |
83 | | -pub fn role_listener_name(zk: &v1alpha1::ZookeeperCluster, zk_role: &ZookeeperRole) -> String { |
84 | | - // TODO (@NickLarsenNZ): Make a convention, do we use name_any() and allow empty string? or handle the error (as unlikely as it would be)? |
85 | | - format!("{zk}-{zk_role}", zk = zk.name_any()) |
| 45 | +pub fn role_listener_name(cluster_name: &str, zk_role: &ZookeeperRole) -> String { |
| 46 | + format!("{cluster_name}-{zk_role}") |
86 | 47 | } |
87 | 48 |
|
88 | 49 | // We only use the server port here and intentionally omit the metrics one. |
|
0 commit comments