Skip to content

feat: HBase Listener integration #639

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 42 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
05e5c16
output listener refs
adwk67 Mar 26, 2025
776e273
add listener refs to config map
adwk67 Mar 26, 2025
d824b50
Merge branch 'main' into feat/integrate-listener-operator
adwk67 Mar 26, 2025
967239d
changelog
adwk67 Mar 26, 2025
4eb4e35
changed logging statement
adwk67 Mar 26, 2025
96593c7
integration test
adwk67 Mar 27, 2025
ae1654a
changed listener class designation
adwk67 Mar 27, 2025
53ea8bc
update listener class docs
adwk67 Mar 27, 2025
f8cc1c7
working tests
adwk67 Mar 28, 2025
7a2756b
wip: experimental command
adwk67 Mar 31, 2025
2affa65
cleanup start command
adwk67 Mar 31, 2025
652999e
added hostname/port to hbase-env.sh
adwk67 Mar 31, 2025
c8a2644
wip: will move startup logic to hbase-entrypoint.sh
adwk67 Apr 1, 2025
dd793c0
cleaned up/reverted previous wip
adwk67 Apr 1, 2025
bd1db17
cleaned up/reverted previous wip II
adwk67 Apr 1, 2025
80adf71
correct callout
adwk67 Apr 1, 2025
aee4fc2
use pvcs for externally-reachable endpoints
adwk67 Apr 2, 2025
bf969a0
added comment
adwk67 Apr 2, 2025
90efe2b
docs
adwk67 Apr 3, 2025
0030bfb
merge main
adwk67 Apr 3, 2025
8313995
resolve listener-class across role-groups/role
adwk67 Apr 8, 2025
465d0f1
merge conflicts
adwk67 Apr 8, 2025
fb8efde
regenerate nix
adwk67 Apr 8, 2025
5ddbff2
updated tokio and nix packages
adwk67 Apr 9, 2025
6146593
merge main
adwk67 Apr 9, 2025
8acadff
merge main
adwk67 Apr 9, 2025
68ab9cc
added listener-relevant config settings
adwk67 Apr 23, 2025
9a4231a
merged main
adwk67 Apr 24, 2025
61c79a5
Try a different tack at reconfiguring hbase
nightkr May 31, 2025
7b742c0
formatting and partial clean-up
adwk67 Jun 5, 2025
fde3c8a
formatting and partial clean-up
adwk67 Jun 5, 2025
550ea47
merge main and fix conflicts
adwk67 Jun 5, 2025
71015a5
replaced listener-class enum with string
adwk67 Jun 6, 2025
c555448
Merge branch 'main' into feat/integrate-listener-operator
adwk67 Jun 6, 2025
8b3e650
tweak test cases
adwk67 Jun 10, 2025
39740fa
add generic properties for listener endpoints
adwk67 Jun 10, 2025
00ef5c9
write endpoints to hbase-site instead of dedicated config map
adwk67 Jun 10, 2025
74bfc29
remove unused error defs
adwk67 Jun 11, 2025
6c616a1
remove unused error def/function
adwk67 Jun 11, 2025
4309b9d
fix some tests inline with 2.6.1, add UI port type
adwk67 Jun 13, 2025
51b2837
use listener service resolved in entrypoint script rather than passin…
adwk67 Jun 16, 2025
a51003c
Merge branch 'main' into feat/integrate-listener-operator
adwk67 Jun 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Added

- Added listener support for HBase ([#639]).
- Adds new telemetry CLI arguments and environment variables ([#652]).
- Use `--file-log-max-files` (or `FILE_LOG_MAX_FILES`) to limit the number of log files kept.
- Use `--file-log-rotation-period` (or `FILE_LOG_ROTATION_PERIOD`) to configure the frequency of rotation.
Expand Down Expand Up @@ -38,6 +39,7 @@
- test: Remove HDFS `3.3.4`, `3.3.6`, and `3.4.0` ([#655]).
- test: HBase 2.4.18 removed ([#659]):

[#639]: https://github.com/stackabletech/hbase-operator/pull/639
[#640]: https://github.com/stackabletech/hbase-operator/pull/640
[#645]: https://github.com/stackabletech/hbase-operator/pull/645
[#647]: https://github.com/stackabletech/hbase-operator/pull/647
Expand Down
38 changes: 24 additions & 14 deletions deploy/helm/hbase-operator/crds/crds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -73,20 +73,6 @@ spec:
hdfsConfigMapName:
description: Name of the [discovery ConfigMap](https://docs.stackable.tech/home/nightly/concepts/service_discovery) for an HDFS cluster.
type: string
listenerClass:
default: cluster-internal
description: |-
This field controls which type of Service the Operator creates for this HbaseCluster:

* cluster-internal: Use a ClusterIP service

* external-unstable: Use a NodePort service

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.
enum:
- cluster-internal
- external-unstable
type: string
vectorAggregatorConfigMapName:
description: Name of the Vector aggregator [discovery ConfigMap](https://docs.stackable.tech/home/nightly/concepts/service_discovery). It must contain the key `ADDRESS` with the address of the Vector aggregator. Follow the [logging tutorial](https://docs.stackable.tech/home/nightly/tutorials/logging-vector-aggregator) to learn how to configure log aggregation with Vector.
nullable: true
Expand Down Expand Up @@ -210,6 +196,10 @@ spec:
hbaseRootdir:
nullable: true
type: string
listenerClass:
description: This field controls which [ListenerClass](https://docs.stackable.tech/home/nightly/listener-operator/listenerclass.html) is used to expose this rolegroup.
nullable: true
type: string
logging:
default:
containers: {}
Expand Down Expand Up @@ -460,6 +450,10 @@ spec:
hbaseRootdir:
nullable: true
type: string
listenerClass:
description: This field controls which [ListenerClass](https://docs.stackable.tech/home/nightly/listener-operator/listenerclass.html) is used to expose this rolegroup.
nullable: true
type: string
logging:
default:
containers: {}
Expand Down Expand Up @@ -691,6 +685,10 @@ spec:
hbaseRootdir:
nullable: true
type: string
listenerClass:
description: This field controls which [ListenerClass](https://docs.stackable.tech/home/nightly/listener-operator/listenerclass.html) is used to expose this rolegroup.
nullable: true
type: string
logging:
default:
containers: {}
Expand Down Expand Up @@ -969,6 +967,10 @@ spec:
hbaseRootdir:
nullable: true
type: string
listenerClass:
description: This field controls which [ListenerClass](https://docs.stackable.tech/home/nightly/listener-operator/listenerclass.html) is used to expose this rolegroup.
nullable: true
type: string
logging:
default:
containers: {}
Expand Down Expand Up @@ -1228,6 +1230,10 @@ spec:
hbaseRootdir:
nullable: true
type: string
listenerClass:
description: This field controls which [ListenerClass](https://docs.stackable.tech/home/nightly/listener-operator/listenerclass.html) is used to expose this rolegroup.
nullable: true
type: string
logging:
default:
containers: {}
Expand Down Expand Up @@ -1478,6 +1484,10 @@ spec:
hbaseRootdir:
nullable: true
type: string
listenerClass:
description: This field controls which [ListenerClass](https://docs.stackable.tech/home/nightly/listener-operator/listenerclass.html) is used to expose this rolegroup.
nullable: true
type: string
logging:
default:
containers: {}
Expand Down
6 changes: 6 additions & 0 deletions deploy/helm/hbase-operator/templates/roles.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ rules:
verbs:
- create
- patch
- apiGroups:
- listeners.stackable.tech
resources:
- listeners
verbs:
- get
- apiGroups:
- {{ include "operator.name" . }}.stackable.tech
resources:
Expand Down
39 changes: 29 additions & 10 deletions docs/modules/hbase/pages/usage-guide/listenerclass.adoc
Original file line number Diff line number Diff line change
@@ -1,18 +1,37 @@
= Service exposition with ListenerClasses
:description: Configure HBase service exposure using ListenerClasses to control internal and external access for all roles.

Apache HBase offers an API.
The operator deploys a service called `<name>` (where `<name>` is the name of the HbaseCluster) through which HBase can be reached.
The operator deploys a xref:listener-operator:listener.adoc[Listener] for each Master, Regionserver and Restserver pod.
They all default to only being accessible from within the Kubernetes cluster, but this can be changed by setting `.spec.{masters,regionServers,restServers}.config.listenerClass`:

This service can have either the `cluster-internal` or `external-unstable` type.
`external-stable` is not supported for HBase at the moment.
Read more about the types in the xref:concepts:service-exposition.adoc[service exposition] documentation at platform level.
[source,yaml]
----
spec:
masters:
config:
listenerClass: external-unstable # <1>
regionServers:
config:
listenerClass: external-unstable
restServers:
config:
listenerClass: external-unstable
----
<1> Specify one of `external-stable`, `external-unstable`, `cluster-internal` (the default setting is `cluster-internal`).
This can be set separately for all three roles.

This is how the listener class is configured:
Externally-reachable endpoints (i.e. where listener-class = `external-unstable` or `external-unstable`) are written to a ConfigMap called `<cluster-name>-ui-endpoints`, listing each rolegroup by replica:

[source,yaml]
----
spec:
clusterConfig:
listenerClass: cluster-internal # <1>
apiVersion: v1
data:
hbase.master-0.ui: 172.19.0.3:32353
hbase.master-1.ui: 172.19.0.5:31817
hbase.regionserver-0.ui: 172.19.0.3:31719
hbase.regionserver-1.ui: 172.19.0.5:30626
hbase.restserver-0.ui: 172.19.0.3:31790
hbase.restserver-1.ui: 172.19.0.5:32292
kind: ConfigMap
...
----
<1> The default `cluster-internal` setting.
85 changes: 38 additions & 47 deletions rust/operator-binary/src/crd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@ pub const SSL_CLIENT_XML: &str = "ssl-client.xml";

pub const HBASE_CLUSTER_DISTRIBUTED: &str = "hbase.cluster.distributed";
pub const HBASE_ROOTDIR: &str = "hbase.rootdir";
pub const HBASE_UNSAFE_REGIONSERVER_HOSTNAME_DISABLE_MASTER_REVERSEDNS: &str =
"hbase.unsafe.regionserver.hostname.disable.master.reversedns";

pub const HBASE_UI_PORT_NAME_HTTP: &str = "ui-http";
pub const HBASE_UI_PORT_NAME_HTTPS: &str = "ui-https";
Expand All @@ -80,6 +78,8 @@ pub const HBASE_REST_UI_PORT: u16 = 8085;
// This port is only used by Hbase prior to version 2.6 with a third-party JMX exporter.
// Newer versions use the same port as the UI because Hbase provides it's own metrics API
pub const METRICS_PORT: u16 = 9100;
pub const LISTENER_VOLUME_NAME: &str = "listener";
pub const LISTENER_VOLUME_DIR: &str = "/stackable/listener";

const DEFAULT_REGION_MOVER_TIMEOUT: Duration = Duration::from_minutes_unchecked(59);
const DEFAULT_REGION_MOVER_DELTA_TO_SHUTDOWN: Duration = Duration::from_minutes_unchecked(1);
Expand All @@ -106,6 +106,9 @@ pub enum Error {

#[snafu(display("incompatible merge types"))]
IncompatibleMergeTypes,

#[snafu(display("role-group is not valid"))]
NoRoleGroup,
}

#[versioned(version(name = "v1alpha1"))]
Expand Down Expand Up @@ -175,18 +178,6 @@ pub mod versioned {
/// for a ZooKeeper cluster.
pub zookeeper_config_map_name: String,

/// This field controls which type of Service the Operator creates for this HbaseCluster:
///
/// * cluster-internal: Use a ClusterIP service
///
/// * external-unstable: Use a NodePort service
///
/// This is a temporary solution with the goal to keep yaml manifests forward compatible.
/// In the future, this setting will control which [ListenerClass](DOCS_BASE_URL_PLACEHOLDER/listener-operator/listenerclass.html)
/// will be used to expose the service, and ListenerClass names will stay the same, allowing for a non-breaking change.
#[serde(default)]
pub listener_class: CurrentlySupportedListenerClasses,

/// Settings related to user [authentication](DOCS_BASE_URL_PLACEHOLDER/usage-guide/security).
pub authentication: Option<AuthenticationConfig>,

Expand Down Expand Up @@ -216,6 +207,11 @@ impl v1alpha1::HbaseCluster {
let defaults =
AnyConfigFragment::default_for(role, &self.name_any(), hdfs_discovery_cm_name);

// Trivial values for role-groups are not allowed
if role_group.is_empty() {
return Err(Error::NoRoleGroup);
}

let (mut role_config, mut role_group_config) = match role {
HbaseRole::RegionServer => {
let role = self
Expand All @@ -231,7 +227,9 @@ impl v1alpha1::HbaseCluster {
.role_groups
.get(role_group)
.map(|rg| rg.config.config.clone())
.unwrap_or_default();
.expect(
"Cannot be empty as trivial values of role-group have already been checked",
);

(
AnyConfigFragment::RegionServer(role_config),
Expand All @@ -253,7 +251,9 @@ impl v1alpha1::HbaseCluster {
.role_groups
.get(role_group)
.map(|rg| rg.config.config.clone())
.unwrap_or_default();
.expect(
"Cannot be empty as trivial values of role-group have already been checked",
);

// Retrieve role resource config
(
Expand All @@ -273,7 +273,9 @@ impl v1alpha1::HbaseCluster {
.role_groups
.get(role_group)
.map(|rg| rg.config.config.clone())
.unwrap_or_default();
.expect(
"Cannot be empty as trivial values of role-group have already been checked",
);

// Retrieve role resource config
(
Expand Down Expand Up @@ -539,7 +541,7 @@ impl v1alpha1::HbaseCluster {
}

/// Name of the port used by the Web UI, which depends on HTTPS usage
fn ui_port_name(&self) -> String {
pub fn ui_port_name(&self) -> String {
if self.has_https_enabled() {
HBASE_UI_PORT_NAME_HTTPS
} else {
Expand All @@ -565,27 +567,6 @@ pub fn merged_env(rolegroup_config: Option<&BTreeMap<String, String>>) -> Vec<En
merged_env
}

// TODO: Temporary solution until listener-operator is finished
#[derive(Clone, Debug, Default, Display, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
#[serde(rename_all = "PascalCase")]
pub enum CurrentlySupportedListenerClasses {
#[default]
#[serde(rename = "cluster-internal")]
ClusterInternal,

#[serde(rename = "external-unstable")]
ExternalUnstable,
}

impl CurrentlySupportedListenerClasses {
pub fn k8s_service_type(&self) -> String {
match self {
CurrentlySupportedListenerClasses::ClusterInternal => "ClusterIP".to_string(),
CurrentlySupportedListenerClasses::ExternalUnstable => "NodePort".to_string(),
}
}
}

#[derive(Clone, Debug, Deserialize, Eq, Hash, JsonSchema, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct KerberosConfig {
Expand Down Expand Up @@ -709,6 +690,7 @@ impl HbaseRole {
affinity: get_affinity(cluster_name, self, hdfs_discovery_cm_name),
graceful_shutdown_timeout: Some(graceful_shutdown_timeout),
requested_secret_lifetime: Some(requested_secret_lifetime),
listener_class: Some("cluster-internal".to_string()),
}
}

Expand Down Expand Up @@ -809,6 +791,7 @@ impl AnyConfigFragment {
cli_opts: None,
},
requested_secret_lifetime: Some(HbaseRole::DEFAULT_REGION_SECRET_LIFETIME),
listener_class: Some("cluster-internal".to_string()),
})
}
HbaseRole::RestServer => AnyConfigFragment::RestServer(HbaseConfigFragment {
Expand All @@ -820,6 +803,7 @@ impl AnyConfigFragment {
HbaseRole::DEFAULT_REST_SERVER_GRACEFUL_SHUTDOWN_TIMEOUT,
),
requested_secret_lifetime: Some(HbaseRole::DEFAULT_REST_SECRET_LIFETIME),
listener_class: Some("cluster-internal".to_string()),
}),
HbaseRole::Master => AnyConfigFragment::Master(HbaseConfigFragment {
hbase_rootdir: None,
Expand All @@ -830,6 +814,7 @@ impl AnyConfigFragment {
HbaseRole::DEFAULT_MASTER_GRACEFUL_SHUTDOWN_TIMEOUT,
),
requested_secret_lifetime: Some(HbaseRole::DEFAULT_MASTER_SECRET_LIFETIME),
listener_class: Some("cluster-internal".to_string()),
}),
}
}
Expand Down Expand Up @@ -907,6 +892,9 @@ pub struct HbaseConfig {
/// Please note that this can be shortened by the `maxCertificateLifetime` setting on the SecretClass issuing the TLS certificate.
#[fragment_attrs(serde(default))]
pub requested_secret_lifetime: Option<Duration>,

/// This field controls which [ListenerClass](DOCS_BASE_URL_PLACEHOLDER/listener-operator/listenerclass.html) is used to expose this rolegroup.
pub listener_class: String,
}

impl Configuration for HbaseConfigFragment {
Expand Down Expand Up @@ -965,10 +953,6 @@ impl Configuration for HbaseConfigFragment {
HBASE_CLUSTER_DISTRIBUTED.to_string(),
Some("true".to_string()),
);
result.insert(
HBASE_UNSAFE_REGIONSERVER_HOSTNAME_DISABLE_MASTER_REVERSEDNS.to_string(),
Some("true".to_string()),
);
result.insert(HBASE_ROOTDIR.to_string(), self.hbase_rootdir.clone());
}
_ => {}
Expand Down Expand Up @@ -1060,6 +1044,9 @@ pub struct RegionServerConfig {
/// The operator will compute a timeout period for the region move that will not exceed the graceful shutdown timeout.
#[fragment_attrs(serde(default))]
pub region_mover: RegionMover,

/// This field controls which [ListenerClass](DOCS_BASE_URL_PLACEHOLDER/listener-operator/listenerclass.html) is used to expose this rolegroup.
pub listener_class: String,
}

impl Configuration for RegionServerConfigFragment {
Expand Down Expand Up @@ -1116,10 +1103,6 @@ impl Configuration for RegionServerConfigFragment {
HBASE_CLUSTER_DISTRIBUTED.to_string(),
Some("true".to_string()),
);
result.insert(
HBASE_UNSAFE_REGIONSERVER_HOSTNAME_DISABLE_MASTER_REVERSEDNS.to_string(),
Some("true".to_string()),
);
result.insert(HBASE_ROOTDIR.to_string(), self.hbase_rootdir.clone());
}
_ => {}
Expand Down Expand Up @@ -1185,6 +1168,14 @@ impl AnyServiceConfig {
}
}

pub fn listener_class(&self) -> String {
match self {
AnyServiceConfig::Master(config) => config.listener_class.clone(),
AnyServiceConfig::RegionServer(config) => config.listener_class.clone(),
AnyServiceConfig::RestServer(config) => config.listener_class.clone(),
}
}

/// Returns command line arguments to pass on to the region mover tool.
/// The following arguments are excluded because they are already part of the
/// hbase-entrypoint.sh script.
Expand Down
Loading