From 873db013182eba0dcab3ba0ee2f0458008b09f3d Mon Sep 17 00:00:00 2001 From: Sebastian Bernauer Date: Mon, 13 Jan 2025 16:12:15 +0100 Subject: [PATCH 01/11] fix: Avllow trailing dots in DomainName --- .../src/commons/networking.rs | 4 +- crates/stackable-operator/src/validation.rs | 37 ++++++++++++++++--- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/crates/stackable-operator/src/commons/networking.rs b/crates/stackable-operator/src/commons/networking.rs index 18feeb074..c42ec32ef 100644 --- a/crates/stackable-operator/src/commons/networking.rs +++ b/crates/stackable-operator/src/commons/networking.rs @@ -11,13 +11,13 @@ use crate::validation; Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, JsonSchema, )] #[serde(try_from = "String", into = "String")] -pub struct DomainName(#[validate(regex(path = "validation::RFC_1123_SUBDOMAIN_REGEX"))] String); +pub struct DomainName(#[validate(regex(path = "validation::FQDN_REGEX"))] String); impl FromStr for DomainName { type Err = validation::Errors; fn from_str(value: &str) -> Result { - validation::is_rfc_1123_subdomain(value)?; + validation::is_fqdn(value)?; Ok(DomainName(value.to_owned())) } } diff --git a/crates/stackable-operator/src/validation.rs b/crates/stackable-operator/src/validation.rs index 76e64f7d6..af1517b22 100644 --- a/crates/stackable-operator/src/validation.rs +++ b/crates/stackable-operator/src/validation.rs @@ -15,18 +15,23 @@ use const_format::concatcp; use regex::Regex; use snafu::Snafu; +/// Minimal length required by RFC 1123 is 63. Up to 255 allowed, unsupported by k8s. +const RFC_1123_LABEL_MAX_LENGTH: usize = 63; // FIXME: According to https://www.rfc-editor.org/rfc/rfc1035#section-2.3.1 domain names must start with a letter // (and not a number). const RFC_1123_LABEL_FMT: &str = "[a-z0-9]([-a-z0-9]*[a-z0-9])?"; +const RFC_1123_LABEL_ERROR_MSG: &str = "a lowercase RFC 1123 label must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character"; + +/// This is a subdomain's max length in DNS (RFC 1123) +const RFC_1123_SUBDOMAIN_MAX_LENGTH: usize = 253; const RFC_1123_SUBDOMAIN_FMT: &str = concatcp!(RFC_1123_LABEL_FMT, "(\\.", RFC_1123_LABEL_FMT, ")*"); const RFC_1123_SUBDOMAIN_ERROR_MSG: &str = "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character"; -const RFC_1123_LABEL_ERROR_MSG: &str = "a lowercase RFC 1123 label must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character"; -// This is a subdomain's max length in DNS (RFC 1123) -const RFC_1123_SUBDOMAIN_MAX_LENGTH: usize = 253; -// Minimal length required by RFC 1123 is 63. Up to 255 allowed, unsupported by k8s. -const RFC_1123_LABEL_MAX_LENGTH: usize = 63; +const FQDN_MAX_LENGTH: usize = RFC_1123_SUBDOMAIN_MAX_LENGTH; +/// Same as [`RFC_1123_SUBDOMAIN_FMT`], but allows a trailing slash +const FQDN_FMT: &str = concatcp!(RFC_1123_SUBDOMAIN_FMT, "\\.?"); +const FQDN_ERROR_MSG: &str = "a FQDN must consist of lower case alphanumeric characters, '-' or '.', and must start with an alphanumeric character and end with an alphanumeric character or '.'"; const RFC_1035_LABEL_FMT: &str = "[a-z]([-a-z0-9]*[a-z0-9])?"; const RFC_1035_LABEL_ERROR_MSG: &str = "a DNS-1035 label must consist of lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character"; @@ -46,6 +51,9 @@ const KERBEROS_REALM_NAME_ERROR_MSG: &str = "Kerberos realm name must only contain alphanumeric characters, '-', and '.'"; // Lazily initialized regular expressions +pub(crate) static FQDN_REGEX: LazyLock = + LazyLock::new(|| Regex::new(&format!("^{FQDN_FMT}$")).expect("failed to compile FQDN regex")); + pub(crate) static RFC_1123_SUBDOMAIN_REGEX: LazyLock = LazyLock::new(|| { Regex::new(&format!("^{RFC_1123_SUBDOMAIN_FMT}$")) .expect("failed to compile RFC 1123 subdomain regex") @@ -178,6 +186,23 @@ fn validate_all(validations: impl IntoIterator>) -> Res } } +pub fn is_fqdn(value: &str) -> Result { + validate_all([ + validate_str_length(value, FQDN_MAX_LENGTH), + validate_str_regex( + value, + &FQDN_REGEX, + FQDN_ERROR_MSG, + &[ + "example.com", + "example.com.", + "cluster.local", + "cluster.local.", + ], + ), + ]) +} + /// Tests for a string that conforms to the definition of a subdomain in DNS (RFC 1123). pub fn is_rfc_1123_subdomain(value: &str) -> Result { validate_all([ @@ -394,6 +419,8 @@ mod tests { #[case(&"a".repeat(253))] fn is_rfc_1123_subdomain_pass(#[case] value: &str) { assert!(is_rfc_1123_subdomain(value).is_ok()); + // Every valid RFC1123 is also a valid FQDN + assert!(is_fqdn(value).is_ok()); } #[test] From 21eb5500a715e3e5f9099be85444e801febd80bf Mon Sep 17 00:00:00 2001 From: Sebastian Bernauer Date: Mon, 13 Jan 2025 16:12:47 +0100 Subject: [PATCH 02/11] Add trailing dot to KubernetesClusterInfo::cluster_domain --- crates/stackable-operator/src/utils/cluster_info.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/crates/stackable-operator/src/utils/cluster_info.rs b/crates/stackable-operator/src/utils/cluster_info.rs index d31275668..ffbf721ad 100644 --- a/crates/stackable-operator/src/utils/cluster_info.rs +++ b/crates/stackable-operator/src/utils/cluster_info.rs @@ -2,18 +2,22 @@ use std::str::FromStr; use crate::commons::networking::DomainName; -const KUBERNETES_CLUSTER_DOMAIN_DEFAULT: &str = "cluster.local"; +const KUBERNETES_CLUSTER_DOMAIN_DEFAULT: &str = "cluster.local."; /// Some information that we know about the Kubernetes cluster. #[derive(Debug, Clone)] pub struct KubernetesClusterInfo { - /// The Kubernetes cluster domain, typically `cluster.local`. + /// The Kubernetes cluster domain, typically `cluster.local.`. pub cluster_domain: DomainName, } #[derive(clap::Parser, Debug, Default, PartialEq, Eq)] pub struct KubernetesClusterInfoOpts { - /// Kubernetes cluster domain, usually this is `cluster.local`. + /// Kubernetes cluster domain, usually this is `cluster.local.`. + /// + /// Please note that we recommend adding a trailing dot (".") for performance reasons, see + /// for details. + // // We are not using a default value here, as operators will probably do an more advanced // auto-detection of the cluster domain in case it is not specified in the future. #[arg(long, env)] @@ -25,6 +29,9 @@ impl KubernetesClusterInfo { let cluster_domain = match &cluster_info_opts.kubernetes_cluster_domain { Some(cluster_domain) => { tracing::info!(%cluster_domain, "Using configured Kubernetes cluster domain"); + if !cluster_domain.ends_with('.') { + tracing::warn!(%cluster_domain, "Your configured Kubernetes cluster domain does not end with a dot (\".\"). We recommend to add a trailing dot for performance reasons, see https://github.com/stackabletech/issues/issues/656 for details"); + } cluster_domain.clone() } From 10627cc0726f084486ec9ebede404111e39aa962 Mon Sep 17 00:00:00 2001 From: Sebastian Bernauer Date: Tue, 14 Jan 2025 09:58:24 +0100 Subject: [PATCH 03/11] Update crates/stackable-operator/src/validation.rs --- crates/stackable-operator/src/validation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/stackable-operator/src/validation.rs b/crates/stackable-operator/src/validation.rs index af1517b22..d08b58520 100644 --- a/crates/stackable-operator/src/validation.rs +++ b/crates/stackable-operator/src/validation.rs @@ -29,7 +29,7 @@ const RFC_1123_SUBDOMAIN_FMT: &str = const RFC_1123_SUBDOMAIN_ERROR_MSG: &str = "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character"; const FQDN_MAX_LENGTH: usize = RFC_1123_SUBDOMAIN_MAX_LENGTH; -/// Same as [`RFC_1123_SUBDOMAIN_FMT`], but allows a trailing slash +/// Same as [`RFC_1123_SUBDOMAIN_FMT`], but allows a trailing dot const FQDN_FMT: &str = concatcp!(RFC_1123_SUBDOMAIN_FMT, "\\.?"); const FQDN_ERROR_MSG: &str = "a FQDN must consist of lower case alphanumeric characters, '-' or '.', and must start with an alphanumeric character and end with an alphanumeric character or '.'"; From 8f175208a0f28b66a0c2cab894f82e5f2042ef6d Mon Sep 17 00:00:00 2001 From: Lukas Krug Date: Tue, 14 Jan 2025 10:01:19 +0100 Subject: [PATCH 04/11] Update crates/stackable-operator/src/utils/cluster_info.rs Co-authored-by: Malte Sander --- crates/stackable-operator/src/utils/cluster_info.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/stackable-operator/src/utils/cluster_info.rs b/crates/stackable-operator/src/utils/cluster_info.rs index ffbf721ad..ea66bb46c 100644 --- a/crates/stackable-operator/src/utils/cluster_info.rs +++ b/crates/stackable-operator/src/utils/cluster_info.rs @@ -15,7 +15,7 @@ pub struct KubernetesClusterInfo { pub struct KubernetesClusterInfoOpts { /// Kubernetes cluster domain, usually this is `cluster.local.`. /// - /// Please note that we recommend adding a trailing dot (".") for performance reasons, see + /// Please note that we recommend adding a trailing dot (".") to reduce DNS requests, see /// for details. // // We are not using a default value here, as operators will probably do an more advanced From c05d30f9ca9fb6c0d92c9b89685743fcc5c63765 Mon Sep 17 00:00:00 2001 From: Lukas Krug Date: Tue, 14 Jan 2025 10:01:27 +0100 Subject: [PATCH 05/11] Update crates/stackable-operator/src/utils/cluster_info.rs Co-authored-by: Malte Sander --- crates/stackable-operator/src/utils/cluster_info.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/stackable-operator/src/utils/cluster_info.rs b/crates/stackable-operator/src/utils/cluster_info.rs index ea66bb46c..b7d732b98 100644 --- a/crates/stackable-operator/src/utils/cluster_info.rs +++ b/crates/stackable-operator/src/utils/cluster_info.rs @@ -30,7 +30,7 @@ impl KubernetesClusterInfo { Some(cluster_domain) => { tracing::info!(%cluster_domain, "Using configured Kubernetes cluster domain"); if !cluster_domain.ends_with('.') { - tracing::warn!(%cluster_domain, "Your configured Kubernetes cluster domain does not end with a dot (\".\"). We recommend to add a trailing dot for performance reasons, see https://github.com/stackabletech/issues/issues/656 for details"); + tracing::warn!(%cluster_domain, "Your configured Kubernetes cluster domain does not end with a dot (\".\"). We recommend to add a trailing dot to reduce DNS requests, see https://github.com/stackabletech/issues/issues/656 for details"); } cluster_domain.clone() From fab9e95af90c003d8cd039b5ec603df1d1a28aa9 Mon Sep 17 00:00:00 2001 From: dervoeti Date: Tue, 14 Jan 2025 10:19:26 +0100 Subject: [PATCH 06/11] chore: update CHANGELOG to reflect breaking changes in cluster domain handling --- crates/stackable-operator/CHANGELOG.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/crates/stackable-operator/CHANGELOG.md b/crates/stackable-operator/CHANGELOG.md index 2796a280f..e523f4df9 100644 --- a/crates/stackable-operator/CHANGELOG.md +++ b/crates/stackable-operator/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Changed + +- BREAKING: Append a dot to the default cluster domain and allow a trailing dot in `DomainName` ([#939]). + +[#939]: https://github.com/stackabletech/operator-rs/pull/939 + ### Added - BREAKING: Aggregate emitted Kubernetes events on the CustomResources thanks to the new @@ -114,7 +120,7 @@ All notable changes to this project will be documented in this file. ### Fixed - BREAKING: `KeyValuePairs::insert` (as well as `Labels::`/`Annotations::` via it) now overwrites - the old value if the key already exists. Previously, `iter()` would return *both* values in + the old value if the key already exists. Previously, `iter()` would return _both_ values in lexicographical order (causing further conversions like `Into` to prefer the maximum value) ([#888]). @@ -316,7 +322,7 @@ All notable changes to this project will be documented in this file. [#808]: https://github.com/stackabletech/operator-rs/pull/808 -## [0.69.1] 2024-06-10 +## [0.69.1] 2024-06-10 ### Added @@ -379,7 +385,7 @@ All notable changes to this project will be documented in this file. ### Changed -- Implement `PartialEq` for most *Snafu* Error enums ([#757]). +- Implement `PartialEq` for most _Snafu_ Error enums ([#757]). - Update Rust to 1.77 ([#759]) ### Fixed @@ -1130,7 +1136,7 @@ This is a rerelease of 0.25.1 which some last-minute incompatible API changes to ### Changed - Objects are now streamed rather than polled when waiting for them to be deleted ([#452]). -- serde\_yaml 0.8.26 -> 0.9.9 ([#450]) +- serde_yaml 0.8.26 -> 0.9.9 ([#450]) [#450]: https://github.com/stackabletech/operator-rs/pull/450 [#452]: https://github.com/stackabletech/operator-rs/pull/452 From 0edc5a8f6f8d064c68a3296e0779b08f059d602b Mon Sep 17 00:00:00 2001 From: dervoeti Date: Tue, 14 Jan 2025 10:23:39 +0100 Subject: [PATCH 07/11] test: add additional test cases for FQDN validation --- crates/stackable-operator/src/validation.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/crates/stackable-operator/src/validation.rs b/crates/stackable-operator/src/validation.rs index d08b58520..ac34204fd 100644 --- a/crates/stackable-operator/src/validation.rs +++ b/crates/stackable-operator/src/validation.rs @@ -423,6 +423,13 @@ mod tests { assert!(is_fqdn(value).is_ok()); } + #[rstest] + #[case("cluster.local")] + #[case("cluster.local.")] + fn is_fqdn_pass(#[case] value: &str) { + assert!(is_fqdn(value).is_ok()); + } + #[test] fn test_mask_trailing_dash() { assert_eq!(mask_trailing_dash("abc-".to_string()), "abca"); From f9d1ae433c5b28725a06fe486b4b83fbd6dd5b1d Mon Sep 17 00:00:00 2001 From: dervoeti Date: Tue, 14 Jan 2025 10:26:17 +0100 Subject: [PATCH 08/11] chore: fixed changelog entry --- crates/stackable-operator/CHANGELOG.md | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/crates/stackable-operator/CHANGELOG.md b/crates/stackable-operator/CHANGELOG.md index e523f4df9..63ba2b99b 100644 --- a/crates/stackable-operator/CHANGELOG.md +++ b/crates/stackable-operator/CHANGELOG.md @@ -4,12 +4,6 @@ All notable changes to this project will be documented in this file. ## [Unreleased] -### Changed - -- BREAKING: Append a dot to the default cluster domain and allow a trailing dot in `DomainName` ([#939]). - -[#939]: https://github.com/stackabletech/operator-rs/pull/939 - ### Added - BREAKING: Aggregate emitted Kubernetes events on the CustomResources thanks to the new @@ -26,6 +20,9 @@ All notable changes to this project will be documented in this file. - BREAKING: Bump Rust dependencies to enable Kubernetes 1.32 (via `kube` 0.98.0 and `k8s-openapi` 0.23.0) ([#867]). +- BREAKING: Append a dot to the default cluster domain and allow a trailing dot in `DomainName` ([#939]). + +[#939]: https://github.com/stackabletech/operator-rs/pull/939 ## [0.83.0] - 2024-12-03 @@ -120,7 +117,7 @@ All notable changes to this project will be documented in this file. ### Fixed - BREAKING: `KeyValuePairs::insert` (as well as `Labels::`/`Annotations::` via it) now overwrites - the old value if the key already exists. Previously, `iter()` would return _both_ values in + the old value if the key already exists. Previously, `iter()` would return *both* values in lexicographical order (causing further conversions like `Into` to prefer the maximum value) ([#888]). @@ -322,7 +319,7 @@ All notable changes to this project will be documented in this file. [#808]: https://github.com/stackabletech/operator-rs/pull/808 -## [0.69.1] 2024-06-10 +## [0.69.1] - 2024-06-10 ### Added @@ -385,7 +382,7 @@ All notable changes to this project will be documented in this file. ### Changed -- Implement `PartialEq` for most _Snafu_ Error enums ([#757]). +- Implement `PartialEq` for most *Snafu* Error enums ([#757]). - Update Rust to 1.77 ([#759]) ### Fixed @@ -1136,7 +1133,7 @@ This is a rerelease of 0.25.1 which some last-minute incompatible API changes to ### Changed - Objects are now streamed rather than polled when waiting for them to be deleted ([#452]). -- serde_yaml 0.8.26 -> 0.9.9 ([#450]) +- serde\_yaml 0.8.26 -> 0.9.9 ([#450]) [#450]: https://github.com/stackabletech/operator-rs/pull/450 [#452]: https://github.com/stackabletech/operator-rs/pull/452 From c470059171fa97daa001df4906bb220e2b69ee49 Mon Sep 17 00:00:00 2001 From: Lukas Krug Date: Tue, 14 Jan 2025 16:54:53 +0100 Subject: [PATCH 09/11] Update crates/stackable-operator/src/utils/cluster_info.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Natalie Klestrup Röijezon --- crates/stackable-operator/src/utils/cluster_info.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/stackable-operator/src/utils/cluster_info.rs b/crates/stackable-operator/src/utils/cluster_info.rs index b7d732b98..9bad4c00d 100644 --- a/crates/stackable-operator/src/utils/cluster_info.rs +++ b/crates/stackable-operator/src/utils/cluster_info.rs @@ -30,7 +30,7 @@ impl KubernetesClusterInfo { Some(cluster_domain) => { tracing::info!(%cluster_domain, "Using configured Kubernetes cluster domain"); if !cluster_domain.ends_with('.') { - tracing::warn!(%cluster_domain, "Your configured Kubernetes cluster domain does not end with a dot (\".\"). We recommend to add a trailing dot to reduce DNS requests, see https://github.com/stackabletech/issues/issues/656 for details"); + tracing::warn!(%cluster_domain, "Your configured Kubernetes cluster domain is not fully qualified (it does not end with a dot (\".\")). We recommend adding a trailing dot to reduce DNS requests, see https://github.com/stackabletech/issues/issues/656 for details"); } cluster_domain.clone() From bea9a4017f5fa2948677738f759982c5c5c19b04 Mon Sep 17 00:00:00 2001 From: dervoeti Date: Tue, 14 Jan 2025 17:20:00 +0100 Subject: [PATCH 10/11] docs: be more explicit about the change in the CHANGELOG --- crates/stackable-operator/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/stackable-operator/CHANGELOG.md b/crates/stackable-operator/CHANGELOG.md index 63ba2b99b..433bec2b9 100644 --- a/crates/stackable-operator/CHANGELOG.md +++ b/crates/stackable-operator/CHANGELOG.md @@ -20,7 +20,7 @@ All notable changes to this project will be documented in this file. - BREAKING: Bump Rust dependencies to enable Kubernetes 1.32 (via `kube` 0.98.0 and `k8s-openapi` 0.23.0) ([#867]). -- BREAKING: Append a dot to the default cluster domain and allow a trailing dot in `DomainName` ([#939]). +- BREAKING: Append a dot to the default cluster domain to make it a FQDN and allow FQDNs when validating a `DomainName` ([#939]). [#939]: https://github.com/stackabletech/operator-rs/pull/939 From 28e9a044154303ca7d6bf84d04fe594f159cda45 Mon Sep 17 00:00:00 2001 From: dervoeti Date: Tue, 14 Jan 2025 17:39:56 +0100 Subject: [PATCH 11/11] fix: renamed some variables and functions, since we validate domains, not just FQDNs --- .../src/commons/networking.rs | 4 +-- crates/stackable-operator/src/validation.rs | 27 ++++++++++--------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/crates/stackable-operator/src/commons/networking.rs b/crates/stackable-operator/src/commons/networking.rs index c42ec32ef..534cd3bb1 100644 --- a/crates/stackable-operator/src/commons/networking.rs +++ b/crates/stackable-operator/src/commons/networking.rs @@ -11,13 +11,13 @@ use crate::validation; Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, JsonSchema, )] #[serde(try_from = "String", into = "String")] -pub struct DomainName(#[validate(regex(path = "validation::FQDN_REGEX"))] String); +pub struct DomainName(#[validate(regex(path = "validation::DOMAIN_REGEX"))] String); impl FromStr for DomainName { type Err = validation::Errors; fn from_str(value: &str) -> Result { - validation::is_fqdn(value)?; + validation::is_domain(value)?; Ok(DomainName(value.to_owned())) } } diff --git a/crates/stackable-operator/src/validation.rs b/crates/stackable-operator/src/validation.rs index ac34204fd..68ad7b8ad 100644 --- a/crates/stackable-operator/src/validation.rs +++ b/crates/stackable-operator/src/validation.rs @@ -28,10 +28,10 @@ const RFC_1123_SUBDOMAIN_FMT: &str = concatcp!(RFC_1123_LABEL_FMT, "(\\.", RFC_1123_LABEL_FMT, ")*"); const RFC_1123_SUBDOMAIN_ERROR_MSG: &str = "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character"; -const FQDN_MAX_LENGTH: usize = RFC_1123_SUBDOMAIN_MAX_LENGTH; +const DOMAIN_MAX_LENGTH: usize = RFC_1123_SUBDOMAIN_MAX_LENGTH; /// Same as [`RFC_1123_SUBDOMAIN_FMT`], but allows a trailing dot -const FQDN_FMT: &str = concatcp!(RFC_1123_SUBDOMAIN_FMT, "\\.?"); -const FQDN_ERROR_MSG: &str = "a FQDN must consist of lower case alphanumeric characters, '-' or '.', and must start with an alphanumeric character and end with an alphanumeric character or '.'"; +const DOMAIN_FMT: &str = concatcp!(RFC_1123_SUBDOMAIN_FMT, "\\.?"); +const DOMAIN_ERROR_MSG: &str = "a domain must consist of lower case alphanumeric characters, '-' or '.', and must start with an alphanumeric character and end with an alphanumeric character or '.'"; const RFC_1035_LABEL_FMT: &str = "[a-z]([-a-z0-9]*[a-z0-9])?"; const RFC_1035_LABEL_ERROR_MSG: &str = "a DNS-1035 label must consist of lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character"; @@ -51,8 +51,9 @@ const KERBEROS_REALM_NAME_ERROR_MSG: &str = "Kerberos realm name must only contain alphanumeric characters, '-', and '.'"; // Lazily initialized regular expressions -pub(crate) static FQDN_REGEX: LazyLock = - LazyLock::new(|| Regex::new(&format!("^{FQDN_FMT}$")).expect("failed to compile FQDN regex")); +pub(crate) static DOMAIN_REGEX: LazyLock = LazyLock::new(|| { + Regex::new(&format!("^{DOMAIN_FMT}$")).expect("failed to compile domain regex") +}); pub(crate) static RFC_1123_SUBDOMAIN_REGEX: LazyLock = LazyLock::new(|| { Regex::new(&format!("^{RFC_1123_SUBDOMAIN_FMT}$")) @@ -186,13 +187,13 @@ fn validate_all(validations: impl IntoIterator>) -> Res } } -pub fn is_fqdn(value: &str) -> Result { +pub fn is_domain(value: &str) -> Result { validate_all([ - validate_str_length(value, FQDN_MAX_LENGTH), + validate_str_length(value, DOMAIN_MAX_LENGTH), validate_str_regex( value, - &FQDN_REGEX, - FQDN_ERROR_MSG, + &DOMAIN_REGEX, + DOMAIN_ERROR_MSG, &[ "example.com", "example.com.", @@ -419,15 +420,15 @@ mod tests { #[case(&"a".repeat(253))] fn is_rfc_1123_subdomain_pass(#[case] value: &str) { assert!(is_rfc_1123_subdomain(value).is_ok()); - // Every valid RFC1123 is also a valid FQDN - assert!(is_fqdn(value).is_ok()); + // Every valid RFC1123 is also a valid domain + assert!(is_domain(value).is_ok()); } #[rstest] #[case("cluster.local")] #[case("cluster.local.")] - fn is_fqdn_pass(#[case] value: &str) { - assert!(is_fqdn(value).is_ok()); + fn is_domain_pass(#[case] value: &str) { + assert!(is_domain(value).is_ok()); } #[test]