Skip to content

OLS-3450: Add credentialHotReload flag to skip app-server restart on LLM secret rotation#1779

Open
lalan7 wants to merge 6 commits into
openshift:mainfrom
lalan7:feat/credential-hot-reload
Open

OLS-3450: Add credentialHotReload flag to skip app-server restart on LLM secret rotation#1779
lalan7 wants to merge 6 commits into
openshift:mainfrom
lalan7:feat/credential-hot-reload

Conversation

@lalan7

@lalan7 lalan7 commented Jul 2, 2026

Copy link
Copy Markdown

Summary

  • Adds opt-in credentialHotReload boolean to OLSSpec CRD (default: false)
  • When enabled, the operator's secret watcher skips rolling restart for LLM credential secrets — the service re-reads credentials from disk on each request (RFE-9380)
  • Preserves existing behavior for all clusters when disabled

Test plan

  • Unit tests: 3 new tests covering skip/no-skip/non-LLM paths (23/23 pass)
  • E2e test: rotate LLM secret with flag enabled, verify no restart via Consistently
  • go vet ./... clean
  • go build ./... clean
  • CRD regenerated via make manifests

Related

Summary by CodeRabbit

  • New Features
    • Added spec.ols.credentialHotReload to enable in-process hot-reload of LLM provider credential secrets without app-server restarts.
    • When enabled, the operator stops using the restart-triggering watcher annotation for the affected LLM token Secret.
  • Documentation
    • Added guidance for prerequisites, including required lightspeed-service behavior, and clarified expected handling for credential secret data vs reference changes.
  • Tests
    • Added e2e coverage to verify enabling/disabling hot-reload updates Secret annotations and app-server configuration as expected.

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jul 2, 2026
@openshift-ci-robot

openshift-ci-robot commented Jul 2, 2026

Copy link
Copy Markdown

@lalan7: This pull request references OLS-3450 which is a valid jira issue.

Details

In response to this:

Summary

  • Adds opt-in credentialHotReload boolean to OLSSpec CRD (default: false)
  • When enabled, the operator's secret watcher skips rolling restart for LLM credential secrets — the service re-reads credentials from disk on each request (RFE-9380)
  • Preserves existing behavior for all clusters when disabled

Test plan

  • Unit tests: 3 new tests covering skip/no-skip/non-LLM paths (23/23 pass)
  • E2e test: rotate LLM secret with flag enabled, verify no restart via Consistently
  • go vet ./... clean
  • go build ./... clean
  • CRD regenerated via make manifests

Related

Made with Cursor

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 openshift-eng/jira-lifecycle-plugin repository.

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds an optional CredentialHotReload setting to OLSConfig, propagates it to app-server configuration, removes LLM provider secret watcher annotations when enabled, and validates the behavior with tests and documentation.

Changes

Credential Hot-Reload

Layer / File(s) Summary
Configuration and app-server propagation
api/v1alpha1/olsconfig_types.go, internal/controller/utils/types.go, internal/controller/appserver/assets.go, internal/controller/olsconfig_controller.go
Adds API and internal configuration fields, generates credential_hot_reload, and logs when hot-reload is enabled.
LLM secret watcher control
internal/controller/olsconfig_helpers.go, internal/controller/watchers/watchers.go, internal/controller/watchers/watchers_test.go
Removes watcher annotations from LLM provider secrets when enabled while preserving existing handling for other resources.
Behavior validation and documentation
internal/controller/olsconfig_helpers_test.go, test/e2e/reconciliation_test.go, docs/credential-hot-reload.md
Tests annotation removal and restoration, verifies generated configuration end to end, and documents secret handling and prerequisites.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant OLSConfig
  participant OLSConfigReconciler
  participant LLMSecret
  participant AppServerConfig
  participant SecretWatcherFilter
  participant AppServerDeployment

  OLSConfig->>OLSConfigReconciler: provide CredentialHotReload
  OLSConfigReconciler->>AppServerConfig: set credential_hot_reload
  OLSConfigReconciler->>LLMSecret: remove watcher annotation
  LLMSecret-->>SecretWatcherFilter: credential secret event
  alt hot-reload enabled
    SecretWatcherFilter-->>AppServerDeployment: no restart trigger
  else hot-reload disabled
    SecretWatcherFilter->>AppServerDeployment: trigger restart
  end
