Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Let operators pick stackable version automatically #619

Merged
merged 12 commits into from
Aug 1, 2023
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.

## [Unreleased]

### Changed

- [BREAKING] ProductImageSelection now defaults `stackableVersion` to operator version ([#619]).
maltesander marked this conversation as resolved.
Show resolved Hide resolved
- Default `pullPolicy` to operator `Always`` ([#619]).

[#619]: https://github.com/stackabletech/operator-rs/pull/619

## [0.44.0] - 2023-07-13

### Added
Expand Down
73 changes: 45 additions & 28 deletions src/commons/product_image_selection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,10 @@ pub struct ProductImageCustom {
pub struct ProductImageStackableVersion {
/// Version of the product, e.g. `1.4.1`.
product_version: String,
/// Stackable version of the product, e.g. 2.1.0
stackable_version: String,
/// Stackable version of the product, e.g. `23.4`, `23.4.1` or `0.0.0-dev`.
/// If not specified, the operator will use its own version, e.g. `23.4.1`.
/// When using a nightly operator it will use the nightly `0.0.0-dev` image.
stackable_version: Option<String>,
/// Name of the docker repo, e.g. `docker.stackable.tech/stackable`
repo: Option<String>,
}
Expand All @@ -70,50 +72,58 @@ pub struct ResolvedProductImage {
#[derive(Clone, Debug, Default, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
#[serde(rename = "PascalCase")]
#[derive(AsRefStr)]
/// We default to `Always`, as we use floating tags for our release lines.
/// This means the tag 23.4 starts of pointing to the same image 23.4.0 does, but switches to 23.4.1 after the releases of 23.4.1.
pub enum PullPolicy {
#[default]
IfNotPresent,
#[default]
Always,
Never,
}

impl ProductImage {
pub fn resolve(&self, image_base_name: &str) -> ResolvedProductImage {
/// `image_base_name` should be base of the image name in the container image registry, e.g. `trino`.
/// `operator_version` needs to be the full operator version and a valid semver string.
/// Accepted values are `23.7.0` or `0.0.0-dev`. Versions with a trailing `-pr` or something else are not supported.
pub fn resolve(&self, image_base_name: &str, operator_version: &str) -> ResolvedProductImage {
let image_pull_policy = self.pull_policy.as_ref().to_string();
let pull_secrets = self.pull_secrets.clone();

match &self.image_selection {
ProductImageSelection::Custom(custom) => {
let custom_image_tag = custom
ProductImageSelection::Custom(image_selection) => {
let image_tag = image_selection
.custom
.split_once(':')
.map_or("latest", |splits| splits.1);
let app_version_label = format!("{}-{}", custom.product_version, custom_image_tag);
let app_version_label =
format!("{}-{}", image_selection.product_version, image_tag);
ResolvedProductImage {
product_version: custom.product_version.to_string(),
product_version: image_selection.product_version.to_string(),
app_version_label,
image: custom.custom.to_string(),
image: image_selection.custom.clone(),
image_pull_policy,
pull_secrets,
}
}
ProductImageSelection::StackableVersion(stackable_version) => {
let repo = stackable_version
ProductImageSelection::StackableVersion(image_selection) => {
let repo = image_selection
.repo
.as_deref()
.unwrap_or(STACKABLE_DOCKER_REPO);
let stackable_version = image_selection
.stackable_version
.as_deref()
.unwrap_or(operator_version);
let image = format!(
"{repo}/{image_base_name}:{product_version}-stackable{stackable_version}",
product_version = stackable_version.product_version,
stackable_version = stackable_version.stackable_version,
product_version = image_selection.product_version,
);
let app_version_label = format!(
"{product_version}-stackable{stackable_version}",
product_version = stackable_version.product_version,
stackable_version = stackable_version.stackable_version,
product_version = image_selection.product_version,
);
ResolvedProductImage {
product_version: stackable_version.product_version.to_string(),
product_version: image_selection.product_version.to_string(),
app_version_label,
image,
image_pull_policy,
Expand All @@ -131,6 +141,19 @@ mod tests {
use rstest::rstest;

#[rstest]
#[case::stackable_version_without_stackable_version(
"superset",
r#"
productVersion: 1.4.1
"#,
ResolvedProductImage {
image: "docker.stackable.tech/stackable/superset:1.4.1-stackable23.7.42".to_string(),
app_version_label: "1.4.1-stackable23.7.42".to_string(),
product_version: "1.4.1".to_string(),
image_pull_policy: "Always".to_string(),
pull_secrets: None,
}
)]
#[case::stackable_version_without_repo(
"superset",
r#"
Expand All @@ -141,7 +164,7 @@ mod tests {
image: "docker.stackable.tech/stackable/superset:1.4.1-stackable2.1.0".to_string(),
app_version_label: "1.4.1-stackable2.1.0".to_string(),
product_version: "1.4.1".to_string(),
image_pull_policy: "IfNotPresent".to_string(),
image_pull_policy: "Always".to_string(),
pull_secrets: None,
}
)]
Expand All @@ -156,7 +179,7 @@ mod tests {
image: "my.corp/myteam/stackable/trino:1.4.1-stackable2.1.0".to_string(),
app_version_label: "1.4.1-stackable2.1.0".to_string(),
product_version: "1.4.1".to_string(),
image_pull_policy: "IfNotPresent".to_string(),
image_pull_policy: "Always".to_string(),
pull_secrets: None,
}
)]
Expand All @@ -170,7 +193,7 @@ mod tests {
image: "my.corp/myteam/stackable/superset".to_string(),
app_version_label: "1.4.1-latest".to_string(),
product_version: "1.4.1".to_string(),
image_pull_policy: "IfNotPresent".to_string(),
image_pull_policy: "Always".to_string(),
pull_secrets: None,
}
)]
Expand All @@ -184,7 +207,7 @@ mod tests {
image: "my.corp/myteam/stackable/superset:latest-and-greatest".to_string(),
app_version_label: "1.4.1-latest-and-greatest".to_string(),
product_version: "1.4.1".to_string(),
image_pull_policy: "IfNotPresent".to_string(),
image_pull_policy: "Always".to_string(),
pull_secrets: None,
}
)]
Expand All @@ -199,7 +222,7 @@ mod tests {
image: "my.corp/myteam/stackable/superset:latest-and-greatest".to_string(),
app_version_label: "1.4.1-latest-and-greatest".to_string(),
product_version: "1.4.1".to_string(),
image_pull_policy: "IfNotPresent".to_string(),
image_pull_policy: "Always".to_string(),
pull_secrets: None,
}
)]
Expand Down Expand Up @@ -272,7 +295,7 @@ mod tests {
#[case] expected: ResolvedProductImage,
) {
let product_image: ProductImage = serde_yaml::from_str(&input).expect("Illegal test input");
let resolved_product_image = product_image.resolve(&image_base_name);
let resolved_product_image = product_image.resolve(&image_base_name, "23.7.42");

assert_eq!(resolved_product_image, expected);
}
Expand All @@ -284,12 +307,6 @@ mod tests {
"#,
"data did not match any variant of untagged enum ProductImageSelection at line 2 column 9"
)]
#[case::product_version(
r#"
productVersion: 1.4.1
"#,
"data did not match any variant of untagged enum ProductImageSelection at line 2 column 9"
)]
#[case::stackable_version(
r#"
stackableVersion: 2.1.0
Expand Down