diff --git a/crates/stackable-operator/CHANGELOG.md b/crates/stackable-operator/CHANGELOG.md index e882a2862..09b8e3595 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] +### Added + +- Add `region` field to S3ConnectionSpec ([#959]). + +[#959]: https://github.com/stackabletech/operator-rs/pull/959 + ## [0.86.0] - 2025-01-30 ### Added diff --git a/crates/stackable-operator/src/commons/s3/crd.rs b/crates/stackable-operator/src/commons/s3/crd.rs index d1609ccb9..f378a6176 100644 --- a/crates/stackable-operator/src/commons/s3/crd.rs +++ b/crates/stackable-operator/src/commons/s3/crd.rs @@ -56,6 +56,23 @@ pub struct S3ConnectionSpec { #[serde(default, skip_serializing_if = "Option::is_none")] pub port: Option, + /// AWS service API region used by the AWS SDK when using AWS S3 buckets. + /// + /// This defaults to `us-east-1` and can be ignored if not using AWS S3 + /// buckets. + /// + /// NOTE: This is not the bucket region, and is used by the AWS SDK to + /// construct endpoints for various AWS service APIs. It is only useful when + /// using AWS S3 buckets. + /// + /// When using AWS S3 buckets, you can configure optimal AWS service API + /// connections in the following ways: + /// - From **inside** AWS: Use an auto-discovery source (eg: AWS IMDS). + /// - From **outside** AWS, or when IMDS is disabled, explicity set the + /// region name nearest to where the client application is running from. + #[serde(default)] + pub region: AwsRegion, + /// Which access style to use. /// Defaults to virtual hosted-style as most of the data products out there. /// Have a look at the [AWS documentation](https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html). @@ -85,3 +102,57 @@ pub enum S3AccessStyle { #[default] VirtualHosted, } + +/// Set a named AWS region, or defer to an auto-discovery mechanism. +#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)] +#[serde(rename_all = "camelCase")] +pub enum AwsRegion { + /// Defer region detection to an auto-discovery mechanism. + Source(AwsRegionAutoDiscovery), + + /// An explicit region, eg: eu-central-1 + Name(String), +} + +impl AwsRegion { + /// Get the AWS region name. + /// + /// Returns `None` if an auto-discovery source has been selected. Otherwise, + /// it returns the configured region name. + /// + /// Example usage: + /// + /// ``` + /// # use stackable_operator::commons::s3::AwsRegion; + /// # fn set_property(key: &str, value: String) {} + /// # fn example(aws_region: AwsRegion) { + /// if let Some(region_name) = aws_region.name() { + /// // set some property if the region is set, or is the default. + /// set_property("aws.region", region_name); + /// }; + /// # } + /// ``` + pub fn name(self) -> Option { + match self { + AwsRegion::Name(name) => Some(name), + AwsRegion::Source(_) => None, + } + } +} + +impl Default for AwsRegion { + fn default() -> Self { + Self::Name("us-east-1".to_owned()) + } +} + +/// AWS region auto-discovery mechanism. +#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)] +#[serde(rename_all = "PascalCase")] +pub enum AwsRegionAutoDiscovery { + /// AWS Instance Meta Data Service. + /// + /// This variant should result in no region being given to the AWS SDK, + /// which should, in turn, query the AWS IMDS. + AwsImds, +} diff --git a/crates/stackable-operator/src/commons/s3/helpers.rs b/crates/stackable-operator/src/commons/s3/helpers.rs index 654bee025..1cb13eac3 100644 --- a/crates/stackable-operator/src/commons/s3/helpers.rs +++ b/crates/stackable-operator/src/commons/s3/helpers.rs @@ -201,6 +201,7 @@ mod tests { access_style: Default::default(), credentials: None, tls: TlsClientDetails { tls: None }, + region: Default::default(), }; let (volumes, mounts) = s3.volumes_and_mounts().unwrap(); @@ -226,6 +227,7 @@ mod tests { }), }), }, + region: Default::default(), }; let (mut volumes, mut mounts) = s3.volumes_and_mounts().unwrap(); @@ -278,6 +280,7 @@ mod tests { verification: TlsVerification::None {}, }), }, + region: Default::default(), }; let (volumes, mounts) = s3.volumes_and_mounts().unwrap();