Loading

Suggested reviewers: bparees, xrajesh, blublinsky

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding a credentialHotReload flag to avoid app-server restarts on LLM secret rotation.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@openshift-ci openshift-ci Bot requested review from bparees and xrajesh July 2, 2026 20:34
@openshift-ci

openshift-ci Bot commented Jul 2, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign blublinsky for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found 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

@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: 2

🧹 Nitpick comments (1)
internal/controller/watchers/watchers_test.go (1)

363-471: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider extracting the repeated Deployment/reconciler setup into a helper.

The three new tests duplicate identical dep/createTestReconciler boilerplate. A small local helper (e.g., newTestDeploymentAndReconciler(cr)) would reduce repetition within this file.

🤖 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 `@internal/controller/watchers/watchers_test.go` around lines 363 - 471, The
new Credential hot-reload tests duplicate the same Deployment and reconciler
setup in each case. Extract that repeated boilerplate into a small local helper
in watchers_test.go, such as a helper that builds the standard Deployment and
calls createTestReconciler, then reuse it in the three Describe/It blocks while
keeping the test-specific watcher config and Secret setup inline.
🤖 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 `@internal/controller/utils/types.go`:
- Around line 60-73: `WatcherConfig` is shared mutable state and is accessed
concurrently by `SecretWatcherFilter()` while `annotateExternalResources()`
updates `CredentialHotReload` and `LLMSecretNames`; add synchronization or
switch to an immutable snapshot approach. Update the `WatcherConfig` type in
`types.go` to guard these fields with a mutex (or refactor to store/retrieve a
copied config atomically), and make both `SecretWatcherFilter()` and
`annotateExternalResources()` use the same protection when reading or writing
`CredentialHotReload` and `LLMSecretNames`.

In `@test/e2e/reconciliation_test.go`:
- Around line 400-416: The reconciliation test uses a fixed sleep after updating
OLSConfig.CredentialHotReload, which makes the hot-reload setup timing-dependent
and flaky. Replace the blind time.Sleep in the credentialHotReload setup with an
Eventually-based wait on an observable signal from the reconciler, such as a
status condition, annotation, or other field updated when the latest
spec.generation has been processed. Use the existing client.Update, client.Get,
and deployment.Generation flow to locate the test, and keep the later
Consistently assertion only after the reconciler-ready signal is observed.

---

Nitpick comments:
In `@internal/controller/watchers/watchers_test.go`:
- Around line 363-471: The new Credential hot-reload tests duplicate the same
Deployment and reconciler setup in each case. Extract that repeated boilerplate
into a small local helper in watchers_test.go, such as a helper that builds the
standard Deployment and calls createTestReconciler, then reuse it in the three
Describe/It blocks while keeping the test-specific watcher config and Secret
setup inline.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: b0d1bbf1-2bfc-49b1-a705-c12229c81079

📥 Commits

Reviewing files that changed from the base of the PR and between 7ed4504 and b59c74c.

⛔ Files ignored due to path filters (1)
  • config/crd/bases/ols.openshift.io_olsconfigs.yaml is excluded by !config/crd/bases/**
📒 Files selected for processing (8)
  • api/v1alpha1/olsconfig_types.go
  • docs/credential-hot-reload.md
  • internal/controller/olsconfig_controller.go
  • internal/controller/olsconfig_helpers.go
  • internal/controller/utils/types.go
  • internal/controller/watchers/watchers.go
  • internal/controller/watchers/watchers_test.go
  • test/e2e/reconciliation_test.go

Comment thread internal/controller/utils/types.go
Comment thread test/e2e/reconciliation_test.go Outdated
@lalan7

lalan7 commented Jul 7, 2026

Copy link
Copy Markdown
Author

Hi @blublinsky — this is the operator companion to service PR openshift/lightspeed-service#2955 (RFE-9380).

Adds an opt-in credentialHotReload boolean to the OLSConfig CRD. When enabled, the operator skips rolling restarts for LLM credential secret rotations — the service handles it in-process. Default is false, so no behavior change for existing clusters.

All CI checks pass. The bundle-e2e-4-21 failure is a pre-existing main issue (unknown fields agenticConsole/alertsAdapter in test fixtures from PRs #1758/#1759), not related to this change.

Would appreciate a review when you have a chance.

@blublinsky

Copy link
Copy Markdown
Contributor

Suggestion: drive hot-reload from ForEachExternalSecret instead of SecretWatcherFilter

The flag is currently wired in two places: LLMSecretNames + CredentialHotReload are populated before ForEachExternalSecret, and SecretWatcherFilter has a runtime skip branch. That duplicates the provider iteration and adds special-case logic on the event path.

A simpler approach is to handle this inside the ForEachExternalSecret callback, the same way TLS secrets get their AnnotatedSecretMapping today: when credentialHotReload is enabled and source is llm-provider-*, do not annotate that secret (skip annotateSecretIfNeeded). Without the watcher annotation, shouldWatchSecret never admits it, so no restart watcher is created for that secret — no .data events on the hot-reload path, no SecretWatcherFilter changes, no LLMSecretNames map, no extra fields on WatcherConfig, no skip logic at event time.

When the flag is off, behavior stays as today: foreach annotates LLM credential secrets and rotations trigger a rolling restart as they do now.

That keeps “which secrets does the operator react to?” entirely in the existing foreach/mapping configuration model, instead of splitting it between reconcile-time config and filter-time exceptions.

One thing to nail when toggling the flag on for clusters that already have annotated LLM secrets: reconcile may need to remove the watcher annotation when hot-reload is enabled, not only skip adding it for new ones.


I’d hold off on deeper review until this is reworked — the foreach-based approach removes most of the PR’s watcher-layer changes and is the pattern we already use for other secret types.

@blublinsky

Copy link
Copy Markdown
Contributor

Follow-up: credentialHotReload must reach the service via OLS config for end-to-end behavior

Today this flag lives only on the CR and in operator WatcherConfig (skip restart). It is not propagated into the app-server olsconfig ConfigMap (buildOLSConfig / AppSrvConfigFile) and the service PR has no corresponding config field either.

That leaves two independent behaviors with no runtime coupling:

Layer What happens
Operator (credentialHotReload: true) Skips pod restart on LLM secret rotation
Service (lightspeed-service #2955) Re-reads credentials_path on every request — but unconditionally, not driven by this flag

For this to work end-to-end, the flag should flow:

OLSConfig CR (spec.ols.credentialHotReload)
  → operator builds olsconfig ConfigMap
  → service reads config and enables hot-reload credential reads when true

Without that, enabling the CR flag on a cluster with an older service image (or before #2955 is deployed) silently disables restarts while credentials stay stale at startup — the CR comment warns about this, but nothing in config enforces it.

Suggest:

  1. Add the field to the generated OLS config (utils.OLSConfig / buildOLSConfig).
  2. Service side: gate get_credentials() disk re-read on that config flag (default false for backward compatibility).
  3. Operator watcher skip (ideally via ForEachExternalSecret / no annotation) should follow the same CR flag.

That gives one user-facing switch that coordinates both “don’t restart” and “do re-read from disk,” instead of two repos assuming the other half is always correct.

@blublinsky

Copy link
Copy Markdown
Contributor

Scoping: operator-only PR + bundle follow-up

This PR is correctly scoped to the operator only — service changes stay in openshift/lightspeed-service#2955. Keep it that way.

Once the operator changes here are in good shape, suggest landing this PR without blocking on the OLM bundle, then a follow-up PR that runs make manifests && make bundle (or hack/update_bundle.sh) so bundle/manifests/ols.openshift.io_olsconfigs.yaml picks up credentialHotReload. Right now the field is only in config/crd/bases/; OLM installs use the bundle CRD, so the feature isn’t usable from the shipped bundle until that follow-up.

Order I’d expect:

  1. Operator PR (this repo) — CRD + reconcile/watcher wiring + config pass-through to olsconfig once agreed
  2. Service PR — gated get_credentials() re-read on config flag
  3. Bundle follow-up — regenerate committed bundle/ manifests

That keeps review focused and matches how we usually ship CRD schema vs bundle image updates.

@openshift-ci openshift-ci Bot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jul 14, 2026

@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 `@internal/controller/olsconfig_helpers.go`:
- Around line 389-416: The credential hot-reload branch in the
ForEachExternalSecret callback currently logs failures from
removeSecretAnnotationIfNeeded without recording them. Append that error to errs
before returning, matching the existing annotateSecretIfNeeded error handling so
reconciliation reports the failure and retries.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 6896947a-047f-45c2-a404-05c4b75468c8

📥 Commits

Reviewing files that changed from the base of the PR and between b59c74c and 1eaa6a2.

📒 Files selected for processing (6)
  • internal/controller/appserver/assets.go
  • internal/controller/olsconfig_helpers.go
  • internal/controller/utils/types.go
  • internal/controller/watchers/watchers.go
  • internal/controller/watchers/watchers_test.go
  • test/e2e/reconciliation_test.go
💤 Files with no reviewable changes (2)
  • internal/controller/watchers/watchers.go
  • internal/controller/watchers/watchers_test.go

Comment thread internal/controller/olsconfig_helpers.go
lalan7 added 2 commits July 14, 2026 10:44
…LLM secret rotation

Adds an opt-in credentialHotReload boolean to OLSSpec CRD. When enabled,
the operator's secret watcher skips rolling restart for LLM credential
secrets, allowing the service's in-process hot-reload to handle rotated
tokens without downtime (RFE-9380).

Default: false (preserves existing behavior).

- New CRD field: spec.olsConfig.credentialHotReload (default: false)
- Watcher: skip restart for LLM secrets when flag is true
- Info log emitted during reconciliation when enabled
- Unit tests (3 new) + e2e test for hot-reload skip
- Documentation: docs/credential-hot-reload.md

Companion to lightspeed-service PR #2955.
- Drive hot-reload from ForEachExternalSecret callback: skip annotation
  for LLM secrets when credentialHotReload is enabled, remove existing
  annotations when toggling on
- Remove CredentialHotReload/LLMSecretNames from WatcherConfig and the
  skip block from SecretWatcherFilter
- Propagate credentialHotReload into olsconfig ConfigMap via
  utils.OLSConfig and buildOLSConfig()
- Add removeSecretAnnotationIfNeeded helper
- Rework e2e test to verify annotation removal and ConfigMap content
- Remove obsolete watcher hot-reload unit tests
@lalan7 lalan7 force-pushed the feat/credential-hot-reload branch from 1eaa6a2 to 1cda906 Compare July 14, 2026 14:51
@openshift-ci openshift-ci Bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jul 14, 2026
… add unit tests

- Append removeSecretAnnotationIfNeeded errors to errs slice so
  annotateExternalResources reports failures consistently.
- Replace hardcoded "ols.openshift.io/watcher" in e2e test with
  utils.WatcherAnnotationKey constant.
- Add unit tests for removeSecretAnnotationIfNeeded covering annotation
  present, absent, and secret-not-found cases.
@lalan7

lalan7 commented Jul 14, 2026

Copy link
Copy Markdown
Author

@blublinsky

Addressed all code review findings in the latest push:

Service (lightspeed-service):

Consolidated AWS credential reads — Bedrock.load() now calls get_aws_credentials() once and passes the tuple through to _build_boto3_session() / _build_sigv4_auth() via an optional parameter. This cuts disk reads per load() from 6 to 3 and eliminates a potential mid-request partial rotation race (e.g. new access_key + old secret_key if rotation lands between calls).

Guarded optional role_arn read — get_aws_credentials() now checks os.path.isfile() before attempting to read the role_arn file, avoiding spurious warning logs when it's not configured (common scenario).

Operator (lightspeed-operator):

Collected removeSecretAnnotationIfNeeded errors — failures are now appended to the errs slice, consistent with annotateSecretIfNeeded error handling. Previously these were logged but silently swallowed.
Replaced hardcoded annotation key in e2e test — all 3 instances of "ols.openshift.io/watcher" now use utils.WatcherAnnotationKey.

Added unit tests for removeSecretAnnotationIfNeeded — covers annotation present (removed), annotation absent (no-op), and secret not found (no-op).

All service tests pass (28/28). Operator compiles and passes go vet cleanly (envtest unit tests require kubebuilder binaries available only in CI).

@lalan7

lalan7 commented Jul 14, 2026

Copy link
Copy Markdown
Author

/retest

lalan7 added 2 commits July 14, 2026 13:51
The controller-gen output in config/crd/bases/ had the field but the
bundle manifest was stale, causing the e2e test to fail with
"unknown field spec.ols.credentialHotReload".
…ation

Annotation failures in annotateExternalResources caused the reconciler to
return early, preventing subsequent steps (including ConfigMap generation)
from running. This starved the olsconfig ConfigMap of the credential_hot_reload
flag, causing the e2e test to time out.

Validation errors (LLM credentials, TLS secrets) remain blocking. Annotation
operations are idempotent and will succeed on the next reconciliation cycle.

@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: 2

🤖 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 `@internal/controller/olsconfig_helpers.go`:
- Around line 408-413: Protect shared WatcherConfig map access with one
sync.RWMutex: guard the AnnotatedSecretMapping write in
internal/controller/olsconfig_helpers.go lines 408-413 and the
AnnotatedConfigMapMapping write in lines 440-442, and use the same mutex in
SecretWatcherFilter and ConfigMapWatcherFilter for corresponding reads.
- Around line 454-458: Update the error-return path in the helper containing the
errs check so non-empty errs is aggregated and returned instead of returning
nil, ensuring reconciliation retries. Use r.GetLogger().Info for the retry
message, and wrap the aggregated error with fmt.Errorf using the applicable
shared error constant from internal/controller/utils/errors.go. Preserve the
existing successful nil return when errs is empty.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 7d5c034e-00f0-4ca2-b7e6-6f8776b361d0

📥 Commits

Reviewing files that changed from the base of the PR and between 1eaa6a2 and ee29f5d.

⛔ Files ignored due to path filters (2)
  • bundle/manifests/ols.openshift.io_olsconfigs.yaml is excluded by !bundle/manifests/ols.openshift.io_olsconfigs.yaml
  • config/crd/bases/ols.openshift.io_olsconfigs.yaml is excluded by !config/crd/bases/**
📒 Files selected for processing (10)
  • api/v1alpha1/olsconfig_types.go
  • docs/credential-hot-reload.md
  • internal/controller/appserver/assets.go
  • internal/controller/olsconfig_controller.go
  • internal/controller/olsconfig_helpers.go
  • internal/controller/olsconfig_helpers_test.go
  • internal/controller/utils/types.go
  • internal/controller/watchers/watchers.go
  • internal/controller/watchers/watchers_test.go
  • test/e2e/reconciliation_test.go
🚧 Files skipped from review as they are similar to previous changes (8)
  • internal/controller/watchers/watchers.go
  • internal/controller/watchers/watchers_test.go
  • api/v1alpha1/olsconfig_types.go
  • test/e2e/reconciliation_test.go
  • internal/controller/appserver/assets.go
  • internal/controller/olsconfig_controller.go
  • docs/credential-hot-reload.md
  • internal/controller/utils/types.go

Comment on lines 408 to 413
if r.WatcherConfig != nil && source == "tls" {
r.WatcherConfig.AnnotatedSecretMapping[name] = []string{
utils.ConsoleUIDeploymentName,
"ACTIVE_BACKEND",
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🔴 Critical | 🏗️ Heavy lift

Concurrent map read/write data race on r.WatcherConfig.

Both map writes in the reconciler loop cause a fatal data race with concurrent reads from the informer event handlers (SecretWatcherFilter and ConfigMapWatcherFilter). Maps in Go are not thread-safe, and this overlap will crash the operator with a panic. The shared root cause is a lack of synchronization when accessing WatcherConfig state across distinct execution threads.

  • internal/controller/olsconfig_helpers.go#L408-L413: guard writes to r.WatcherConfig.AnnotatedSecretMapping with a sync.RWMutex.
  • internal/controller/olsconfig_helpers.go#L440-L442: guard writes to r.WatcherConfig.AnnotatedConfigMapMapping with the same mutex.
📍 Affects 1 file
  • internal/controller/olsconfig_helpers.go#L408-L413 (this comment)
  • internal/controller/olsconfig_helpers.go#L440-L442
🤖 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 `@internal/controller/olsconfig_helpers.go` around lines 408 - 413, Protect
shared WatcherConfig map access with one sync.RWMutex: guard the
AnnotatedSecretMapping write in internal/controller/olsconfig_helpers.go lines
408-413 and the AnnotatedConfigMapMapping write in lines 440-442, and use the
same mutex in SecretWatcherFilter and ConfigMapWatcherFilter for corresponding
reads.

Comment on lines 454 to 458
if len(errs) > 0 {
return fmt.Errorf("failed to annotate %d external resources", len(errs))
r.Logger.Info("some external resource annotations failed, will retry on next reconciliation",
"failureCount", len(errs))
}
return nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🔴 Critical | 🏗️ Heavy lift

Return the aggregated error to ensure the reconciliation is retried.

Returning nil when errs is non-empty swallows the errors and causes the controller to consider the reconciliation successful. The controller will not requeue the request, meaning the retry mentioned in the log will not happen unless another external event triggers a reconciliation.

Additionally, as per coding guidelines and path instructions:

  • Use r.GetLogger().Info instead of r.Logger.Info.
  • Wrap the returned error using fmt.Errorf with the appropriate shared constant from internal/controller/utils/errors.go (if applicable).
🐛 Proposed fix
 	if len(errs) > 0 {
-		r.Logger.Info("some external resource annotations failed, will retry on next reconciliation",
+		r.GetLogger().Info("some external resource annotations failed, will retry on next reconciliation",
 			"failureCount", len(errs))
+		return fmt.Errorf("failed to process annotations: %w", errors.Join(errs...))
 	}
 	return nil
📝 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
if len(errs) > 0 {
return fmt.Errorf("failed to annotate %d external resources", len(errs))
r.Logger.Info("some external resource annotations failed, will retry on next reconciliation",
"failureCount", len(errs))
}
return nil
if len(errs) > 0 {
r.GetLogger().Info("some external resource annotations failed, will retry on next reconciliation",
"failureCount", len(errs))
return fmt.Errorf("failed to process annotations: %w", errors.Join(errs...))
}
return nil
🤖 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 `@internal/controller/olsconfig_helpers.go` around lines 454 - 458, Update the
error-return path in the helper containing the errs check so non-empty errs is
aggregated and returned instead of returning nil, ensuring reconciliation
retries. Use r.GetLogger().Info for the retry message, and wrap the aggregated
error with fmt.Errorf using the applicable shared error constant from
internal/controller/utils/errors.go. Preserve the existing successful nil return
when errs is empty.

Sources: Coding guidelines, Path instructions

The CA-cert test (test 2) sets AdditionalCAConfigMapRef on the CR and
deletes the ConfigMap in a defer, but never clears the CR reference.
When the hot-reload test (test 3) runs, GenerateOLSConfigMap fails with
NotFound for the deleted ConfigMap, permanently blocking the
credential_hot_reload flag from being propagated to olsconfig.yaml.

Also reverts the non-blocking annotation error change from ee29f5d —
that was not the actual root cause.

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/controller/olsconfig_helpers.go (1)

419-426: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use the required reconciler logger.

Replace r.Logger.Error with r.GetLogger().Error in both error paths to follow the repository’s mandated logging pattern.

🤖 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 `@internal/controller/olsconfig_helpers.go` around lines 419 - 426, Replace
r.Logger.Error with r.GetLogger().Error in both error paths within the secret
annotation/removal flow, including the calls for “Failed to remove annotation
from secret” and “Failed to annotate secret,” while preserving their existing
arguments.

Sources: Coding guidelines, Path instructions

🤖 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.

Outside diff comments:
In `@internal/controller/olsconfig_helpers.go`:
- Around line 419-426: Replace r.Logger.Error with r.GetLogger().Error in both
error paths within the secret annotation/removal flow, including the calls for
“Failed to remove annotation from secret” and “Failed to annotate secret,” while
preserving their existing arguments.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 7a81df0a-1ec3-449f-91ee-c57671646807

📥 Commits

Reviewing files that changed from the base of the PR and between ee29f5d and 3848992.

📒 Files selected for processing (2)
  • internal/controller/olsconfig_helpers.go
  • test/e2e/reconciliation_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/e2e/reconciliation_test.go

@openshift-ci

openshift-ci Bot commented Jul 14, 2026

Copy link
Copy Markdown

@lalan7: 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants