diff --git a/CHANGELOG.md b/CHANGELOG.md index 85345070..509d05db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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]). +- Default `pullPolicy` to operator `Always`` ([#619]). + +[#619]: https://github.com/stackabletech/operator-rs/pull/619 + ## [0.44.0] - 2023-07-13 ### Added diff --git a/src/commons/product_image_selection.rs b/src/commons/product_image_selection.rs index 7801f147..bc2a627d 100644 --- a/src/commons/product_image_selection.rs +++ b/src/commons/product_image_selection.rs @@ -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, /// Name of the docker repo, e.g. `docker.stackable.tech/stackable` repo: Option, } @@ -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, @@ -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#" @@ -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, } )] @@ -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, } )] @@ -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, } )] @@ -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, } )] @@ -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, } )] @@ -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); } @@ -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