Skip to content

Added new test case for update image scenario#2285

Merged
openshift-merge-bot[bot] merged 1 commit into
openshift:masterfrom
gangwgr:new-case1
Jun 10, 2026
Merged

Added new test case for update image scenario#2285
openshift-merge-bot[bot] merged 1 commit into
openshift:masterfrom
gangwgr:new-case1

Conversation

@gangwgr

@gangwgr gangwgr commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Added new test case for update image scenario

Summary by CodeRabbit

  • Tests
    • Added an end-to-end scenario that verifies an in-place KMS configuration update does not create a new encryption key and validates propagation of the change.
    • Added a test helper that waits for at least one matching API server pod and ensures all matching pods satisfy a caller-defined container condition for more reliable rollout verification.

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a pod polling helper that waits until all listed pods satisfy a predicate, and a KMS in-place update scenario + test that applies initial/updated KMS providers, asserts no new encryption key is created, and invokes a propagation verification callback.

Changes

KMS In-Place Update and Helpers

Layer / File(s) Summary
Pod polling helper
test/library/encryption/helpers.go
Adds WaitForPodContainerCondition(ctx, t, kubeClient, namespace, labelSelector, keyName, conditionDesc, match) which polls pods by label selector until at least one pod exists and every listed pod satisfies match(pod, keyName); logs progress and fails on timeout.
KMS in-place update scenario and test
test/library/encryption/scenarios.go
Adds KMSInPlaceUpdateScenario (embedding BasicScenario, with Provider, UpdatedProvider, and WaitForPropagation) and TestKMSInPlaceUpdate which validates providers are KMS-based, applies initial provider, records current encryption key metadata, applies updated provider, asserts no new encryption key is created, and invokes WaitForPropagation.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels

lgtm

Suggested reviewers

  • dgrisonnet
