Skip to content

Commit 45529e5

Browse files
committed
Add pull policy (#75)
# Description Added two optional fields to the custom resource to govern pull policy and secrets to be used when accessing images. Closes #69.
1 parent 5bdf867 commit 45529e5

20 files changed

+220
-27
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
44

55
## [Unreleased]
66

7+
### Added
8+
9+
- Added new fields to govern image pull policy ([#75])
10+
11+
[#75]: https://github.com/stackabletech/spark-k8s-operator/pull/75
12+
713
### Changed
814

915
- Updated examples ([#71])

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

deploy/crd/sparkapplication.crd.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,23 @@ spec:
356356
sparkImage:
357357
nullable: true
358358
type: string
359+
sparkImagePullPolicy:
360+
enum:
361+
- Always
362+
- IfNotPresent
363+
- Never
364+
nullable: true
365+
type: string
366+
sparkImagePullSecrets:
367+
items:
368+
description: LocalObjectReference contains enough information to let you locate the referenced object inside the same namespace.
369+
properties:
370+
name:
371+
description: "Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names"
372+
type: string
373+
type: object
374+
nullable: true
375+
type: array
359376
stopped:
360377
nullable: true
361378
type: boolean

deploy/helm/spark-k8s-operator/crds/crds.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,23 @@ spec:
358358
sparkImage:
359359
nullable: true
360360
type: string
361+
sparkImagePullPolicy:
362+
enum:
363+
- Always
364+
- IfNotPresent
365+
- Never
366+
nullable: true
367+
type: string
368+
sparkImagePullSecrets:
369+
items:
370+
description: LocalObjectReference contains enough information to let you locate the referenced object inside the same namespace.
371+
properties:
372+
name:
373+
description: "Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names"
374+
type: string
375+
type: object
376+
nullable: true
377+
type: array
361378
stopped:
362379
nullable: true
363380
type: boolean

deploy/manifests/crds.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,23 @@ spec:
359359
sparkImage:
360360
nullable: true
361361
type: string
362+
sparkImagePullPolicy:
363+
enum:
364+
- Always
365+
- IfNotPresent
366+
- Never
367+
nullable: true
368+
type: string
369+
sparkImagePullSecrets:
370+
items:
371+
description: LocalObjectReference contains enough information to let you locate the referenced object inside the same namespace.
372+
properties:
373+
name:
374+
description: "Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names"
375+
type: string
376+
type: object
377+
nullable: true
378+
type: array
362379
stopped:
363380
nullable: true
364381
type: boolean

docs/modules/ROOT/pages/usage.adoc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,12 @@ Below are listed the CRD fields that can be defined by the user:
199199
|`spec.sparkImage`
200200
| Spark image which will be deployed to driver and executor pods, which must contain spark environment needed by the job e.g. `docker.stackable.tech/stackable/spark-k8s:3.2.1-hadoop3.2-stackable0.4.0`
201201

202+
|`spec.sparkImagePullPolicy`
203+
| Optional Enum (one of `Always`, `IfNotPresent` or `Never`) that determines the pull policy of the spark job image
204+
205+
|`spec.sparkImagePullSecrets`
206+
| An optional list of references to secrets in the same namespace to use for pulling any of the images used by a `SparkApplication` resource. Each reference has a single property (`name`) that must contain a reference to a valid secret
207+
202208
|`spec.mainApplicationFile`
203209
|The actual application file that will be called by `spark-submit`
204210

examples/ny-tlc-report-external-dependencies.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ metadata:
77
spec:
88
version: "1.0"
99
sparkImage: docker.stackable.tech/stackable/pyspark-k8s:3.2.1-hadoop3.2-python39-stackable0.1.0
10+
# Always | IfNotPresent | Never
11+
sparkImagePullPolicy: IfNotPresent
1012
mode: cluster
1113
mainApplicationFile: s3a://my-bucket/ny-tlc-report.py
1214
args:

examples/ny-tlc-report-image.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ spec:
99
# everything under /jobs will be copied to /stackable/spark/jobs
1010
image: docker.stackable.tech/stackable/ny-tlc-report:0.1.0
1111
sparkImage: docker.stackable.tech/stackable/pyspark-k8s:3.2.1-hadoop3.2-python39-stackable0.1.0
12+
sparkImagePullPolicy: Always
1213
mode: cluster
1314
mainApplicationFile: local:///stackable/spark/jobs/ny_tlc_report.py
1415
args:

rust/crd/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ serde = { version = "1.0", features = ["derive"] }
1515
serde_json = "1.0"
1616
serde_yaml = "0.8"
1717
snafu = "0.7"
18+
strum = { version = "0.24", features = ["derive"] }

rust/crd/src/lib.rs

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ pub mod constants;
55
use constants::*;
66
use stackable_operator::commons::s3::{InlinedS3BucketSpec, S3BucketDef};
77
use stackable_operator::k8s_openapi::api::core::v1::{
8-
EnvVar, EnvVarSource, SecretKeySelector, Volume, VolumeMount,
8+
EnvVar, EnvVarSource, LocalObjectReference, SecretKeySelector, Volume, VolumeMount,
99
};
1010

1111
use std::collections::{BTreeMap, HashMap};
@@ -20,6 +20,7 @@ use stackable_operator::{
2020
role_utils::CommonConfiguration,
2121
schemars::{self, JsonSchema},
2222
};
23+
use strum::{Display, EnumString};
2324

2425
#[derive(Snafu, Debug)]
2526
pub enum Error {
@@ -68,6 +69,10 @@ pub struct SparkApplicationSpec {
6869
#[serde(default, skip_serializing_if = "Option::is_none")]
6970
pub spark_image: Option<String>,
7071
#[serde(default, skip_serializing_if = "Option::is_none")]
72+
pub spark_image_pull_policy: Option<ImagePullPolicy>,
73+
#[serde(default, skip_serializing_if = "Option::is_none")]
74+
pub spark_image_pull_secrets: Option<Vec<LocalObjectReference>>,
75+
#[serde(default, skip_serializing_if = "Option::is_none")]
7176
pub driver: Option<DriverConfig>,
7277
#[serde(default, skip_serializing_if = "Option::is_none")]
7378
pub executor: Option<ExecutorConfig>,
@@ -89,6 +94,13 @@ pub struct SparkApplicationSpec {
8994
pub env: Option<Vec<EnvVar>>,
9095
}
9196

97+
#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize, Display, EnumString)]
98+
pub enum ImagePullPolicy {
99+
Always,
100+
IfNotPresent,
101+
Never,
102+
}
103+
92104
#[derive(Clone, Debug, Default, Deserialize, JsonSchema, PartialEq, Serialize)]
93105
#[serde(rename_all = "camelCase")]
94106
pub struct JobDependencies {
@@ -123,6 +135,14 @@ impl SparkApplication {
123135
self.spec.image.as_deref()
124136
}
125137

138+
pub fn spark_image_pull_policy(&self) -> Option<ImagePullPolicy> {
139+
self.spec.spark_image_pull_policy.clone()
140+
}
141+
142+
pub fn spark_image_pull_secrets(&self) -> Option<Vec<LocalObjectReference>> {
143+
self.spec.spark_image_pull_secrets.clone()
144+
}
145+
126146
pub fn version(&self) -> Option<&str> {
127147
self.spec.version.as_deref()
128148
}
@@ -380,7 +400,10 @@ pub struct CommandStatus {
380400

381401
#[cfg(test)]
382402
mod tests {
403+
use crate::ImagePullPolicy;
404+
use crate::LocalObjectReference;
383405
use crate::SparkApplication;
406+
use std::str::FromStr;
384407

385408
#[test]
386409
fn test_spark_examples_s3() {
@@ -542,4 +565,72 @@ spec:
542565
assert!(spark_application.spec.main_class.is_none());
543566
assert!(spark_application.spec.image.is_none());
544567
}
568+
569+
#[test]
570+
fn test_image_actions() {
571+
let spark_application = serde_yaml::from_str::<SparkApplication>(
572+
r#"
573+
---
574+
apiVersion: spark.stackable.tech/v1alpha1
575+
kind: SparkApplication
576+
metadata:
577+
name: spark-pi-local
578+
namespace: default
579+
spec:
580+
version: "1.0"
581+
sparkImage: docker.stackable.tech/stackable/spark-k8s:3.2.1-hadoop3.2-stackable0.4.0
582+
sparkImagePullPolicy: Always
583+
sparkImagePullSecrets:
584+
- name: myregistrykey
585+
mode: cluster
586+
mainClass: org.apache.spark.examples.SparkPi
587+
mainApplicationFile: local:///stackable/spark/examples/jars/spark-examples_2.12-3.2.1.jar
588+
sparkConf:
589+
spark.kubernetes.node.selector.node: "2"
590+
driver:
591+
cores: 1
592+
coreLimit: "1200m"
593+
memory: "512m"
594+
executor:
595+
cores: 1
596+
instances: 1
597+
memory: "512m"
598+
"#,
599+
)
600+
.unwrap();
601+
602+
assert_eq!(
603+
Some(vec![LocalObjectReference {
604+
name: Some("myregistrykey".to_string())
605+
}]),
606+
spark_application.spark_image_pull_secrets()
607+
);
608+
assert_eq!(
609+
Some(ImagePullPolicy::Always),
610+
spark_application.spark_image_pull_policy()
611+
);
612+
}
613+
614+
#[test]
615+
fn test_image_pull_policy_ser() {
616+
assert_eq!("Never", ImagePullPolicy::Never.to_string());
617+
assert_eq!("Always", ImagePullPolicy::Always.to_string());
618+
assert_eq!("IfNotPresent", ImagePullPolicy::IfNotPresent.to_string());
619+
}
620+
621+
#[test]
622+
fn test_image_pull_policy_de() {
623+
assert_eq!(
624+
ImagePullPolicy::Always,
625+
ImagePullPolicy::from_str("Always").unwrap()
626+
);
627+
assert_eq!(
628+
ImagePullPolicy::Never,
629+
ImagePullPolicy::from_str("Never").unwrap()
630+
);
631+
assert_eq!(
632+
ImagePullPolicy::IfNotPresent,
633+
ImagePullPolicy::from_str("IfNotPresent").unwrap()
634+
);
635+
}
545636
}

0 commit comments

Comments
 (0)