Skip to content

Commit 85abdc2

Browse files
committed
wip - use 3 services
1 parent 5a3bf1e commit 85abdc2

File tree

4 files changed

+261
-198
lines changed

4 files changed

+261
-198
lines changed

rust/operator-binary/src/controller.rs

Lines changed: 59 additions & 190 deletions
Original file line numberDiff line numberDiff line change
@@ -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

8485
pub 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
}
322326
type 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
734621
fn 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
13751244
pub fn build_recommended_labels<'a, T>(
13761245
owner: &'a T,

rust/operator-binary/src/crd/mod.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -319,24 +319,32 @@ impl v1alpha1::OpaCluster {
319319
})
320320
}
321321

322-
/// The name of the role-level load-balanced Kubernetes `Service`
323-
pub fn server_role_service_name(&self) -> Option<String> {
322+
/// DEPRECATED: The name of the role-level traffic policy local Kubernetes `Service`
323+
pub fn server_role_service_name_itp_local_deprecated(&self) -> Option<String> {
324324
self.metadata.name.clone()
325325
}
326326

327-
/// The name of the role-level load-balanced Kubernetes `Service`
328-
pub fn server_role_service_name_load_balanced(&self) -> Option<String> {
329-
if let Some(service_name) = self.server_role_service_name() {
330-
return Some(format!("{service_name}-lb"));
327+
/// The name of the role-level traffic policy cluster Kubernetes `Service`
328+
pub fn server_role_service_name_itp_local(&self) -> Option<String> {
329+
if let Some(service_name) = &self.metadata.name {
330+
return Some(format!("{service_name}-local"));
331331
}
332332
None
333333
}
334334

335-
/// The fully-qualified domain name of the role-level load-balanced Kubernetes `Service`
335+
/// The name of the role-level traffic policy cluster Kubernetes `Service`
336+
pub fn server_role_service_name_itp_cluster(&self) -> Option<String> {
337+
if let Some(service_name) = &self.metadata.name {
338+
return Some(format!("{service_name}-cluster"));
339+
}
340+
None
341+
}
342+
343+
/// The fully-qualified domain name of the role-level local Kubernetes `Service`
336344
pub fn server_role_service_fqdn(&self, cluster_info: &KubernetesClusterInfo) -> Option<String> {
337345
Some(format!(
338346
"{role_service_name}.{namespace}.svc.{cluster_domain}",
339-
role_service_name = self.server_role_service_name()?,
347+
role_service_name = self.server_role_service_name_itp_local_deprecated()?,
340348
namespace = self.metadata.namespace.as_ref()?,
341349
cluster_domain = cluster_info.cluster_domain
342350
))

rust/operator-binary/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ mod controller;
3131
mod discovery;
3232
mod operations;
3333
mod product_logging;
34+
mod service;
3435

3536
pub mod built_info {
3637
include!(concat!(env!("OUT_DIR"), "/built.rs"));

0 commit comments

Comments
 (0)