Skip to content

Commit ecea5fc

Browse files
Druid 37.0.0 (#832)
* feat: Add support for Druid 37.0.0 This requires providing the aws.region, which necessitated moving the additional MiddleManager jvm configs out of MiddleManagerConfigFragment::compute_files * test: Add 37.0.0, remove 34.0.0 Note: Druid 37.0.0 doesn't support non-TLS S3 connections, so we drop the non-TLS tests. * docs: Update supported versions * chore: Update changelog * Apply suggestions from code review Co-authored-by: Techassi <git@techassi.dev> --------- Co-authored-by: Techassi <git@techassi.dev>
1 parent ff1bc48 commit ecea5fc

6 files changed

Lines changed: 133 additions & 40 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ All notable changes to this project will be documented in this file.
77
### Added
88

99
- BREAKING: Add required CLI argument and env var to set the image repository used to construct final product image names: `IMAGE_REPOSITORY` (`--image-repository`), eg. `oci.example.org/my/namespace` ([#818]).
10-
- Support OIDC `clientAuthenticationMethod` configuration ([#813]).
10+
- Add support for OIDC `clientAuthenticationMethod` configuration ([#813]).
11+
- Add support for Druid 37.0.0 ([#832]).
1112

1213
### Changed
1314

@@ -21,14 +22,16 @@ All notable changes to this project will be documented in this file.
2122

2223
### Deleted
2324

24-
- Removed all metadata storage related properties from product config ([#814]).
25+
- Remove all metadata storage related properties from product config ([#814]).
26+
- Remove support for Druid 34.0.0 ([#832]).
2527

2628
[#810]: https://github.com/stackabletech/druid-operator/pull/810
2729
[#813]: https://github.com/stackabletech/druid-operator/pull/813
2830
[#814]: https://github.com/stackabletech/druid-operator/pull/814
2931
[#818]: https://github.com/stackabletech/druid-operator/pull/818
3032
[#824]: https://github.com/stackabletech/druid-operator/pull/824
3133
[#826]: https://github.com/stackabletech/druid-operator/pull/826
34+
[#832]: https://github.com/stackabletech/druid-operator/pull/832
3235

3336
## [26.3.0] - 2026-03-16
3437

docs/modules/druid/partials/supported-versions.adoc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
// This is a separate file, since it is used by both the direct Druid documentation, and the overarching
33
// Stackable Platform documentation.
44

5-
- 35.0.1
6-
- 34.0.0 (deprecated)
7-
- 30.0.1 (LTS)
5+
- 37.0.0 (LTS)
6+
- 35.0.1 (Deprecated)
7+
- 30.0.1 (Deprecated)

rust/operator-binary/src/config/jvm.rs

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1+
use semver::Version;
12
use snafu::{ResultExt, Snafu};
23
use stackable_operator::{
4+
crd::s3::v1alpha1::ConnectionSpec,
35
memory::MemoryQuantity,
4-
role_utils,
5-
role_utils::{GenericRoleConfig, JavaCommonConfig, JvmArgumentOverrides, Role},
6+
role_utils::{self, GenericRoleConfig, JavaCommonConfig, JvmArgumentOverrides, Role},
67
};
78

89
use crate::crd::{
9-
DruidConfigOverrides, DruidRole, JVM_SECURITY_PROPERTIES_FILE, LOG4J2_CONFIG,
10+
AWS_REGION, DruidConfigOverrides, DruidRole, JVM_SECURITY_PROPERTIES_FILE, LOG4J2_CONFIG,
1011
RW_CONFIG_DIRECTORY, STACKABLE_TRUST_STORE, STACKABLE_TRUST_STORE_PASSWORD,
1112
};
1213

@@ -30,6 +31,9 @@ pub fn construct_jvm_args<T>(
3031
role_group: &str,
3132
heap: MemoryQuantity,
3233
direct_memory: Option<MemoryQuantity>,
34+
s3_conn: Option<&ConnectionSpec>,
35+
// TODO (@NickLarsenNZ): Remove this once we don't support Druid less than 37.0.0
36+
druid_version: Result<Version, semver::Error>,
3337
) -> Result<String, Error> {
3438
let heap_str = heap
3539
.format_for_java()
@@ -67,6 +71,18 @@ pub fn construct_jvm_args<T>(
6771
if druid_role == &DruidRole::Coordinator {
6872
jvm_args.push("-Dderby.stream.error.file=/stackable/var/druid/derby.log".to_owned());
6973
}
74+
// TODO (@NickLarsenNZ): Remove the condition (keep the body) once we no longer support Druid
75+
// less than 37.0.0
76+
// Druid >= 37.0.0 uses the AWS SDK v2, which requires a region to be set via the JVM system
77+
// property `aws.region`.
78+
if matches!(&druid_version, Ok(v) if *v >= Version::new(37, 0, 0))
79+
&& let Some(s3) = s3_conn
80+
{
81+
jvm_args.push(format!(
82+
"-D{AWS_REGION}={region_name}",
83+
region_name = s3.region.name
84+
));
85+
}
7086

7187
let operator_generated = JvmArgumentOverrides::new_with_only_additions(jvm_args);
7288
let merged_jvm_argument_overrides = role
@@ -299,6 +315,15 @@ mod tests {
299315
.get_memory_sizes(druid_role)
300316
.unwrap();
301317

302-
construct_jvm_args(druid_role, &role, "default", heap, direct).unwrap()
318+
construct_jvm_args(
319+
druid_role,
320+
&role,
321+
"default",
322+
heap,
323+
direct,
324+
None,
325+
semver::Version::parse("37.0.0"),
326+
)
327+
.unwrap()
303328
}
304329
}

rust/operator-binary/src/controller.rs

Lines changed: 86 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use product_config::{
1313
types::PropertyNameKind,
1414
writer::{PropertiesWriterError, to_java_properties_string},
1515
};
16+
use semver::Version;
1617
use snafu::{ResultExt, Snafu};
1718
use stackable_operator::{
1819
builder::{
@@ -66,13 +67,15 @@ use crate::{
6667
authentication::DruidAuthenticationConfig,
6768
config::jvm::construct_jvm_args,
6869
crd::{
69-
APP_NAME, AUTH_AUTHORIZER_OPA_URI, CommonRoleGroupConfig, Container,
70+
APP_NAME, AUTH_AUTHORIZER_OPA_URI, AWS_REGION, CommonRoleGroupConfig, Container,
7071
DRUID_CONFIG_DIRECTORY, DS_BUCKET, DeepStorageSpec, DruidClusterStatus, DruidRole,
71-
EXTENSIONS_LOADLIST, HDFS_CONFIG_DIRECTORY, JVM_CONFIG, JVM_SECURITY_PROPERTIES_FILE,
72-
LOG_CONFIG_DIRECTORY, MAX_DRUID_LOG_FILES_SIZE, METRICS_PORT, METRICS_PORT_NAME,
73-
OPERATOR_NAME, RUNTIME_PROPS, RW_CONFIG_DIRECTORY, S3_ACCESS_KEY, S3_ENDPOINT_URL,
74-
S3_PATH_STYLE_ACCESS, S3_SECRET_KEY, STACKABLE_LOG_DIR, ZOOKEEPER_CONNECTION_STRING,
75-
build_recommended_labels, build_string_list, security::DruidTlsSecurity, v1alpha1,
72+
EXTENSIONS_LOADLIST, HDFS_CONFIG_DIRECTORY, INDEXER_JAVA_OPTS, JVM_CONFIG,
73+
JVM_SECURITY_PROPERTIES_FILE, LOG_CONFIG_DIRECTORY, MAX_DRUID_LOG_FILES_SIZE, METRICS_PORT,
74+
METRICS_PORT_NAME, OPERATOR_NAME, RUNTIME_PROPS, RW_CONFIG_DIRECTORY, S3_ACCESS_KEY,
75+
S3_ENDPOINT_URL, S3_PATH_STYLE_ACCESS, S3_SECRET_KEY, S3_USE_TRANSFER_MANAGER,
76+
STACKABLE_LOG_DIR, STACKABLE_TRUST_STORE, STACKABLE_TRUST_STORE_PASSWORD,
77+
ZOOKEEPER_CONNECTION_STRING, build_recommended_labels, build_string_list,
78+
security::DruidTlsSecurity, v1alpha1,
7679
},
7780
discovery::{self, build_discovery_configmaps},
7881
extensions::get_extension_list,
@@ -678,15 +681,42 @@ fn build_rolegroup_config_map(
678681
}
679682

680683
if let Some(s3) = s3_conn {
681-
if !s3.region.is_default_config() {
682-
// Raising this as warning instead of returning an error, better safe than sorry.
683-
// It might still work out for the user.
684-
tracing::warn!(
685-
region = ?s3.region,
686-
"You configured a non-default region on the S3Connection.
687-
The S3Connection region field is ignored because Druid uses the AWS SDK v1, which ignores the region if the endpoint is set. \
688-
The host is a required field, therefore the endpoint will always be set."
689-
)
684+
// TODO (@NickLarsenNZ): Remove the version condition once we no longer support
685+
// Druid less than 37.0.0.
686+
// Druid >= 37.0.0 uses the AWS SDK v2, which requires a region. Older versions
687+
// use the AWS SDK v1, which ignores the region when an endpoint is set (and the
688+
// endpoint is always set because `host` is a required field on S3Connection).
689+
let druid_version = Version::parse(&resolved_product_image.product_version);
690+
match &druid_version {
691+
Ok(v) if *v < Version::new(37, 0, 0) => {
692+
if !s3.region.is_default_config() {
693+
tracing::warn!(
694+
region = ?s3.region,
695+
"You configured a non-default region on the S3Connection. \
696+
The S3Connection region field is ignored because this Druid version \
697+
uses the AWS SDK v1, which ignores the region if the endpoint is set. \
698+
The host is a required field, therefore the endpoint will always be set."
699+
);
700+
}
701+
}
702+
Err(err) => {
703+
tracing::warn!(
704+
%err,
705+
version = %resolved_product_image.product_version,
706+
"Failed to parse Druid product version, skipping S3 region configuration"
707+
);
708+
}
709+
// For Druid >= 37.0.0, region is set via JVM system property
710+
// `-Daws.region` in the JVM_CONFIG section below.
711+
Ok(_) => {
712+
// Disable the S3 Transfer Manager to avoid the AWS
713+
// CRT async HTTP client, which fails with non-AWS
714+
// S3 endpoints. See S3_TRANSFER_MANAGER_ENABLED.
715+
conf.insert(
716+
S3_USE_TRANSFER_MANAGER.to_string(),
717+
Some("false".to_string()),
718+
);
719+
}
690720
}
691721

692722
conf.insert(
@@ -733,6 +763,34 @@ fn build_rolegroup_config_map(
733763
// extend the config to respect overrides
734764
conf.extend(transformed_config);
735765

766+
// Build javaOptsArray for Middle Manager Peon workers.
767+
// These JVM opts are passed to Peon processes spawned by the
768+
// Middle Manager.
769+
if druid_role == DruidRole::MiddleManager {
770+
let mut peon_java_opts = vec![
771+
format!("-Djavax.net.ssl.trustStore={STACKABLE_TRUST_STORE}"),
772+
format!(
773+
"-Djavax.net.ssl.trustStorePassword={STACKABLE_TRUST_STORE_PASSWORD}"
774+
),
775+
"-Djavax.net.ssl.trustStoreType=pkcs12".to_owned(),
776+
];
777+
778+
if let Some(s3) = s3_conn {
779+
let druid_version = Version::parse(&resolved_product_image.product_version);
780+
if matches!(&druid_version, Ok(v) if *v >= Version::new(37, 0, 0)) {
781+
peon_java_opts.push(format!(
782+
"-D{AWS_REGION}={region_name}",
783+
region_name = s3.region.name,
784+
));
785+
}
786+
}
787+
788+
conf.insert(
789+
INDEXER_JAVA_OPTS.to_string(),
790+
Some(build_string_list(&peon_java_opts)),
791+
);
792+
}
793+
736794
let runtime_properties =
737795
to_java_properties_string(conf.iter()).context(PropertiesWriteSnafu)?;
738796
cm_conf_data.insert(RUNTIME_PROPS.to_string(), runtime_properties);
@@ -743,9 +801,19 @@ fn build_rolegroup_config_map(
743801
.resources
744802
.get_memory_sizes(&druid_role)
745803
.context(DeriveMemorySettingsSnafu)?;
746-
let jvm_config =
747-
construct_jvm_args(&druid_role, &role, &rolegroup.role_group, heap, direct)
748-
.context(GetJvmConfigSnafu)?;
804+
// TODO (@NickLarsenNZ): Remove this once we don't support Druid less than 37.0.0
805+
let druid_version = Version::parse(&resolved_product_image.product_version);
806+
let jvm_config = construct_jvm_args(
807+
&druid_role,
808+
&role,
809+
&rolegroup.role_group,
810+
heap,
811+
direct,
812+
s3_conn,
813+
druid_version,
814+
)
815+
.context(GetJvmConfigSnafu)?;
816+
749817
cm_conf_data.insert(JVM_CONFIG.to_string(), jvm_config);
750818
}
751819

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

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ pub const S3_ENDPOINT_URL: &str = "druid.s3.endpoint.url";
105105
pub const S3_ACCESS_KEY: &str = "druid.s3.accessKey";
106106
pub const S3_SECRET_KEY: &str = "druid.s3.secretKey";
107107
pub const S3_PATH_STYLE_ACCESS: &str = "druid.s3.enablePathStyleAccess";
108+
pub const S3_USE_TRANSFER_MANAGER: &str = "druid.storage.transfer.useTransferManager";
109+
/// AWS Region JVM System Property, passed to AWS SDK v2.
110+
/// See: https://druid.apache.org/docs/latest/development/extensions-core/s3/#aws-region
111+
pub const AWS_REGION: &str = "aws.region";
108112
// OPA
109113
pub const AUTH_AUTHORIZERS: &str = "druid.auth.authorizers";
110114
pub const AUTH_AUTHORIZERS_VALUE: &str = "[\"OpaAuthorizer\"]";
@@ -1534,16 +1538,7 @@ impl Configuration for MiddleManagerConfigFragment {
15341538
_role_name: &str,
15351539
file: &str,
15361540
) -> Result<BTreeMap<String, Option<String>>, ConfigError> {
1537-
let mut result = resource.common_compute_files(file)?;
1538-
result.insert(
1539-
INDEXER_JAVA_OPTS.to_string(),
1540-
Some(build_string_list(&[
1541-
format!("-Djavax.net.ssl.trustStore={STACKABLE_TRUST_STORE}"),
1542-
format!("-Djavax.net.ssl.trustStorePassword={STACKABLE_TRUST_STORE_PASSWORD}"),
1543-
"-Djavax.net.ssl.trustStoreType=pkcs12".to_owned(),
1544-
])),
1545-
);
1546-
Ok(result)
1541+
resource.common_compute_files(file)
15471542
}
15481543
}
15491544

tests/test-definition.yaml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ dimensions:
1414
- name: druid
1515
values:
1616
- 30.0.1
17-
- 34.0.0
1817
- 35.0.1
18+
- 37.0.0
1919
# To use a custom image, add a comma and the full name after the product version
2020
# - 30.0.0,oci.stackable.tech/sdp/druid:30.0.0-stackable0.0.0-dev
2121
- name: druid-latest
2222
values:
23-
- 35.0.1
23+
- 37.0.0
2424
# To use a custom image, add a comma and the full name after the product version
2525
# - 30.0.0,oci.stackable.tech/sdp/druid:30.0.0-stackable0.0.0-dev
2626
- name: zookeeper
@@ -43,7 +43,9 @@ dimensions:
4343
- name: s3-use-tls
4444
values:
4545
- "true"
46-
- "false"
46+
# Druid >= 37.0.0 (AWS SDK v2) does not support non-TLS S3 endpoints
47+
# due to SigV4 signing mismatches over HTTP.
48+
# - "false"
4749
- name: tls-mode
4850
values:
4951
- "no-tls"

0 commit comments

Comments
 (0)