Skip to content
This repository was archived by the owner on Sep 9, 2026. It is now read-only.

NO-ISSUE: Fix CaaS boot failures caused by dirty database migrations - #260

Closed
omer-vishlitzky wants to merge 1 commit into
osac-project:mainfrom
omer-vishlitzky:fix/scale-down-grpc-before-kustomize-apply
Closed

NO-ISSUE: Fix CaaS boot failures caused by dirty database migrations#260
omer-vishlitzky wants to merge 1 commit into
osac-project:mainfrom
omer-vishlitzky:fix/scale-down-grpc-before-kustomize-apply

Conversation

@omer-vishlitzky

@omer-vishlitzky omer-vishlitzky commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Scale down fulfillment-grpc-server to 0 before applying the kustomize overlay in the refresh script, preventing database migrations from running while the database pod is being recycled
  • Remove 2>/dev/null || true from scale-down commands — on snapshot boot the deployments always exist, and silent failures here mask real problems

Root Cause

The kustomize overlay changes the fulfillment-database StatefulSet image reference from a :latest tag to a @sha256: digest. This spec change triggers a StatefulSet pod recreation, killing the database server. If fulfillment-grpc-server is running database migrations at that moment, golang-migrate leaves the schema_migrations table dirty (dirty=true), and all subsequent grpc-server starts crash with Dirty database version N. Fix and force version.

This was the root cause of intermittent CaaS boot failures in openshift/release#79512 — the failure rate depended on whether migrations finished before the database pod was killed (a race condition).

Evidence

Differential analysis across 5 CaaS rehearsal jobs from the same batch:

  • Failing (osac-operator): DB pod age 7m53s (recreated), grpc-server dirty=true at v39
  • Passing (osac-aap): DB pod age 30m (also recreated, but migrations had already completed)
  • Passing (others): DB pod ages 27-29m, migrations completed before recreation

Test plan

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Deployment refresh now uses declarative configuration for scaling during snapshot restoration.
    • Streamlined restart sequence for certificate and service refresh to improve reliability and reduce downtime.
    • Removed redundant runtime scaling steps and clarified operator guidance for preparing fulfillment services prior to refresh.

@openshift-ci-robot

Copy link
Copy Markdown

@omer-vishlitzky: This pull request explicitly references no jira issue.

Details

In response to this:

Summary

  • Scale down fulfillment-grpc-server to 0 before applying the kustomize overlay in the refresh script, preventing database migrations from running while the database pod is being recycled
  • Remove 2>/dev/null || true from scale-down commands — on snapshot boot the deployments always exist, and silent failures here mask real problems

Root Cause

The kustomize overlay changes the fulfillment-database StatefulSet image reference from a :latest tag to a @sha256: digest. This spec change triggers a StatefulSet pod recreation, killing the database server. If fulfillment-grpc-server is running database migrations at that moment, golang-migrate leaves the schema_migrations table dirty (dirty=true), and all subsequent grpc-server starts crash with Dirty database version N. Fix and force version.

This was the root cause of intermittent CaaS boot failures in openshift/release#79512 — the failure rate depended on whether migrations finished before the database pod was killed (a race condition).

Evidence

Differential analysis across 5 CaaS rehearsal jobs from the same batch:

  • Failing (osac-operator): DB pod age 7m53s (recreated), grpc-server dirty=true at v39
  • Passing (osac-aap): DB pod age 30m (also recreated, but migrations had already completed)
  • Passing (others): DB pod ages 27-29m, migrations completed before recreation

Test plan

🤖 Generated with Claude Code

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 Jun 11, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Consolidates fulfillment scale-to-zero into a kustomize overlay edit before oc apply -k, and reorders the TLS/certificate restart sequence to wait for DB rollout, scale controller and grpc-server up, restart ingress-proxy, then wait for fulfillment deployment rollouts and CDI cert refresh.

Changes

Snapshot Refresh Deployment Coordination

