Skip to content

Commit 58cb34c

Browse files
committed
feat: Support configuring JVM arguments
1 parent 8a9c5b9 commit 58cb34c

File tree

8 files changed

+329
-70
lines changed

8 files changed

+329
-70
lines changed

deploy/helm/hive-operator/crds/crds.yaml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,32 @@ spec:
507507
default: {}
508508
description: '`envOverrides` configure environment variables to be set in the Pods. It is a map from strings to strings - environment variables and the value to set. Read the [environment variable overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#env-overrides) for more information and consult the operator specific usage guide to find out about the product specific environment variables that are available.'
509509
type: object
510+
jvmArgumentOverrides:
511+
default:
512+
add: []
513+
remove: []
514+
removeRegex: []
515+
description: Allows overriding JVM arguments. Please read on the [JVM argument overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#jvm-argument-overrides) for details on the usage.
516+
properties:
517+
add:
518+
default: []
519+
description: JVM arguments to be added
520+
items:
521+
type: string
522+
type: array
523+
remove:
524+
default: []
525+
description: JVM arguments to be removed by exact match
526+
items:
527+
type: string
528+
type: array
529+
removeRegex:
530+
default: []
531+
description: JVM arguments matching any of this regexes will be removed
532+
items:
533+
type: string
534+
type: array
535+
type: object
510536
podOverrides:
511537
default: {}
512538
description: In the `podOverrides` property you can define a [PodTemplateSpec](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#podtemplatespec-v1-core) to override any property that can be set on a Kubernetes Pod. Read the [Pod overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#pod-overrides) for more information.
@@ -775,6 +801,32 @@ spec:
775801
default: {}
776802
description: '`envOverrides` configure environment variables to be set in the Pods. It is a map from strings to strings - environment variables and the value to set. Read the [environment variable overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#env-overrides) for more information and consult the operator specific usage guide to find out about the product specific environment variables that are available.'
777803
type: object
804+
jvmArgumentOverrides:
805+
default:
806+
add: []
807+
remove: []
808+
removeRegex: []
809+
description: Allows overriding JVM arguments. Please read on the [JVM argument overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#jvm-argument-overrides) for details on the usage.
810+
properties:
811+
add:
812+
default: []
813+
description: JVM arguments to be added
814+
items:
815+
type: string
816+
type: array
817+
remove:
818+
default: []
819+
description: JVM arguments to be removed by exact match
820+
items:
821+
type: string
822+
type: array
823+
removeRegex:
824+
default: []
825+
description: JVM arguments matching any of this regexes will be removed
826+
items:
827+
type: string
828+
type: array
829+
type: object
778830
podOverrides:
779831
default: {}
780832
description: In the `podOverrides` property you can define a [PodTemplateSpec](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#podtemplatespec-v1-core) to override any property that can be set on a Kubernetes Pod. Read the [Pod overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#pod-overrides) for more information.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,10 @@ metastore:
101101

102102
The Hive operator also supports Pod overrides, allowing you to override any property that you can set on a Kubernetes Pod.
103103
Read the xref:concepts:overrides.adoc#pod-overrides[Pod overrides documentation] to learn more about this feature.
104+
105+
== JVM argument overrides
106+
107+
Stackable operators automatically determine the set of needed JVM arguments, such as memory settings or trust- and keystores.
108+
Using JVM argument overrides you can configure the JVM arguments xref:concepts:overrides.adoc#jvm-argument-overrides[according to the concepts page].
109+
110+
One thing that is different for Hive metastores, is that all heap-related arguments will be passed in via the env variable `HADOOP_HEAPSIZE`, all the other ones via `HADOOP_OPTS`.

docs/modules/hive/partials/nav.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
** xref:hive:usage-guide/monitoring.adoc[]
1212
** xref:hive:usage-guide/resources.adoc[]
1313
** xref:hive:usage-guide/security.adoc[]
14-
** xref:hive:usage-guide/configuration-environment-overrides.adoc[]
14+
** xref:hive:usage-guide/overrides.adoc[]
1515
** xref:hive:usage-guide/operations/index.adoc[]
1616
*** xref:hive:usage-guide/operations/cluster-operations.adoc[]
1717
*** xref:hive:usage-guide/operations/pod-placement.adoc[]
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
use crate::crd::{
2+
v1alpha1::HiveCluster, MetaStoreConfig, MetaStoreConfigFragment, JVM_SECURITY_PROPERTIES_FILE,
3+
METRICS_PORT, STACKABLE_CONFIG_DIR, STACKABLE_TRUST_STORE, STACKABLE_TRUST_STORE_PASSWORD,
4+
};
5+
use snafu::{OptionExt, ResultExt, Snafu};
6+
use stackable_operator::{
7+
memory::{BinaryMultiple, MemoryQuantity},
8+
role_utils::{self, GenericRoleConfig, JavaCommonConfig, JvmArgumentOverrides, Role},
9+
};
10+
11+
const JAVA_HEAP_FACTOR: f32 = 0.8;
12+
13+
#[derive(Snafu, Debug)]
14+
pub enum Error {
15+
#[snafu(display("invalid memory resource configuration - missing default or value in crd?"))]
16+
MissingMemoryResourceConfig,
17+
18+
#[snafu(display("invalid memory config"))]
19+
InvalidMemoryConfig {
20+
source: stackable_operator::memory::Error,
21+
},
22+
23+
#[snafu(display("failed to merge jvm argument overrides"))]
24+
MergeJvmArgumentOverrides { source: role_utils::Error },
25+
}
26+
27+
/// All JVM arguments.
28+
fn construct_jvm_args(
29+
hive: &HiveCluster,
30+
merged_config: &MetaStoreConfig,
31+
role: &Role<MetaStoreConfigFragment, GenericRoleConfig, JavaCommonConfig>,
32+
role_group: &str,
33+
) -> Result<Vec<String>, Error> {
34+
let heap_size = MemoryQuantity::try_from(
35+
merged_config
36+
.resources
37+
.memory
38+
.limit
39+
.as_ref()
40+
.context(MissingMemoryResourceConfigSnafu)?,
41+
)
42+
.context(InvalidMemoryConfigSnafu)?
43+
.scale_to(BinaryMultiple::Mebi)
44+
* JAVA_HEAP_FACTOR;
45+
let java_heap = heap_size
46+
.format_for_java()
47+
.context(InvalidMemoryConfigSnafu)?;
48+
49+
let mut jvm_args = vec![
50+
// Heap settings
51+
format!("-Xmx{java_heap}"),
52+
format!("-Xms{java_heap}"),
53+
format!("-Djava.security.properties={STACKABLE_CONFIG_DIR}/{JVM_SECURITY_PROPERTIES_FILE}"),
54+
format!("-javaagent:/stackable/jmx/jmx_prometheus_javaagent.jar={METRICS_PORT}:/stackable/jmx/jmx_hive_config.yaml"),
55+
format!("-Djavax.net.ssl.trustStore={STACKABLE_TRUST_STORE}"),
56+
format!("-Djavax.net.ssl.trustStorePassword={STACKABLE_TRUST_STORE_PASSWORD}"),
57+
format!("-Djavax.net.ssl.trustStoreType=pkcs12"),
58+
];
59+
60+
if hive.has_kerberos_enabled() {
61+
jvm_args.push("-Djava.security.krb5.conf=/stackable/kerberos/krb5.conf".to_owned());
62+
}
63+
64+
let operator_generated = JvmArgumentOverrides::new_with_only_additions(jvm_args);
65+
let merged = role
66+
.get_merged_jvm_argument_overrides(role_group, &operator_generated)
67+
.context(MergeJvmArgumentOverridesSnafu)?;
68+
Ok(merged
69+
.effective_jvm_config_after_merging()
70+
// Sorry for the clone, that's how operator-rs is currently modelled :P
71+
.clone())
72+
}
73+
74+
/// Arguments that go into `HADOOP_OPTS`, so *not* the heap settings (which you can get using
75+
/// [`construct_heap_jvm_args`]).
76+
pub fn construct_non_heap_jvm_args(
77+
hive: &HiveCluster,
78+
merged_config: &MetaStoreConfig,
79+
role: &Role<MetaStoreConfigFragment, GenericRoleConfig, JavaCommonConfig>,
80+
role_group: &str,
81+
) -> Result<String, Error> {
82+
let mut jvm_args = construct_jvm_args(hive, merged_config, role, role_group)?;
83+
jvm_args.retain(|arg| !is_heap_jvm_argument(arg));
84+
85+
Ok(jvm_args.join(" "))
86+
}
87+
88+
/// Arguments that go into `HADOOP_HEAPSIZE`.
89+
/// You can get the normal JVM arguments using [`construct_non_heap_jvm_args`].
90+
pub fn construct_heap_jvm_args(
91+
hive: &HiveCluster,
92+
merged_config: &MetaStoreConfig,
93+
role: &Role<MetaStoreConfigFragment, GenericRoleConfig, JavaCommonConfig>,
94+
role_group: &str,
95+
) -> Result<String, Error> {
96+
let mut jvm_args = construct_jvm_args(hive, merged_config, role, role_group)?;
97+
jvm_args.retain(|arg| is_heap_jvm_argument(arg));
98+
99+
Ok(jvm_args.join(" "))
100+
}
101+
102+
fn is_heap_jvm_argument(jvm_argument: &str) -> bool {
103+
let lowercase = jvm_argument.to_lowercase();
104+
105+
lowercase.starts_with("-xms") || lowercase.starts_with("-xmx")
106+
}
107+
108+
#[cfg(test)]
109+
mod tests {
110+
use crate::crd::HiveRole;
111+
112+
use super::*;
113+
114+
#[test]
115+
fn test_construct_jvm_arguments_defaults() {
116+
let input = r#"
117+
apiVersion: hive.stackable.tech/v1alpha1
118+
kind: HiveCluster
119+
metadata:
120+
name: simple-hive
121+
spec:
122+
image:
123+
productVersion: 4.0.0
124+
clusterConfig:
125+
database:
126+
connString: jdbc:derby:;databaseName=/tmp/hive;create=true
127+
dbType: derby
128+
credentialsSecret: mySecret
129+
metastore:
130+
roleGroups:
131+
default:
132+
replicas: 1
133+
"#;
134+
let (hive, hive_role, role, merged_config) = construct_boilerplate(input);
135+
let non_heap_jvm_args =
136+
construct_non_heap_jvm_args(&hive, &hive_role, &role, &merged_config).unwrap();
137+
let heap_jvm_args =
138+
construct_heap_jvm_args(&hive, &hive_role, &role, &merged_config).unwrap();
139+
140+
assert_eq!(
141+
non_heap_jvm_args,
142+
"-Djava.security.properties=/stackable/config/security.properties \
143+
-javaagent:/stackable/jmx/jmx_prometheus_javaagent.jar=9084:/stackable/jmx/jmx_hive_config.yaml \
144+
-Djavax.net.ssl.trustStore=/stackable/truststore.p12 \
145+
-Djavax.net.ssl.trustStorePassword=changeit \
146+
-Djavax.net.ssl.trustStoreType=pkcs12"
147+
);
148+
assert_eq!(heap_jvm_args, "-Xmx409m -Xms409m");
149+
}
150+
151+
#[test]
152+
fn test_construct_jvm_argument_overrides() {
153+
let input = r#"
154+
apiVersion: hive.stackable.tech/v1alpha1
155+
kind: HiveCluster
156+
metadata:
157+
name: simple-hive
158+
spec:
159+
image:
160+
productVersion: 4.0.0
161+
clusterConfig:
162+
database:
163+
connString: jdbc:derby:;databaseName=/tmp/hive;create=true
164+
dbType: derby
165+
credentialsSecret: mySecret
166+
metastore:
167+
config:
168+
resources:
169+
memory:
170+
limit: 42Gi
171+
jvmArgumentOverrides:
172+
add:
173+
- -Dhttps.proxyHost=proxy.my.corp
174+
- -Dhttps.proxyPort=8080
175+
- -Djava.net.preferIPv4Stack=true
176+
roleGroups:
177+
default:
178+
replicas: 1
179+
jvmArgumentOverrides:
180+
# We need more memory!
181+
removeRegex:
182+
- -Xmx.*
183+
- -Dhttps.proxyPort=.*
184+
add:
185+
- -Xmx40000m
186+
- -Dhttps.proxyPort=1234
187+
"#;
188+
let (hive, merged_config, role, role_group) = construct_boilerplate(input);
189+
let non_heap_jvm_args =
190+
construct_non_heap_jvm_args(&hive, &merged_config, &role, &role_group).unwrap();
191+
let heap_jvm_args =
192+
construct_heap_jvm_args(&hive, &merged_config, &role, &role_group).unwrap();
193+
194+
assert_eq!(
195+
non_heap_jvm_args,
196+
"-Djava.security.properties=/stackable/config/security.properties \
197+
-javaagent:/stackable/jmx/jmx_prometheus_javaagent.jar=9084:/stackable/jmx/jmx_hive_config.yaml \
198+
-Djavax.net.ssl.trustStore=/stackable/truststore.p12 \
199+
-Djavax.net.ssl.trustStorePassword=changeit \
200+
-Djavax.net.ssl.trustStoreType=pkcs12 \
201+
-Dhttps.proxyHost=proxy.my.corp \
202+
-Djava.net.preferIPv4Stack=true \
203+
-Dhttps.proxyPort=1234"
204+
);
205+
assert_eq!(heap_jvm_args, "-Xms34406m -Xmx40000m");
206+
}
207+
208+
fn construct_boilerplate(
209+
hive_cluster: &str,
210+
) -> (
211+
HiveCluster,
212+
MetaStoreConfig,
213+
Role<MetaStoreConfigFragment, GenericRoleConfig, JavaCommonConfig>,
214+
String,
215+
) {
216+
let hive: HiveCluster = serde_yaml::from_str(hive_cluster).expect("illegal test input");
217+
218+
let hive_role = HiveRole::MetaStore;
219+
let rolegroup_ref = hive.metastore_rolegroup_ref("default");
220+
let merged_config = hive.merged_config(&hive_role, &rolegroup_ref).unwrap();
221+
let role = hive.spec.metastore.clone().unwrap();
222+
223+
(hive, merged_config, role, "default".to_owned())
224+
}
225+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod jvm;

0 commit comments

Comments
 (0)