Skip to content

Commit d008047

Browse files
committed
WIP: Listener integration
1 parent 90cc507 commit d008047

File tree

5 files changed

+151
-136
lines changed

5 files changed

+151
-136
lines changed

Cargo.lock

Lines changed: 8 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

deploy/helm/hive-operator/crds/crds.yaml

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -77,23 +77,6 @@ spec:
7777
required:
7878
- configMap
7979
type: object
80-
listenerClass:
81-
default: cluster-internal
82-
description: |-
83-
This field controls which type of Service the Operator creates for this HiveCluster:
84-
85-
* cluster-internal: Use a ClusterIP service
86-
87-
* external-unstable: Use a NodePort service
88-
89-
* external-stable: Use a LoadBalancer service
90-
91-
This is a temporary solution with the goal to keep yaml manifests forward compatible. In the future, this setting will control which [ListenerClass](https://docs.stackable.tech/home/nightly/listener-operator/listenerclass.html) will be used to expose the service, and ListenerClass names will stay the same, allowing for a non-breaking change.
92-
enum:
93-
- cluster-internal
94-
- external-unstable
95-
- external-stable
96-
type: string
9780
s3:
9881
description: S3 connection specification. This can be either `inline` or a `reference` to an S3Connection object. Read the [S3 concept documentation](https://docs.stackable.tech/home/nightly/concepts/s3) to learn more.
9982
nullable: true
@@ -333,6 +316,10 @@ spec:
333316
description: Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details.
334317
nullable: true
335318
type: string
319+
listenerClass:
320+
description: This field controls which [ListenerClass](https://docs.stackable.tech/home/nightly/listener-operator/listenerclass.html) is used to expose the webserver.
321+
nullable: true
322+
type: string
336323
logging:
337324
default:
338325
containers: {}
@@ -627,6 +614,10 @@ spec:
627614
description: Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details.
628615
nullable: true
629616
type: string
617+
listenerClass:
618+
description: This field controls which [ListenerClass](https://docs.stackable.tech/home/nightly/listener-operator/listenerclass.html) is used to expose the webserver.
619+
nullable: true
620+
type: string
630621
logging:
631622
default:
632623
containers: {}

rust/operator-binary/src/controller.rs

Lines changed: 118 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use std::{
44
borrow::Cow,
55
collections::{BTreeMap, HashMap},
6+
default,
67
hash::Hasher,
78
sync::Arc,
89
};
@@ -22,16 +23,28 @@ use stackable_operator::{
2223
configmap::ConfigMapBuilder,
2324
meta::ObjectMetaBuilder,
2425
pod::{
25-
PodBuilder, container::ContainerBuilder, resources::ResourceRequirementsBuilder,
26-
security::PodSecurityContextBuilder, volume::VolumeBuilder,
26+
PodBuilder,
27+
container::ContainerBuilder,
28+
resources::ResourceRequirementsBuilder,
29+
security::PodSecurityContextBuilder,
30+
volume::{
31+
ListenerOperatorVolumeSourceBuilder, ListenerOperatorVolumeSourceBuilderError,
32+
ListenerReference, VolumeBuilder,
33+
},
2734
},
2835
},
2936
cluster_resources::{ClusterResourceApplyStrategy, ClusterResources},
3037
commons::{
3138
product_image_selection::ResolvedProductImage, rbac::build_rbac_resources,
3239
tls_verification::TlsClientDetailsError,
3340
},
34-
crd::s3,
41+
crd::{
42+
listener::{
43+
self,
44+
v1alpha1::{Listener, ListenerPort, ListenerSpec},
45+
},
46+
s3,
47+
},
3548
k8s_openapi::{
3649
DeepMerge,
3750
api::{
@@ -82,8 +95,9 @@ use crate::{
8295
crd::{
8396
APP_NAME, CORE_SITE_XML, Container, DB_PASSWORD_ENV, DB_USERNAME_ENV, HIVE_PORT,
8497
HIVE_PORT_NAME, HIVE_SITE_XML, HiveClusterStatus, HiveRole, JVM_SECURITY_PROPERTIES_FILE,
85-
METRICS_PORT, METRICS_PORT_NAME, MetaStoreConfig, STACKABLE_CONFIG_DIR,
86-
STACKABLE_CONFIG_DIR_NAME, STACKABLE_CONFIG_MOUNT_DIR, STACKABLE_CONFIG_MOUNT_DIR_NAME,
98+
LISTENER_VOLUME_DIR, LISTENER_VOLUME_NAME, METRICS_PORT, METRICS_PORT_NAME,
99+
MetaStoreConfig, STACKABLE_CONFIG_DIR, STACKABLE_CONFIG_DIR_NAME,
100+
STACKABLE_CONFIG_MOUNT_DIR, STACKABLE_CONFIG_MOUNT_DIR_NAME,
87101
STACKABLE_LOG_CONFIG_MOUNT_DIR, STACKABLE_LOG_CONFIG_MOUNT_DIR_NAME, STACKABLE_LOG_DIR,
88102
STACKABLE_LOG_DIR_NAME, v1alpha1,
89103
},
@@ -327,6 +341,16 @@ pub enum Error {
327341

328342
#[snafu(display("failed to construct JVM arguments"))]
329343
ConstructJvmArguments { source: crate::config::jvm::Error },
344+
345+
#[snafu(display("failed to apply group listener for {rolegroup}"))]
346+
ApplyGroupListener {
347+
source: stackable_operator::cluster_resources::Error,
348+
rolegroup: RoleGroupRef<v1alpha1::HiveCluster>,
349+
},
350+
#[snafu(display("failed to build listener volume"))]
351+
BuildListenerVolume {
352+
source: ListenerOperatorVolumeSourceBuilderError,
353+
},
330354
}
331355
type Result<T, E = Error> = std::result::Result<T, E>;
332356

@@ -428,16 +452,10 @@ pub async fn reconcile_hive(
428452
.await
429453
.context(ApplyRoleBindingSnafu)?;
430454

431-
let metastore_role_service = build_metastore_role_service(hive, &resolved_product_image)?;
432-
433-
// we have to get the assigned ports
434-
let metastore_role_service = cluster_resources
435-
.add(client, metastore_role_service)
436-
.await
437-
.context(ApplyRoleServiceSnafu)?;
438-
439455
let mut ss_cond_builder = StatefulSetConditionBuilder::default();
440456

457+
// TODO: You want to add service creation in this for loop
458+
// for each rg a service needs to be build for hive
441459
for (rolegroup_name, rolegroup_config) in metastore_config.iter() {
442460
let rolegroup = hive.metastore_rolegroup_ref(rolegroup_name);
443461

@@ -467,6 +485,20 @@ pub async fn reconcile_hive(
467485
&rbac_sa.name_any(),
468486
)?;
469487

488+
let rg_group_listener = build_group_listener(
489+
hive,
490+
&resolved_product_image,
491+
&rolegroup,
492+
config.listener_class,
493+
)?;
494+
495+
cluster_resources
496+
.add(client, rg_group_listener)
497+
.await
498+
.with_context(|_| ApplyGroupListenerSnafu {
499+
rolegroup: rolegroup.clone(),
500+
})?;
501+
470502
cluster_resources
471503
.add(client, rg_service)
472504
.await
@@ -504,16 +536,10 @@ pub async fn reconcile_hive(
504536
// std's SipHasher is deprecated, and DefaultHasher is unstable across Rust releases.
505537
// We don't /need/ stability, but it's still nice to avoid spurious changes where possible.
506538
let mut discovery_hash = FnvHasher::with_key(0);
507-
for discovery_cm in discovery::build_discovery_configmaps(
508-
client,
509-
hive,
510-
hive,
511-
&resolved_product_image,
512-
&metastore_role_service,
513-
None,
514-
)
515-
.await
516-
.context(BuildDiscoveryConfigSnafu)?
539+
for discovery_cm in
540+
discovery::build_discovery_configmaps(client, hive, hive, &resolved_product_image, None)
541+
.await
542+
.context(BuildDiscoveryConfigSnafu)?
517543
{
518544
let discovery_cm = cluster_resources
519545
.add(client, discovery_cm)
@@ -547,43 +573,47 @@ pub async fn reconcile_hive(
547573
Ok(Action::await_change())
548574
}
549575

550-
/// The server-role service is the primary endpoint that should be used by clients that do not
551-
/// perform internal load balancing including targets outside of the cluster.
552-
pub fn build_metastore_role_service(
576+
pub fn build_group_listener(
553577
hive: &v1alpha1::HiveCluster,
554578
resolved_product_image: &ResolvedProductImage,
555-
) -> Result<Service> {
556-
let role_name = HiveRole::MetaStore.to_string();
579+
rolegroup: &RoleGroupRef<v1alpha1::HiveCluster>,
580+
listener_class: String,
581+
) -> Result<Listener> {
582+
let metadata = ObjectMetaBuilder::new()
583+
.name_and_namespace(hive)
584+
.name(hive.group_listener_name(rolegroup))
585+
.ownerreference_from_resource(hive, None, Some(true))
586+
.context(ObjectMissingMetadataForOwnerRefSnafu)?
587+
.with_recommended_labels(build_recommended_labels(
588+
hive,
589+
&resolved_product_image.app_version_label,
590+
&rolegroup.role,
591+
&rolegroup.role_group,
592+
))
593+
.context(MetadataBuildSnafu)?
594+
.build();
557595

558-
let role_svc_name = hive
559-
.metastore_role_service_name()
560-
.context(GlobalServiceNameNotFoundSnafu)?;
561-
Ok(Service {
562-
metadata: ObjectMetaBuilder::new()
563-
.name_and_namespace(hive)
564-
.name(role_svc_name)
565-
.ownerreference_from_resource(hive, None, Some(true))
566-
.context(ObjectMissingMetadataForOwnerRefSnafu)?
567-
.with_recommended_labels(build_recommended_labels(
568-
hive,
569-
&resolved_product_image.app_version_label,
570-
&role_name,
571-
"global",
572-
))
573-
.context(MetadataBuildSnafu)?
574-
.build(),
575-
spec: Some(ServiceSpec {
576-
type_: Some(hive.spec.cluster_config.listener_class.k8s_service_type()),
577-
ports: Some(service_ports()),
578-
selector: Some(
579-
Labels::role_selector(hive, APP_NAME, &role_name)
580-
.context(LabelBuildSnafu)?
581-
.into(),
582-
),
583-
..ServiceSpec::default()
584-
}),
596+
let spec = ListenerSpec {
597+
class_name: Some(listener_class),
598+
ports: Some(listener_ports()),
599+
..Default::default()
600+
};
601+
602+
let listener = Listener {
603+
metadata,
604+
spec,
585605
status: None,
586-
})
606+
};
607+
608+
Ok(listener)
609+
}
610+
611+
fn listener_ports() -> Vec<ListenerPort> {
612+
vec![ListenerPort {
613+
name: HIVE_PORT_NAME.to_owned(),
614+
port: HIVE_PORT.into(),
615+
protocol: Some("TCP".to_owned()),
616+
}]
587617
}
588618

589619
/// The rolegroup [`ConfigMap`] configures the rolegroup based on the configuration given by the administrator
@@ -729,6 +759,7 @@ fn build_metastore_rolegroup_config_map(
729759
/// The rolegroup [`Service`] is a headless service that allows direct access to the instances of a certain rolegroup
730760
///
731761
/// This is mostly useful for internal communication between peers, or for clients that perform client-side load balancing.
762+
// TODO: However it looks like I need to add it here as services will be created here by rolegroup
732763
fn build_rolegroup_service(
733764
hive: &v1alpha1::HiveCluster,
734765
resolved_product_image: &ResolvedProductImage,
@@ -949,16 +980,39 @@ fn build_metastore_rolegroup_statefulset(
949980
}
950981
}
951982

983+
let recommended_object_labels = build_recommended_labels(
984+
hive,
985+
&resolved_product_image.app_version_label,
986+
&rolegroup_ref.role,
987+
&rolegroup_ref.role_group,
988+
);
989+
// Used for PVC templates that cannot be modified once they are deployed
990+
let unversioned_recommended_labels = Labels::recommended(build_recommended_labels(
991+
hive,
992+
// A version value is required, and we do want to use the "recommended" format for the other desired labels
993+
"none",
994+
&rolegroup_ref.role,
995+
&rolegroup_ref.role_group,
996+
))
997+
.context(LabelBuildSnafu)?;
998+
952999
let metadata = ObjectMetaBuilder::new()
953-
.with_recommended_labels(build_recommended_labels(
954-
hive,
955-
&resolved_product_image.app_version_label,
956-
&rolegroup_ref.role,
957-
&rolegroup_ref.role_group,
958-
))
1000+
.with_recommended_labels(recommended_object_labels.clone())
9591001
.context(MetadataBuildSnafu)?
9601002
.build();
9611003

1004+
let pvc = ListenerOperatorVolumeSourceBuilder::new(
1005+
&ListenerReference::ListenerName(hive.group_listener_name(rolegroup_ref)),
1006+
&unversioned_recommended_labels,
1007+
)
1008+
.context(BuildListenerVolumeSnafu)?
1009+
.build_pvc(LISTENER_VOLUME_NAME.to_owned())
1010+
.context(BuildListenerVolumeSnafu)?;
1011+
1012+
container_builder
1013+
.add_volume_mount(LISTENER_VOLUME_NAME, LISTENER_VOLUME_DIR)
1014+
.context(AddVolumeMountSnafu)?;
1015+
9621016
pod_builder
9631017
.metadata(metadata)
9641018
.image_pull_secrets_from_product_image(resolved_product_image)
@@ -1069,12 +1123,7 @@ fn build_metastore_rolegroup_statefulset(
10691123
.name(rolegroup_ref.object_name())
10701124
.ownerreference_from_resource(hive, None, Some(true))
10711125
.context(ObjectMissingMetadataForOwnerRefSnafu)?
1072-
.with_recommended_labels(build_recommended_labels(
1073-
hive,
1074-
&resolved_product_image.app_version_label,
1075-
&rolegroup_ref.role,
1076-
&rolegroup_ref.role_group,
1077-
))
1126+
.with_recommended_labels(recommended_object_labels)
10781127
.context(MetadataBuildSnafu)?
10791128
.build(),
10801129
spec: Some(StatefulSetSpec {
@@ -1095,6 +1144,7 @@ fn build_metastore_rolegroup_statefulset(
10951144
},
10961145
service_name: Some(rolegroup_ref.object_name()),
10971146
template: pod_template,
1147+
volume_claim_templates: Some(vec![pvc]),
10981148
..StatefulSetSpec::default()
10991149
}),
11001150
status: None,

0 commit comments

Comments
 (0)