Layer / File(s) Summary
Overlay-driven scaling: set replicas in kustomize overlay
scripts/refresh-after-snapshot.sh
Removes explicit pre- and post-overlay oc scale deploy/fulfillment-controller --replicas=0 calls and adds an overlay-edit that sets replicas: 0 for both fulfillment-controller and fulfillment-grpc-server before oc apply -k (range: range_d954805fe978).
TLS/certificate restart reorder and scaled bring-up
scripts/refresh-after-snapshot.sh
After certificate readiness, waits for statefulset/fulfillment-database rollout, scales fulfillment-controller and fulfillment-grpc-server to replicas=1, restarts fulfillment-ingress-proxy, then waits for fulfillment deployment rollouts and CDI cert refresh (range: range_d1a4d5549c9d).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

lgtm

Suggested reviewers

  • akshaynadkarni
  • trewest
  • danmanor

Security & Operational Risk Assessment

Severity: Medium — rehoming scale-to-zero into the overlay removes explicit imperative scaling calls; if the overlay edit or oc apply -k fails or the overlay content is incorrect, deployments may not be scaled down/up as expected, risking migration races or downtime. Verify overlay edits, oc apply -k success, and rollout status checks in automation.

Overlay edits set the pods to sleep,
DB must roll out before we leap,
Scale up controller and grpc in line,
Restart the proxy — then watch each sign. 🎛️


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (3 errors, 1 warning)