🚥 Pre-merge checks | ✅ 13 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title references an 'update image scenario' but the changes actually implement a KMS in-place update test scenario and encryption helper function. Revise the title to accurately reflect the main changes, such as: 'Add KMS in-place update test scenario and encryption helper'
Test Structure And Quality ⚠️ Warning TestKMSInPlaceUpdate has require.NoError calls without meaningful error messages on lines 393 and 402, violating the assertion message requirement. Add descriptive failure messages to require.NoError calls, e.g., 'require.NoError(t, err, "failed to get encryption key metadata")'.
✅ Passed checks (13 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed New test code uses static step names without dynamic information like pod names, timestamps, UUIDs, or node names. Helper functions are not Ginkgo tests.
Microshift Test Compatibility ✅ Passed No new Ginkgo e2e tests (It/Describe/Context patterns) are added. The PR adds library helper functions and structs for encryption test scenarios, not standalone Ginkgo tests.
Single Node Openshift (Sno) Test Compatibility ✅ Passed These are library test helpers (not Ginkgo tests), with no multi-node assumptions. Pod polling works on SNO with single or multiple pods on one node.
Topology-Aware Scheduling Compatibility ✅ Passed PR only adds test helper functions and test scenarios in test/library/encryption/. No deployment manifests, operator code, or scheduling constraints are introduced.
Ote Binary Stdout Contract ✅ Passed New test helpers contain no process-level stdout writes; all logging uses t.Logf() within test context, complying with OTE Binary Stdout Contract.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed Adds test helper functions without IPv4 assumptions or external connectivity. Check applies only to Ginkgo e2e tests marked with It/Describe/Context, not library helpers.
No-Weak-Crypto ✅ Passed No weak crypto, custom implementations, or non-constant-time secret comparisons found. PR adds test helpers for KMS encryption with standard library functions only.
Container-Privileges ✅ Passed PR adds test helper functions for encryption testing; no privileged container settings, hostPID/hostNetwork/hostIPC, SYS_ADMIN capabilities, or allowPrivilegeEscalation configurations found.
No-Sensitive-Data-In-Logs ✅ Passed All logging in new code logs only non-sensitive metadata: test step names, Kubernetes names, label selectors, timeouts, and errors—no passwords, tokens, API keys, PII, or customer data.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@openshift-ci openshift-ci Bot requested review from ardaguclu and dgrisonnet June 9, 2026 12:07

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/library/encryption/scenarios.go`:
- Around line 419-426: The kmsPluginImage helper dereferences encryption.KMS and
encryption.KMS.Vault without nil checks; add defensive guards at the top of
kmsPluginImage(encryption configv1.APIServerEncryption) to verify encryption.KMS
!= nil and encryption.KMS.Vault != nil before accessing Type or KMSPluginImage,
and return a clear error (e.g., "missing KMS configuration" or "missing Vault
configuration") when those are nil; keep the existing switch on
configv1.VaultKMSProvider and only return the Vault.KMSPluginImage after the nil
checks succeed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: a46b0da8-686d-490c-bc94-4ad56a02d520

📥 Commits

Reviewing files that changed from the base of the PR and between 5637f8b and eeb5178.

📒 Files selected for processing (1)
  • test/library/encryption/scenarios.go

Comment thread test/library/encryption/scenarios.go Outdated
Comment on lines +419 to +426
func kmsPluginImage(encryption configv1.APIServerEncryption) (string, error) {
switch encryption.KMS.Type {
case configv1.VaultKMSProvider:
return encryption.KMS.Vault.KMSPluginImage, nil
default:
return "", fmt.Errorf("unsupported KMS provider type %q", encryption.KMS.Type)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add nil pointer guards to prevent runtime panics.

The function accesses encryption.KMS.Type (line 420) and encryption.KMS.Vault.KMSPluginImage (line 422) without checking whether encryption.KMS or encryption.KMS.Vault are nil. While current callers validate the encryption type before calling this helper, the function should be defensive against nil pointer dereferences to prevent runtime panics if called in other contexts.

🛡️ Proposed fix to add nil guards
 func kmsPluginImage(encryption configv1.APIServerEncryption) (string, error) {
+	if encryption.KMS == nil {
+		return "", fmt.Errorf("KMS configuration is nil")
+	}
 	switch encryption.KMS.Type {
 	case configv1.VaultKMSProvider:
+		if encryption.KMS.Vault == nil {
+			return "", fmt.Errorf("Vault KMS configuration is nil")
+		}
 		return encryption.KMS.Vault.KMSPluginImage, nil
 	default:
 		return "", fmt.Errorf("unsupported KMS provider type %q", encryption.KMS.Type)
 	}
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func kmsPluginImage(encryption configv1.APIServerEncryption) (string, error) {
switch encryption.KMS.Type {
case configv1.VaultKMSProvider:
return encryption.KMS.Vault.KMSPluginImage, nil
default:
return "", fmt.Errorf("unsupported KMS provider type %q", encryption.KMS.Type)
}
}
func kmsPluginImage(encryption configv1.APIServerEncryption) (string, error) {
if encryption.KMS == nil {
return "", fmt.Errorf("KMS configuration is nil")
}
switch encryption.KMS.Type {
case configv1.VaultKMSProvider:
if encryption.KMS.Vault == nil {
return "", fmt.Errorf("Vault KMS configuration is nil")
}
return encryption.KMS.Vault.KMSPluginImage, nil
default:
return "", fmt.Errorf("unsupported KMS provider type %q", encryption.KMS.Type)
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/library/encryption/scenarios.go` around lines 419 - 426, The
kmsPluginImage helper dereferences encryption.KMS and encryption.KMS.Vault
without nil checks; add defensive guards at the top of kmsPluginImage(encryption
configv1.APIServerEncryption) to verify encryption.KMS != nil and
encryption.KMS.Vault != nil before accessing Type or KMSPluginImage, and return
a clear error (e.g., "missing KMS configuration" or "missing Vault
configuration") when those are nil; keep the existing switch on
configv1.VaultKMSProvider and only return the Vault.KMSPluginImage after the nil
checks succeed.

Comment thread test/library/encryption/scenarios.go Outdated
require.NoError(t, err)
require.NotEqual(t, initialImage, updatedImage, "UpdatedProvider kmsPluginImage must differ from Provider")

var prevKeyMeta EncryptionKeyMeta

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need this. Maybe it is better to call GetLastKeyMeta every time.

Comment thread test/library/encryption/scenarios.go Outdated
ApplyEncryption(ctx, t, scenario.UpdatedProvider.APIServerEncryption)
}},
{name: "WaitForNoNewEncryptionKey", testFunc: func(t testing.TB) {
WaitForNoNewEncryptionKey(t, clientSet.Kube, prevKeyMeta,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling WaitForNoNewEncryptionKey definitely makes sense. But I wonder how we will ensure that the kms plugin container uses the new image.

@gangwgr gangwgr force-pushed the new-case1 branch 3 times, most recently from b6f51ab to 0a27404 Compare June 9, 2026 12:40
@gangwgr

gangwgr commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

/test unit

Comment thread test/library/encryption/scenarios.go Outdated
// rolls out a new sidecar image without creating a new encryption key.
// The caller supplies Provider (initial valid config) and UpdatedProvider (same config
// with only kmsPluginImage changed).
type KMSPluginImageUpdateScenario struct {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we did for invalidconfig scenario, I think it is better to rename this to more generic like KMSInPlaceUpdateScenario.

Comment thread test/library/encryption/scenarios.go Outdated
// WaitForUpdatedImage is called after the image update to verify the new image
// is running (e.g. by polling API server pod init containers). Caller-provided,
// same pattern as WaitForStuck in KMSInvalidEncryptionRecoveryScenario.
WaitForUpdatedImage func(ctx context.Context, t testing.TB)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order to keep it generic, we can rename it to WaitForPropagation.

Comment thread test/library/encryption/scenarios.go Outdated
scenario.AssertFunc(t, clientSet, scenario.Provider.Type,
scenario.Namespace, scenario.LabelSelector)
}},
{name: "UpdateKMSPluginImage", testFunc: func(t testing.TB) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UpdateInPlaceField

Comment thread test/library/encryption/scenarios.go Outdated
scenario.Namespace, scenario.LabelSelector)
}},
{name: "WaitForUpdatedImage", testFunc: func(t testing.TB) {
scenario.WaitForUpdatedImage(ctx, t)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WaitForPropagation and callers will use custom wait command as we did for invalidconfigrecovery.

Comment thread test/library/encryption/helpers.go Outdated
// WaitForPodInitContainerImage polls pods until each has a running init container
// using the expected image. Init containers are scanned the same way as in
// WaitForPodImagePullBackOff.
func WaitForPodInitContainerImage(ctx context.Context, t testing.TB, kubeClient kubernetes.Interface, namespace, labelSelector, expectedImage string) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about updating this function to be generic;

 // WaitForPodContainerCondition polls pods until every pod has at least one
  // container status (init or regular, depending on the predicate) that satisfies
  // the given condition.
  func WaitForPodContainerCondition(
      ctx context.Context,
      t testing.TB,
      kubeClient kubernetes.Interface,
      namespace, labelSelector, conditionDesc string,
      match func(pod corev1.Pod) bool,
  ) {
      t.Helper()
      t.Logf("Waiting up to %s for pods in %s (selector=%s) to satisfy: %s",
          waitPollTimeout, namespace, labelSelector, conditionDesc)
      err := wait.PollUntilContextTimeout(ctx, waitPollInterval, waitPollTimeout, true,
          func(ctx context.Context) (bool, error) {
              pods, err := kubeClient.CoreV1().Pods(namespace).List(ctx,
                  metav1.ListOptions{LabelSelector: labelSelector})
              if err != nil {
                  t.Logf("Error listing pods: %v", err)
                  return false, nil
              }
              if len(pods.Items) == 0 {
                  t.Logf("No pods found yet in %s", namespace)
                  return false, nil
              }
              for _, pod := range pods.Items { 
                  if !match(pod) {
                      t.Logf("Pod %s does not yet satisfy condition: %s", pod.Name, conditionDesc)
                      return false, nil
                  }
              }
              return true, nil
          })
      require.NoError(t, err, "timed out waiting for pods in %s to satisfy: %s",
          namespace, conditionDesc)
  }

Callers will use it like this;

 WaitForPropagation: func(ctx context.Context, t testing.TB) {
      WaitForPodContainerCondition(ctx, t, kubeClient, namespace, labelSelector,
          fmt.Sprintf("running init container with image %q", expectedImage),
          func(pod corev1.Pod) bool {
              if pod.Status.Phase != corev1.PodRunning {
                  return false
              }
              for _, cs := range pod.Status.InitContainerStatuses {
                  if cs.State.Running != nil && cs.Image == expectedImage {
                      return true
                  }
              }
              return false
          },
      )
  },

@ardaguclu

Copy link
Copy Markdown
Member

Thank you
/lgtm
/approve
/hold
Can you please run this PR with #2241 on kas-o to see it passes?. If everything works, you can unhold this PR.

@openshift-ci openshift-ci Bot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Jun 10, 2026
@openshift-ci openshift-ci Bot added lgtm Indicates that a PR is ready to be merged. approved Indicates a PR has been approved by an approver from all required OWNERS files. labels Jun 10, 2026
Comment thread test/library/encryption/scenarios.go Outdated
Comment on lines +355 to +402
}

// KMSInPlaceUpdateScenario tests that updating an in-place KMS config field
// (e.g. kmsPluginImage) takes effect without creating a new encryption key.
// The caller supplies Provider (initial valid config) and UpdatedProvider (same config
// with one in-place field changed).
type KMSInPlaceUpdateScenario struct {
BasicScenario
Provider EncryptionProvider
UpdatedProvider EncryptionProvider
// WaitForPropagation is called after the in-place update to verify the change
// took effect. Caller-provided, same pattern as WaitForStuck in
// KMSInvalidEncryptionRecoveryScenario.
WaitForPropagation func(ctx context.Context, t testing.TB)
}

// TestKMSInPlaceUpdate validates in-place KMS config field updates:
// 1. Apply valid provider and verify migration
// 2. Update in-place field and verify no new encryption key is created
// 3. WaitForPropagation — caller verifies the change took effect
func TestKMSInPlaceUpdate(ctx context.Context, t testing.TB, scenario KMSInPlaceUpdateScenario) {
e := NewE(t, PrintEventsOnFailure(scenario.OperatorNamespace))
clientSet := GetClients(e)

require.NotNil(t, scenario.Provider.Setup, "Provider.Setup must not be nil")
require.NotNil(t, scenario.UpdatedProvider.Setup, "UpdatedProvider.Setup must not be nil")
require.NotNil(t, scenario.WaitForPropagation, "WaitForPropagation must not be nil")
require.Equal(t, configv1.EncryptionTypeKMS, scenario.Provider.Type, "Provider must use KMS encryption type")
require.Equal(t, configv1.EncryptionTypeKMS, scenario.UpdatedProvider.Type, "UpdatedProvider must use KMS encryption type")

steps := []testStep{
{name: "ApplyValidProviderAndVerifyMigration", testFunc: func(t testing.TB) {
SetAndWaitForEncryptionType(ctx, t, scenario.Provider, scenario.TargetGRs,
scenario.Namespace, scenario.LabelSelector)
scenario.AssertFunc(t, clientSet, scenario.Provider.Type,
scenario.Namespace, scenario.LabelSelector)
}},
{name: "UpdateInPlaceField", testFunc: func(t testing.TB) {
keyMeta, err := GetLastKeyMeta(t, clientSet.Kube,
scenario.Namespace, scenario.LabelSelector)
require.NoError(t, err)
scenario.UpdatedProvider.Setup(ctx, t)
ApplyEncryption(ctx, t, scenario.UpdatedProvider.APIServerEncryption)
WaitForNoNewEncryptionKey(t, clientSet.Kube, keyMeta,
scenario.Namespace, scenario.LabelSelector)
}},
{name: "WaitForPropagation", testFunc: func(t testing.TB) {
scenario.WaitForPropagation(ctx, t)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should get last key as in line: 393 and pass it to waitforpropagation. So that if we find a matching container, we can compare container name with our key.

t.Logf("No pods found yet in %s", namespace)
return false, nil
}
for _, pod := range pods.Items {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for _, pod := range pods.Items {
for _, pod := range pods.Items {
if match(pod, keyName) {
return true, nil
}
}
t.Logf("Pod %s does not yet satisfy condition: %s", pod.Name, conditionDesc)
return false, nil

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we need to continue iteration over the pods until we see match. So maybe we should use this ^^

@openshift-ci openshift-ci Bot removed the lgtm Indicates that a PR is ready to be merged. label Jun 10, 2026
@ardaguclu

Copy link
Copy Markdown
Member

/lgtm
/hold cancel

@openshift-ci openshift-ci Bot added lgtm Indicates that a PR is ready to be merged. and removed do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. labels Jun 10, 2026
Comment thread test/library/encryption/helpers.go Outdated
// WaitForPodContainerCondition polls pods until every pod satisfies the given condition.
// keyName is the current encryption key secret name, passed to match so callers can
// correlate pod container names with the active key (e.g. vault-kms-plugin-42).
func WaitForPodContainerCondition(ctx context.Context, t testing.TB, kubeClient kubernetes.Interface, namespace, labelSelector, keyName, conditionDesc string, match func(pod corev1.Pod, keyName string) bool) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need conditionDesc?

@ardaguclu

Copy link
Copy Markdown
Member

/lgtm cancel

@openshift-ci openshift-ci Bot removed lgtm Indicates that a PR is ready to be merged. approved Indicates a PR has been approved by an approver from all required OWNERS files. labels Jun 10, 2026
@gangwgr

gangwgr commented Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

@ardaguclu holding pr to test with your pr, will unhold later
/hold

@openshift-ci openshift-ci Bot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Jun 10, 2026
@gangwgr

gangwgr commented Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

/unhold

@openshift-ci openshift-ci Bot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Jun 10, 2026
Comment thread test/library/encryption/helpers.go Outdated
if match(pod, keyName) {
return true, nil
}
t.Logf("Pod %s does not yet satisfy condition", pod.Name)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pod may not be the one we are looking for. Can we move this log just above the return false, nil

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@ardaguclu

Copy link
Copy Markdown
Member

/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label Jun 10, 2026
@openshift-ci

openshift-ci Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: ardaguclu, gangwgr

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jun 10, 2026
@openshift-ci

openshift-ci Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

@gangwgr: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@openshift-merge-bot openshift-merge-bot Bot merged commit 09fa75d into openshift:master Jun 10, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. lgtm Indicates that a PR is ready to be merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants