Skip to content
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

fix: Include hdfs principal names in discovery ConfigMap #424

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ All notable changes to this project will be documented in this file.

- Don't default roleGroup replicas to zero when not specified ([#402]).
- [BREAKING] Removed field `autoFormatFs`, which was never read ([#422]).
- Include hdfs principals `dfs.journalnode.kerberos.principal`, `dfs.namenode.kerberos.principal`
and `dfs.datanode.kerberos.principal` in the discovery ConfigMap in case Kerberos is enabled ([#424]).

### Removed

Expand All @@ -51,6 +53,7 @@ All notable changes to this project will be documented in this file.
[#407]: https://github.com/stackabletech/hdfs-operator/pull/407
[#409]: https://github.com/stackabletech/hdfs-operator/pull/409
[#422]: https://github.com/stackabletech/hdfs-operator/pull/422
[#424]: https://github.com/stackabletech/hdfs-operator/pull/424
[#425]: https://github.com/stackabletech/hdfs-operator/pull/425

## [23.7.0] - 2023-07-14
Expand Down
11 changes: 10 additions & 1 deletion docs/modules/hdfs/pages/reference/discovery.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,13 @@
Contains the `fs.DefaultFS` which defaults to `hdfs://{clusterName}/`.

`hdfs-site.xml`::
Contains the `dfs.namenode.*` properties for `rpc` and `http` addresses for the `namenodes` as well as the `dfs.nameservices` property which defaults to `hdfs://{clusterName}/`.
Contains the `dfs.namenode.*` properties for `rpc` and `http` addresses for the `namenodes` as well as the `dfs.nameservices` property which defaults to `hdfs://{clusterName}/`.

=== Kerberos
In case Kerberos is enabled according the xref:usage-guide/security.adoc[security documentation] the discovery will also include the information that clients must authenticate themselves using Kerberos.

Some Kerberos-related configs require the environmental variable `KERBEROS_REALM` to be set (e.g. using `export KERBEROS_REALM=$(grep -oP 'default_realm = \K.*' /stackable/kerberos/krb5.conf)`).
When you want to use the discovery configmap outside of Stackable services, you need to provide this environment variable!

Check notice on line 46 in docs/modules/hdfs/pages/reference/discovery.adoc

View workflow job for this annotation

GitHub Actions / LanguageTool

[LanguageTool] docs/modules/hdfs/pages/reference/discovery.adoc#L46

This phrase is redundant. Consider using “outside”. (OUTSIDE_OF[1]) Suggestions: `outside` URL: https://languagetool.org/insights/post/wordiness/ Rule: https://community.languagetool.org/rule/show/OUTSIDE_OF?lang=en-US&subId=1 Category: REDUNDANCY
Raw output
docs/modules/hdfs/pages/reference/discovery.adoc:46:45: This phrase is redundant. Consider using “outside”. (OUTSIDE_OF[1])
 Suggestions: `outside`
 URL: https://languagetool.org/insights/post/wordiness/ 
 Rule: https://community.languagetool.org/rule/show/OUTSIDE_OF?lang=en-US&subId=1
 Category: REDUNDANCY
As an alternative you can text-replace `${env.KERBEROS_REALM}` with your actual realm (e.g. by using `sed -i -e 's/${{env.KERBEROS_REALM}}/'"$KERBEROS_REALM/g" hbase-site.xml`).

One example would be the property `dfs.namenode.kerberos.principal` being set to `nn/hdfs.kuttl-test-daring-mammal.svc.cluster.local@${env.KERBEROS_REALM}`.
6 changes: 4 additions & 2 deletions rust/crd/src/affinity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ spec:
replicas: 1
"#;
let hdfs: HdfsCluster = serde_yaml::from_str(input).unwrap();
let merged_config = role.merged_config(&hdfs, "default").unwrap();
let merged_config = role.merged_config(&hdfs, "simple-hdfs", "default").unwrap();

assert_eq!(
merged_config.affinity(),
Expand Down Expand Up @@ -168,7 +168,9 @@ spec:
- antarctica-west1
"#;
let hdfs: HdfsCluster = serde_yaml::from_str(input).unwrap();
let merged_config = HdfsRole::DataNode.merged_config(&hdfs, "default").unwrap();
let merged_config = HdfsRole::DataNode
.merged_config(&hdfs, "simple-hdfs", "default")
.unwrap();

assert_eq!(
merged_config.affinity(),
Expand Down
22 changes: 11 additions & 11 deletions rust/crd/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use stackable_operator::{
api::core::v1::PodTemplateSpec,
apimachinery::pkg::{api::resource::Quantity, apis::meta::v1::LabelSelector},
},
kube::{runtime::reflector::ObjectRef, CustomResource, ResourceExt},
kube::{runtime::reflector::ObjectRef, CustomResource},
labels::role_group_selector_labels,
product_config_utils::{ConfigError, Configuration},
product_logging,
Expand Down Expand Up @@ -264,11 +264,12 @@ impl HdfsRole {
pub fn merged_config(
&self,
hdfs: &HdfsCluster,
hdfs_name: &str,
role_group: &str,
) -> Result<Box<dyn MergedConfig + Send + 'static>, Error> {
match self {
HdfsRole::NameNode => {
let default_config = NameNodeConfigFragment::default_config(&hdfs.name_any(), self);
let default_config = NameNodeConfigFragment::default_config(hdfs_name, self);
let role = hdfs
.spec
.name_nodes
Expand Down Expand Up @@ -307,7 +308,7 @@ impl HdfsRole {
))
}
HdfsRole::DataNode => {
let default_config = DataNodeConfigFragment::default_config(&hdfs.name_any(), self);
let default_config = DataNodeConfigFragment::default_config(hdfs_name, self);
let role = hdfs
.spec
.data_nodes
Expand Down Expand Up @@ -346,8 +347,7 @@ impl HdfsRole {
))
}
HdfsRole::JournalNode => {
let default_config =
JournalNodeConfigFragment::default_config(&hdfs.name_any(), self);
let default_config = JournalNodeConfigFragment::default_config(hdfs_name, self);
let role = hdfs
.spec
.journal_nodes
Expand Down Expand Up @@ -1344,7 +1344,7 @@ spec:
let hdfs: HdfsCluster = serde_yaml::from_str(cr).unwrap();
let role = HdfsRole::DataNode;
let resources = role
.merged_config(&hdfs, "default")
.merged_config(&hdfs, "hdfs", "default")
.unwrap()
.data_node_resources()
.unwrap();
Expand Down Expand Up @@ -1382,7 +1382,7 @@ spec:
let hdfs: HdfsCluster = serde_yaml::from_str(cr).unwrap();
let role = HdfsRole::DataNode;
let resources = role
.merged_config(&hdfs, "default")
.merged_config(&hdfs, "hdfs", "default")
.unwrap()
.data_node_resources()
.unwrap();
Expand Down Expand Up @@ -1415,7 +1415,7 @@ spec:
let hdfs: HdfsCluster = serde_yaml::from_str(cr).unwrap();
let role = HdfsRole::DataNode;
let resources = role
.merged_config(&hdfs, "default")
.merged_config(&hdfs, "hdfs", "default")
.unwrap()
.data_node_resources()
.unwrap();
Expand Down Expand Up @@ -1469,7 +1469,7 @@ spec:
let hdfs: HdfsCluster = serde_yaml::from_str(cr).unwrap();
let role = HdfsRole::DataNode;
let resources = role
.merged_config(&hdfs, "default")
.merged_config(&hdfs, "hdfs", "default")
.unwrap()
.data_node_resources()
.unwrap();
Expand Down Expand Up @@ -1519,7 +1519,7 @@ spec:
let hdfs: HdfsCluster = serde_yaml::from_str(cr).unwrap();
let role = HdfsRole::DataNode;
let rr: ResourceRequirements = role
.merged_config(&hdfs, "default")
.merged_config(&hdfs, "hdfs", "default")
.unwrap()
.data_node_resources()
.unwrap()
Expand Down Expand Up @@ -1572,7 +1572,7 @@ spec:
let hdfs: HdfsCluster = serde_yaml::from_str(cr).unwrap();
let role = HdfsRole::DataNode;
let rr: ResourceRequirements = role
.merged_config(&hdfs, "default")
.merged_config(&hdfs, "hdfs", "default")
.unwrap()
.data_node_resources()
.unwrap()
Expand Down
55 changes: 41 additions & 14 deletions rust/operator-binary/src/container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::product_logging::{
};

use indoc::formatdoc;
use snafu::{OptionExt, ResultExt, Snafu};
use snafu::{ResultExt, Snafu};
use stackable_hdfs_crd::{
constants::{
DATANODE_ROOT_DATA_DIR_PREFIX, DEFAULT_DATA_NODE_METRICS_PORT,
Expand Down Expand Up @@ -151,6 +151,8 @@ impl ContainerConfig {
pub fn add_containers_and_volumes(
pb: &mut PodBuilder,
hdfs: &HdfsCluster,
hdfs_name: &str,
hdfs_namespace: &str,
role: &HdfsRole,
resolved_product_image: &ResolvedProductImage,
merged_config: &(dyn MergedConfig + Send + 'static),
Expand All @@ -164,6 +166,8 @@ impl ContainerConfig {
pb.add_volumes(main_container_config.volumes(merged_config, object_name));
pb.add_container(main_container_config.main_container(
hdfs,
hdfs_name,
hdfs_namespace,
role,
resolved_product_image,
zk_config_map_name,
Expand Down Expand Up @@ -209,7 +213,7 @@ impl ContainerConfig {
SecretOperatorVolumeSourceBuilder::new(
&authentication_config.kerberos.secret_class,
)
.with_service_scope(hdfs.name_any())
.with_service_scope(hdfs_name)
.with_kerberos_service_name(role.kerberos_service_name())
.with_kerberos_service_name("HTTP")
.build(),
Expand All @@ -226,6 +230,8 @@ impl ContainerConfig {
pb.add_volumes(zkfc_container_config.volumes(merged_config, object_name));
pb.add_container(zkfc_container_config.main_container(
hdfs,
hdfs_name,
hdfs_namespace,
role,
resolved_product_image,
zk_config_map_name,
Expand All @@ -241,6 +247,8 @@ impl ContainerConfig {
);
pb.add_init_container(format_namenodes_container_config.init_container(
hdfs,
hdfs_name,
hdfs_namespace,
role,
resolved_product_image,
zk_config_map_name,
Expand All @@ -257,6 +265,8 @@ impl ContainerConfig {
);
pb.add_init_container(format_zookeeper_container_config.init_container(
hdfs,
hdfs_name,
hdfs_namespace,
role,
resolved_product_image,
zk_config_map_name,
Expand All @@ -274,6 +284,8 @@ impl ContainerConfig {
);
pb.add_init_container(wait_for_namenodes_container_config.init_container(
hdfs,
hdfs_name,
hdfs_namespace,
role,
resolved_product_image,
zk_config_map_name,
Expand Down Expand Up @@ -317,9 +329,13 @@ impl ContainerConfig {
/// - Namenode ZooKeeper fail over controller (ZKFC)
/// - Datanode main process
/// - Journalnode main process

#[allow(clippy::too_many_arguments)]
fn main_container(
&self,
hdfs: &HdfsCluster,
hdfs_name: &str,
hdfs_namespace: &str,
role: &HdfsRole,
resolved_product_image: &ResolvedProductImage,
zookeeper_config_map_name: &str,
Expand All @@ -335,7 +351,7 @@ impl ContainerConfig {

cb.image_from_product_image(resolved_product_image)
.command(Self::command())
.args(self.args(hdfs, role, merged_config, &[])?)
.args(self.args(hdfs, hdfs_name, hdfs_namespace, role, merged_config, &[]))
.add_env_vars(self.env(
hdfs,
zookeeper_config_map_name,
Expand Down Expand Up @@ -364,6 +380,8 @@ impl ContainerConfig {
fn init_container(
&self,
hdfs: &HdfsCluster,
hdfs_name: &str,
hdfs_namespace: &str,
role: &HdfsRole,
resolved_product_image: &ResolvedProductImage,
zookeeper_config_map_name: &str,
Expand All @@ -376,7 +394,14 @@ impl ContainerConfig {

cb.image_from_product_image(resolved_product_image)
.command(Self::command())
.args(self.args(hdfs, role, merged_config, namenode_podrefs)?)
.args(self.args(
hdfs,
hdfs_name,
hdfs_namespace,
role,
merged_config,
namenode_podrefs,
))
.add_env_vars(self.env(hdfs, zookeeper_config_map_name, env_overrides, None))
.add_volume_mounts(self.volume_mounts(hdfs, merged_config));

Expand Down Expand Up @@ -427,10 +452,12 @@ impl ContainerConfig {
fn args(
&self,
hdfs: &HdfsCluster,
hdfs_name: &str,
hdfs_namespace: &str,
role: &HdfsRole,
merged_config: &(dyn MergedConfig + Send + 'static),
namenode_podrefs: &[HdfsPodRef],
) -> Result<Vec<String>, Error> {
) -> Vec<String> {
let mut args = String::new();
args.push_str(&self.create_config_directory_cmd());
args.push_str(&self.copy_config_xml_cmd());
Expand Down Expand Up @@ -489,7 +516,7 @@ wait_for_termination $!
// If there is no active namenode, the current pod is not formatted we format as
// active namenode. Otherwise as standby node.
if hdfs.has_kerberos_enabled() {
args.push_str(&Self::get_kerberos_ticket(hdfs, role)?);
args.push_str(&Self::get_kerberos_ticket(hdfs_name, hdfs_namespace, role));
}
args.push_str(&formatdoc!(
r###"
Expand Down Expand Up @@ -570,7 +597,7 @@ wait_for_termination $!
));
}
if hdfs.has_kerberos_enabled() {
args.push_str(&Self::get_kerberos_ticket(hdfs, role)?);
args.push_str(&Self::get_kerberos_ticket(hdfs_name, hdfs_namespace, role));
}
args.push_str(&formatdoc!(
r###"
Expand Down Expand Up @@ -610,7 +637,7 @@ wait_for_termination $!
));
}
}
Ok(vec![args])
vec![args]
}

// Command to export `KERBEROS_REALM` env var to default real from krb5.conf, e.g. `CLUSTER.LOCAL`
Expand All @@ -622,19 +649,19 @@ wait_for_termination $!
/// Command to `kinit` a ticket using the principal created for the specified hdfs role
/// Needs the KERBEROS_REALM env var, which will be written with `export_kerberos_real_env_var_command`
/// Needs the POD_NAME env var to be present, which will be provided by the PodSpec
fn get_kerberos_ticket(hdfs: &HdfsCluster, role: &HdfsRole) -> Result<String, Error> {
fn get_kerberos_ticket(hdfs_name: &str, hdfs_namespace: &str, role: &HdfsRole) -> String {
// Watch out, this is a bash substitution from a bash env var,
// not the substitution hdfs is doing.
let principal = format!(
"{service_name}/{hdfs_name}.{namespace}.svc.cluster.local@${{KERBEROS_REALM}}",
"{service_name}/{hdfs_name}.{hdfs_namespace}.svc.cluster.local@${{KERBEROS_REALM}}",
service_name = role.kerberos_service_name(),
hdfs_name = hdfs.name_any(),
namespace = hdfs.namespace().context(ObjectHasNoNamespaceSnafu)?,
);
Ok(formatdoc!(
formatdoc!(
r###"
echo "Getting ticket for {principal}" from /stackable/kerberos/keytab
kinit "{principal}" -kt /stackable/kerberos/keytab
"###,
))
)
}

fn get_namenode_service_state_command() -> String {
Expand Down
21 changes: 13 additions & 8 deletions rust/operator-binary/src/discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ use stackable_operator::{
commons::product_image_selection::ResolvedProductImage,
error::OperatorResult,
k8s_openapi::api::core::v1::ConfigMap,
kube::ResourceExt,
};

/// Creates a discovery config map containing the `hdfs-site.xml` and `core-site.xml`
/// for clients.
pub fn build_discovery_configmap(
hdfs: &HdfsCluster,
hdfs_name: &str,
hdfs_namespace: &str,
controller: &str,
namenode_podrefs: &[HdfsPodRef],
resolved_product_image: &ResolvedProductImage,
Expand All @@ -38,21 +39,21 @@ pub fn build_discovery_configmap(
)
.add_data(
HDFS_SITE_XML,
build_discovery_hdfs_site_xml(hdfs, hdfs.name_any(), namenode_podrefs),
build_discovery_hdfs_site_xml(hdfs, hdfs_name, namenode_podrefs),
)
.add_data(
CORE_SITE_XML,
build_discovery_core_site_xml(hdfs, hdfs.name_any()),
build_discovery_core_site_xml(hdfs, hdfs_name, hdfs_namespace),
)
.build()
}

fn build_discovery_hdfs_site_xml(
hdfs: &HdfsCluster,
logical_name: String,
hdfs_name: &str,
namenode_podrefs: &[HdfsPodRef],
) -> String {
HdfsSiteConfigBuilder::new(logical_name)
HdfsSiteConfigBuilder::new(hdfs_name.to_string())
.dfs_name_services()
.dfs_ha_namenodes(namenode_podrefs)
.dfs_namenode_rpc_address_ha(namenode_podrefs)
Expand All @@ -62,9 +63,13 @@ fn build_discovery_hdfs_site_xml(
.build_as_xml()
}

fn build_discovery_core_site_xml(hdfs: &HdfsCluster, logical_name: String) -> String {
CoreSiteConfigBuilder::new(logical_name)
fn build_discovery_core_site_xml(
hdfs: &HdfsCluster,
hdfs_name: &str,
hdfs_namespace: &str,
) -> String {
CoreSiteConfigBuilder::new(hdfs_name.to_string())
.fs_default_fs()
.security_discovery_config(hdfs)
.security_discovery_config(hdfs, hdfs_name, hdfs_namespace)
.build_as_xml()
}
Loading