Check name Status Explanation Resolution
No-Hardcoded-Secrets ❌ Error Hardcoded token "test-token" and secret placeholders ("config-as-code-ig") plus base64-encoded privateKey in prerequisites/keycloak/service/files/realm.json (MIIE... len 1588) were added in the PR. Remove embedded token/privateKey/base64 secret material from repo; load from Kubernetes Secrets/secret manager at deploy time and use placeholders/redaction in configs.
No-Weak-Crypto ❌ Error scripts/refresh-after-snapshot.sh uses md5sum to hash Keycloak realm.json (NEW_HASH/OLD_HASH) and compares them (non-constant-time), violating the no-weak-crypto rule. citeturn0view0 Replace md5sum with sha256sum (or stronger) for NEW_HASH/OLD_HASH change detection, and adjust the comparison logic accordingly.
No-Sensitive-Data-In-Logs ❌ Error refresh-after-snapshot.sh logs internal hostnames/IPs (e.g., cluster domain, route OLD_HOST/NEW_HOST, and Node IP). This can leak environment details in CI/runtime logs. Remove or redact hostname/IP echo lines (e.g., don’t print ${CLUSTER_DOMAIN}, ${OLD_HOST}/${NEW_HOST}, ${NODE_IP}); log only non-sensitive status messages.
Ai-Attribution ⚠️ Warning High risk: AI attribution uses Co-Authored-By: Claude Opus with no Red Hat Assisted-by or Generated-by trailers in the PR commit. Replace Co-Authored-By with Red Hat-compliant Generated-by/Assisted-by trailers for the AI tool (or remove it) so attribution requirements are met.
✅ Passed checks (7 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main objective of fixing database migration race conditions, though the specific mechanism (scaling down gRPC before kustomize apply) is not mentioned.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
No-Injection-Vectors ✅ Passed Only scripts/refresh-after-snapshot.sh changed; the file contains none of the flagged patterns (eval/exec, pickle.loads, yaml.load, os.system, shell=True, dangerouslySetInnerHTML).
Container-Privileges ✅ Passed PR #260 changes only scripts/refresh-after-snapshot.sh; searching that file shows no privileged/hostPID/hostNetwork/hostIPC/SYS_ADMIN/allowPrivilegeEscalation/running-as-root markers.
✨ 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 and usage tips.

@tzvatot tzvatot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Clean fix, well-analyzed race condition. No findings.

/lgtm

@openshift-ci openshift-ci Bot added the lgtm label Jun 11, 2026
@omer-vishlitzky
omer-vishlitzky force-pushed the fix/scale-down-grpc-before-kustomize-apply branch from eb9dda9 to 682f6de Compare June 11, 2026 15:10
@openshift-ci openshift-ci Bot removed the lgtm label Jun 11, 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 `@scripts/refresh-after-snapshot.sh`:
- Line 183: Remove the redundant scale-down command that re-scales the
fulfillment-controller to 0 replicas (the oc scale deploy/fulfillment-controller
-n "${INSTALLER_NAMESPACE}" --replicas=0 line) because the controller is already
scaled down earlier before the overlay apply; either delete this line or, if you
intentionally want a defensive re-check, keep it but add an inline comment
referencing the earlier pre-overlay scale-down and explaining the defensive
rationale so future readers understand why it's duplicated.
🪄 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: osac-project/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 7d702fb4-c828-455a-8d2e-4a7ceead6637

📥 Commits

Reviewing files that changed from the base of the PR and between 0aea7ed and 682f6de.

📒 Files selected for processing (1)
  • scripts/refresh-after-snapshot.sh

Comment thread scripts/refresh-after-snapshot.sh Outdated

@eliorerz eliorerz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

@openshift-ci openshift-ci Bot added the lgtm label Jun 11, 2026
@omer-vishlitzky
omer-vishlitzky force-pushed the fix/scale-down-grpc-before-kustomize-apply branch from 682f6de to 1e1f82a Compare June 11, 2026 15:52
@openshift-ci openshift-ci Bot removed the lgtm label Jun 11, 2026
@omer-vishlitzky
omer-vishlitzky force-pushed the fix/scale-down-grpc-before-kustomize-apply branch from 1e1f82a to f46ae16 Compare June 11, 2026 16:24

@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 `@scripts/refresh-after-snapshot.sh`:
- Around line 175-181: The script currently scales fulfillment-grpc-server to 0
but only restores fulfillment-controller later; update the restore step that
re-enables replicas (the block that currently resets fulfillment-controller
replicas) to also reset fulfillment-grpc-server to its desired replica count
(e.g., include fulfillment-grpc-server=<desired> in the same kustomize edit set
replicas call) and ensure any subsequent restart/wait loops that check or wait
for fulfillment-controller also include checks for fulfillment-grpc-server so
the grpc service is brought back and verified.
🪄 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: osac-project/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 85e79bb8-5161-42ab-8f73-bfec940ff6f1

📥 Commits

Reviewing files that changed from the base of the PR and between 682f6de and f46ae16.

📒 Files selected for processing (1)
  • scripts/refresh-after-snapshot.sh

Comment thread scripts/refresh-after-snapshot.sh

@eliorerz eliorerz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

@openshift-ci openshift-ci Bot added the lgtm label Jun 11, 2026
@openshift-ci

openshift-ci Bot commented Jun 11, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: eliorerz, omer-vishlitzky, tzvatot

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:
  • OWNERS [eliorerz,omer-vishlitzky,tzvatot]

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

@omer-vishlitzky

Copy link
Copy Markdown
Contributor Author

/retest

…pply

The kustomize overlay changes the fulfillment-database StatefulSet image
reference from a :latest tag to a @sha256: digest. This triggers a
StatefulSet pod recreation, killing the database mid-connection. If the
grpc-server is running database migrations at that moment, golang-migrate
leaves the schema_migrations table in a dirty state and all subsequent
grpc-server starts refuse to run — causing a boot failure.

Fix: use `kustomize edit set replicas` to set fulfillment-controller and
fulfillment-grpc-server to 0 before applying the overlay. The apply
itself deploys with zero replicas, eliminating the race entirely.

At step [5/9], the script now:
1. Waits for TLS certificates
2. Waits for the database StatefulSet rollout to complete
3. Scales grpc-server and controller back to 1
4. Waits for all fulfillment deployment rollouts

This ensures the database is healthy before any migration-running pod
starts, and that grpc-server is available before rest-gateway's
readiness probe checks the gRPC upstream.

Depends on: openshift/release#80431 (adds kustomize binary to the
installer container image).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@omer-vishlitzky
omer-vishlitzky force-pushed the fix/scale-down-grpc-before-kustomize-apply branch from 5d931d0 to cf01bd3 Compare June 12, 2026 06:09
@openshift-ci openshift-ci Bot removed the lgtm label Jun 12, 2026
@openshift-ci

openshift-ci Bot commented Jun 12, 2026

Copy link
Copy Markdown

New changes are detected. LGTM label has been removed.

@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 `@scripts/refresh-after-snapshot.sh`:
- Around line 175-182: The script currently mutates
overlays/${INSTALLER_KUSTOMIZE_OVERLAY}/kustomization.yaml with "kustomize edit
set replicas fulfillment-controller=0 fulfillment-grpc-server=0" and never
restores it; change the script to read and save the current replica values from
the overlay before the edit, perform the zero-replica kustomize edit and oc
apply -k as now, then after rollout verification restore the original replica
values back into the same overlay (use the saved values with kustomize edit set
replicas fulfillment-controller=<saved> fulfillment-grpc-server=<saved>),
placing the restore step after the deployment/rollout checks near the end of the
script so the working tree is not left modified (alternatively replace the
edit-within-file approach by using oc scale --replicas=0 before apply if you
prefer to avoid mutating kustomization.yaml).
🪄 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: osac-project/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 4243e022-8fbd-4fda-b8c8-c20b759b5d80

📥 Commits

Reviewing files that changed from the base of the PR and between f46ae16 and cf01bd3.

📒 Files selected for processing (1)
  • scripts/refresh-after-snapshot.sh

Comment on lines +175 to 182
# Deploy with fulfillment pods scaled to zero. The apply changes the database
# StatefulSet image ref (tag → digest), triggering a pod recreation. If the
# grpc-server were running, it could be mid-migration when the database is
# killed, leaving golang-migrate's schema dirty. Deploying at zero replicas
# eliminates the race entirely — pods are brought back at step [5/9] after
# the database rollout completes.
( cd "overlays/${INSTALLER_KUSTOMIZE_OVERLAY}" && kustomize edit set replicas fulfillment-controller=0 fulfillment-grpc-server=0 )
oc apply -k "overlays/${INSTALLER_KUSTOMIZE_OVERLAY}"

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

Major risk: kustomize edit leaves overlay with replicas: 0 permanently.

The kustomize edit set replicas command on line 181 modifies overlays/${INSTALLER_KUSTOMIZE_OVERLAY}/kustomization.yaml on disk. While lines 322-323 restore replicas via oc scale in the cluster, the kustomization.yaml file retains replicas: 0.

Impact (Severity: Major):

  • Any subsequent oc apply -k overlays/${OVERLAY} (manual or automated) will scale fulfillment-controller and fulfillment-grpc-server to 0, causing immediate service outage
  • On shared clusters (development, hypershift2 per AGENTS.md), this creates a latent disruption risk for other developers
  • Leaves git working tree dirty, potentially masking other overlay changes

Recommended fix: Restore the replicas configuration at the end of the script or after the deployments are successfully rolled out.

🛡️ Proposed fix: Restore replicas in kustomization.yaml

Add this near the end of the script (e.g., after line 418's rollout verification):

 if (( failed )); then echo "ERROR: Fulfillment rollout failed after restart"; exit 1; fi
+# Restore overlay replicas so future applies don't scale to zero
+( cd "overlays/${INSTALLER_KUSTOMIZE_OVERLAY}" && kustomize edit set replicas fulfillment-controller=1 fulfillment-grpc-server=1 )
 ./scripts/prepare-tenant.sh

Alternatively, consider using oc scale --replicas=0 before the apply instead of modifying the overlay file, though this reintroduces the race window you're trying to avoid.

🤖 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 `@scripts/refresh-after-snapshot.sh` around lines 175 - 182, The script
currently mutates overlays/${INSTALLER_KUSTOMIZE_OVERLAY}/kustomization.yaml
with "kustomize edit set replicas fulfillment-controller=0
fulfillment-grpc-server=0" and never restores it; change the script to read and
save the current replica values from the overlay before the edit, perform the
zero-replica kustomize edit and oc apply -k as now, then after rollout
verification restore the original replica values back into the same overlay (use
the saved values with kustomize edit set replicas fulfillment-controller=<saved>
fulfillment-grpc-server=<saved>), placing the restore step after the
deployment/rollout checks near the end of the script so the working tree is not
left modified (alternatively replace the edit-within-file approach by using oc
scale --replicas=0 before apply if you prefer to avoid mutating
kustomization.yaml).

@omer-vishlitzky

Copy link
Copy Markdown
Contributor Author

/retest

@openshift-ci

openshift-ci Bot commented Jun 15, 2026

Copy link
Copy Markdown

@omer-vishlitzky: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/images cf01bd3 link true /test images
ci/prow/e2e-vmaas cf01bd3 link true /test e2e-vmaas

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 subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants