Skip to content

Commit d1c1ac9

Browse files
authored
chore: Wrap SparkApplicationSpec in SparkApplicationTemplateSpec (#685)
1 parent 922f16c commit d1c1ac9

2 files changed

Lines changed: 14 additions & 117 deletions

File tree

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1209,8 +1209,8 @@ mod tests {
12091209

12101210
// Convert templates to SparkApplication and merge left-to-right:
12111211
// template-a has the lowest priority, the spark application has the highest.
1212-
let app_from_a = crate::crd::v1alpha1::SparkApplication::from(&template_a);
1213-
let app_from_b = crate::crd::v1alpha1::SparkApplication::from(&template_b);
1212+
let app_from_a = crate::crd::v1alpha1::SparkApplication::from(template_a);
1213+
let app_from_b = crate::crd::v1alpha1::SparkApplication::from(template_b);
12141214
// This how `merge_application_templates()` does it
12151215
let template_apps = [app_from_a, app_from_b, spark_app];
12161216
let merged = template_apps
@@ -1391,7 +1391,7 @@ mod tests {
13911391
"#})
13921392
.unwrap();
13931393

1394-
let app_from_template = crate::crd::v1alpha1::SparkApplication::from(&template);
1394+
let app_from_template = crate::crd::v1alpha1::SparkApplication::from(template);
13951395
let merged = deep_merge(&app_from_template, &spark_app);
13961396

13971397
let submit_affinity = merged.submit_config().unwrap().affinity;

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

Lines changed: 11 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,17 @@
11
//! This module provides the SparkApplicationTemplateSpec CRD definition.
22
3-
use std::{collections::HashMap, num::ParseIntError, str::ParseBoolError};
3+
use std::{num::ParseIntError, str::ParseBoolError};
44

55
use regex::Regex;
66
use serde::{Deserialize, Serialize};
77
use snafu::{ResultExt, Snafu};
88
use stackable_operator::{
9-
commons::product_image_selection::ProductImage,
10-
crd::s3,
11-
k8s_openapi::api::core::v1::{EnvVar, Volume},
129
kube::{Api, CustomResource, ResourceExt, api::ListParams},
1310
schemars::{self, JsonSchema},
14-
utils::crds::raw_object_list_schema,
1511
versioned::versioned,
1612
};
1713
use strum::{EnumDiscriminants, IntoStaticStr};
1814

19-
use super::{
20-
SparkApplicationDriverRoleType, SparkApplicationExecutorRoleType, SparkApplicationJobRoleType,
21-
history::LogFileDirectorySpec, job_dependencies::JobDependencies, roles::SparkMode,
22-
};
2315
use crate::crd::template_merger::deep_merge;
2416

2517
#[derive(Snafu, Debug, EnumDiscriminants)]
@@ -77,85 +69,11 @@ pub mod versioned {
7769
#[derive(Clone, CustomResource, Debug, Deserialize, JsonSchema, Serialize)]
7870
#[serde(rename_all = "camelCase")]
7971
pub struct SparkApplicationTemplateSpec {
80-
/// Mode: cluster or client. Currently only cluster is supported.
81-
pub mode: SparkMode,
82-
83-
/// The main class - i.e. entry point - for JVM artifacts.
84-
#[serde(default, skip_serializing_if = "Option::is_none")]
85-
pub main_class: Option<String>,
86-
87-
/// The actual application file that will be called by `spark-submit`.
88-
pub main_application_file: String,
89-
90-
/// User-supplied image containing spark-job dependencies that will be copied to the specified volume mount.
91-
/// See the [examples](DOCS_BASE_URL_PLACEHOLDER/spark-k8s/usage-guide/examples).
92-
#[serde(default, skip_serializing_if = "Option::is_none")]
93-
pub image: Option<String>,
94-
95-
// no doc - docs in ProductImage struct.
96-
pub spark_image: ProductImage,
97-
98-
/// Name of the Vector aggregator [discovery ConfigMap](DOCS_BASE_URL_PLACEHOLDER/concepts/service_discovery).
99-
/// It must contain the key `ADDRESS` with the address of the Vector aggregator.
100-
/// Follow the [logging tutorial](DOCS_BASE_URL_PLACEHOLDER/tutorials/logging-vector-aggregator)
101-
/// to learn how to configure log aggregation with Vector.
102-
#[serde(skip_serializing_if = "Option::is_none")]
103-
pub vector_aggregator_config_map_name: Option<String>,
104-
105-
/// The job builds a spark-submit command, complete with arguments and referenced dependencies
106-
/// such as templates, and passes it on to Spark.
107-
/// The reason this property uses its own type (SubmitConfigFragment) is because logging is not
108-
/// supported for spark-submit processes.
109-
//
110-
// IMPORTANT: Please note that the jvmArgumentOverrides have no effect here!
111-
// However, due to product-config things I wasn't able to remove them.
112-
#[serde(default, skip_serializing_if = "Option::is_none")]
113-
pub job: Option<SparkApplicationJobRoleType>,
114-
115-
/// The driver role specifies the configuration that, together with the driver pod template, is used by
116-
/// Spark to create driver pods.
117-
#[serde(default, skip_serializing_if = "Option::is_none")]
118-
pub driver: Option<SparkApplicationDriverRoleType>,
119-
120-
/// The executor role specifies the configuration that, together with the driver pod template, is used by
121-
/// Spark to create the executor pods.
122-
/// This is RoleGroup instead of plain CommonConfiguration because it needs to allow for the number of replicas.
123-
/// to be specified.
124-
#[serde(default, skip_serializing_if = "Option::is_none")]
125-
pub executor: Option<SparkApplicationExecutorRoleType>,
126-
127-
/// A map of key/value strings that will be passed directly to spark-submit.
128-
#[serde(default)]
129-
pub spark_conf: HashMap<String, String>,
130-
131-
/// Job dependencies: a list of python packages that will be installed via pip, a list of packages
132-
/// or repositories that is passed directly to spark-submit, or a list of excluded packages
133-
/// (also passed directly to spark-submit).
134-
#[serde(default)]
135-
pub deps: JobDependencies,
136-
137-
/// Configure an S3 connection that the SparkApplication has access to.
138-
/// Read more in the [Spark S3 usage guide](DOCS_BASE_URL_PLACEHOLDER/spark-k8s/usage-guide/s3).
139-
#[serde(default, skip_serializing_if = "Option::is_none")]
140-
pub s3connection: Option<s3::v1alpha1::InlineConnectionOrReference>,
141-
142-
/// Arguments passed directly to the job artifact.
143-
#[serde(default)]
144-
pub args: Vec<String>,
145-
146-
/// A list of volumes that can be made available to the job, driver or executors via their volume mounts.
147-
#[serde(default)]
148-
#[schemars(schema_with = "raw_object_list_schema")]
149-
pub volumes: Vec<Volume>,
150-
151-
/// A list of environment variables that will be set in the job pod and the driver and executor
152-
/// pod templates.
153-
#[serde(default)]
154-
pub env: Vec<EnvVar>,
155-
156-
/// The log file directory definition used by the Spark history server.
157-
#[serde(default, skip_serializing_if = "Option::is_none")]
158-
pub log_file_directory: Option<LogFileDirectorySpec>,
72+
/// The template body mirrors a [`SparkApplication`](super::super::v1alpha1::SparkApplication)
73+
/// spec exactly — it is merged into a `SparkApplication` at reconcile time, see
74+
/// [`merge_application_templates`].
75+
#[serde(flatten)]
76+
pub spec: crate::crd::v1alpha1::SparkApplicationSpec,
15977
}
16078
}
16179

@@ -170,33 +88,11 @@ impl From<&v1alpha1::SparkApplicationTemplate>
17088
}
17189
}
17290

173-
impl From<&v1alpha1::SparkApplicationTemplate> for super::v1alpha1::SparkApplication {
174-
fn from(template: &v1alpha1::SparkApplicationTemplate) -> super::v1alpha1::SparkApplication {
175-
let spec = super::v1alpha1::SparkApplicationSpec {
176-
mode: template.spec.mode.clone(),
177-
main_class: template.spec.main_class.clone(),
178-
main_application_file: template.spec.main_application_file.clone(),
179-
image: template.spec.image.clone(),
180-
spark_image: template.spec.spark_image.clone(),
181-
vector_aggregator_config_map_name: template
182-
.spec
183-
.vector_aggregator_config_map_name
184-
.clone(),
185-
job: template.spec.job.clone(),
186-
driver: template.spec.driver.clone(),
187-
executor: template.spec.executor.clone(),
188-
spark_conf: template.spec.spark_conf.clone(),
189-
deps: template.spec.deps.clone(),
190-
s3connection: template.spec.s3connection.clone(),
191-
args: template.spec.args.clone(),
192-
volumes: template.spec.volumes.clone(),
193-
env: template.spec.env.clone(),
194-
log_file_directory: template.spec.log_file_directory.clone(),
195-
};
196-
91+
impl From<v1alpha1::SparkApplicationTemplate> for super::v1alpha1::SparkApplication {
92+
fn from(template: v1alpha1::SparkApplicationTemplate) -> super::v1alpha1::SparkApplication {
19793
super::v1alpha1::SparkApplication {
198-
metadata: template.metadata.clone(),
199-
spec,
94+
metadata: template.metadata,
95+
spec: template.spec.spec,
20096
status: None,
20197
}
20298
}
@@ -379,6 +275,7 @@ pub(crate) async fn merge_application_templates(
379275
// which has the highest priority during merging.
380276
let mut template_apps: Vec<super::v1alpha1::SparkApplication> = templates
381277
.iter()
278+
.cloned()
382279
.map(super::v1alpha1::SparkApplication::from)
383280
.collect::<Vec<super::v1alpha1::SparkApplication>>();
384281
template_apps.push(spark_application.clone());

0 commit comments

Comments
 (0)