Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion crates/stackable-operator/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ All notable changes to this project will be documented in this file.

### Added

- Add support for floating tags in product image selection ([#1226]).
- Add support for floating tags in product image selection ([#1226], [#1275]).
- Add missing `SecurityContextBuilder::build` associated function ([#1271]).

### Changed
Expand All @@ -19,6 +19,7 @@ All notable changes to this project will be documented in this file.

[#1226]: https://github.com/stackabletech/operator-rs/pull/1226
[#1271]: https://github.com/stackabletech/operator-rs/pull/1271
[#1275]: https://github.com/stackabletech/operator-rs/pull/1275

## [0.117.0] - 2026-09-03

Expand Down
52 changes: 30 additions & 22 deletions crates/stackable-operator/src/commons/product_image_selection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,8 @@ impl ProductImage {
) -> Result<ResolvedProductImage, Error> {
let Self {
image_selection,
pull_policy,
pull_secrets,
..
} = self;

// Keep track if a tag we consider floating is used. Currently, 0.0.0-dev, latest and YY.MM
Expand All @@ -234,9 +234,8 @@ impl ProductImage {

let app_version = format!("{product_version}-{image_tag_or_hash}");
let app_version_label_value = Self::prepare_app_version_label_value(&app_version)?;
let image_pull_policy = pull_policy
.unwrap_or_else(|| PullPolicy::from_is_floating_tag(is_floating_tag))
.to_string();

let image_pull_policy = self.pull_policy(is_floating_tag, &app_version);

Ok(ResolvedProductImage {
product_version: product_version.to_owned(),
Expand Down Expand Up @@ -291,29 +290,15 @@ impl ProductImage {
stackable_version.to_string()
};

let image_pull_policy = match pull_policy {
Some(pull_policy) => {
if is_floating_tag && *pull_policy != PullPolicy::Always {
tracing::warn!(
pull_policy.configured = %pull_policy,
stackable_version,
"product image pull policy is not \"Always\" but a floating tag is \
used. This can lead to unexpected behaviour and it is recommended \
to explicitly set the pull policy to \"Always\" or let the operator \
derive it automatically by removing the pullPolicy field."
);
}
pull_policy.to_string()
}
None => PullPolicy::from_is_floating_tag(is_floating_tag).to_string(),
};

// Trim leading ans trailing whitespace and also trim the start to ensure no double
// Trim leading and trailing whitespace and also trim the start to ensure no double
// slashes are produced below
let image_name = image_name.trim().trim_start_matches('/');

let app_version = format!("{product_version}-stackable{stackable_version}");
let app_version_label_value = Self::prepare_app_version_label_value(&app_version)?;

let image = format!("{image_repository}/{image_name}:{app_version}");
let image_pull_policy = self.pull_policy(is_floating_tag, &app_version);

Ok(ResolvedProductImage {
product_version: product_version.to_owned(),
Expand Down Expand Up @@ -356,6 +341,29 @@ impl ProductImage {
app_version: formatted_app_version,
})
}

/// Determine the image pull policy.
///
/// This function also prints out a warning if a floating tag is used but the [`PullPolicy`]
/// is explicitly set to something other than [`PullPolicy::Always`].
fn pull_policy(&self, is_floating_tag: bool, app_version: &str) -> String {
match self.pull_policy {
Some(pull_policy) => {
if is_floating_tag && pull_policy != PullPolicy::Always {
tracing::warn!(
pull_policy.configured = %pull_policy,
app_version,
"product image pull policy is not \"Always\" but a floating tag is \
used. This can lead to unexpected behaviour and it is recommended \
to explicitly set the pull policy to \"Always\" or let the operator \
derive it automatically by removing the pullPolicy field."
);
}
pull_policy.to_string()
}
None => PullPolicy::from_is_floating_tag(is_floating_tag).to_string(),
}
}
}

// We use Policy instead of Strategy to follow well-established patterns in the Kubernetes ecosystem.
Expand Down