Skip to content

ARO-24037: gate cloud config on hash to prevent serving stale content#8946

Open
twolff-gh wants to merge 2 commits into
openshift:mainfrom
twolff-gh:fix-ignition-cloud-config-hash-gate
Open

ARO-24037: gate cloud config on hash to prevent serving stale content#8946
twolff-gh wants to merge 2 commits into
openshift:mainfrom
twolff-gh:fix-ignition-cloud-config-hash-gate

Conversation

@twolff-gh

@twolff-gh twolff-gh commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Prevents stale cloud.conf from being served during the race between the CPO updating azure-cloud-config and the ignition server reading it.

Follows the existing pullSecretHash / additionalTrustBundleHash pattern: nodepool controller hashes the cloud config ConfigMap and stores it in the token secret; ignition server verifies the hash before writing cloud.conf, retrying on mismatch.

What this PR does / why we need it:

Which issue(s) this PR fixes:

Fixes https://redhat.atlassian.net/browse/ARO-24037

Related to #8865

Special notes for your reviewer:

Checklist:

  • Subject and description added to both, commit and PR.
  • Relevant issues have been referenced.
  • This change includes docs.
  • This change includes unit tests.

Summary by CodeRabbit

  • New Features

    • Added tracking of cloud provider configuration via a new cloud-config-hash value stored in token Secrets and propagated into ignition payload generation.
    • Ignition payload caching/reuse now records and considers this cloud configuration hash.
  • Bug Fixes

    • Azure/OpenStack ignition payloads now validate the retrieved cloud configuration content against the expected hash, preventing stale or out-of-date configuration.
    • Token secret reconciliation and payload cache invalidation are improved: payloads are regenerated when the cloud configuration hash changes.

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Pipeline controller notification
This repo is configured to use the pipeline controller. Second-stage tests will be triggered either automatically or after lgtm label is added, depending on the repository configuration. The pipeline controller will automatically detect which contexts are required and will utilize /test Prow commands to trigger the second stage.

For optional jobs, comment /test ? to see a list of all defined jobs. To trigger manually all jobs from second stage use /pipeline required command.

This repository is configured in: LGTM mode

@openshift-ci

openshift-ci Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@openshift-ci openshift-ci Bot added do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. do-not-merge/needs-area area/control-plane-operator Indicates the PR includes changes for the control plane operator - in an OCP release area/hypershift-operator Indicates the PR includes changes for the hypershift operator and API - outside an OCP release and removed do-not-merge/needs-area labels Jul 6, 2026
@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

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

Walkthrough

This change adds deterministic hashing for cloud provider ConfigMap data, stores the hash in nodepool token secrets, and threads it through ignition payload generation. The ignition server now carries the hash in cache entries, invalidates cached payloads when the hash changes, and verifies Azure/OpenStack cloud provider ConfigMap data against the expected hash before writing cloud config. Tests were added and updated for hash generation, propagation, validation, and cache invalidation.

Sequence Diagram(s)

sequenceDiagram
  participant ConfigGenerator
  participant NodePoolToken
  participant TokenSecretController
  participant LocalIgnitionProvider
  participant Cache
  participant KubeAPI

  ConfigGenerator->>KubeAPI: Read cloud provider ConfigMap
  KubeAPI-->>ConfigGenerator: ConfigMap data
  ConfigGenerator-->>NodePoolToken: cloudConfigHash
  NodePoolToken->>TokenSecretController: store cloud-config-hash

  TokenSecretController->>Cache: read cached payload
  TokenSecretController->>TokenSecretController: compare CloudConfigHash
  TokenSecretController->>LocalIgnitionProvider: GetPayload(..., cloudConfigHash)
  LocalIgnitionProvider->>KubeAPI: Read cloud provider ConfigMap
  KubeAPI-->>LocalIgnitionProvider: ConfigMap data
  LocalIgnitionProvider->>LocalIgnitionProvider: hash and compare
  LocalIgnitionProvider-->>TokenSecretController: payload or error
  TokenSecretController->>Cache: store payload + CloudConfigHash
Loading
🚥 Pre-merge checks | ✅ 11
✅ Passed checks (11 passed)
Check name Status Explanation
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 All added/changed test titles are static string literals or table names; no fmt.Sprintf/runtime-derived names were found.
Test Structure And Quality ✅ Passed The new tests are isolated table-driven unit tests with fake clients/temp dirs, no cluster resources or waits, and no multi-behavior Ginkgo It blocks.
Topology-Aware Scheduling Compatibility ✅ Passed PR only threads cloud-config hash through secrets/cache and verifies it at ignition time; no affinity, nodeSelector, topology spread, PDB, or replica changes.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed No new Ginkgo e2e tests were added; the new tests are unit tests and show no IPv4-only or external connectivity assumptions.
No-Weak-Crypto ✅ Passed No new MD5/SHA1/DES/RC4/3DES/Blowfish/ECB or secret/token comparisons were added; the new cloud-config hash path uses FNV-based HashSimple and config-only equality checks.
Container-Privileges ✅ Passed The PR diff is code/tests only; no K8s/container manifests changed and no privileged/hostPID/hostNetwork/hostIPC/SYS_ADMIN/allowPrivilegeEscalation settings were found.
No-Sensitive-Data-In-Logs ✅ Passed New logs are generic; no passwords/tokens/hashes/PII are printed, and mismatch errors avoid embedding secret values.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: hashing cloud config to avoid serving stale content.
✨ 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.

@twolff-gh
twolff-gh marked this pull request as ready for review July 6, 2026 23:22
@openshift-ci openshift-ci Bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jul 6, 2026
@openshift-ci
openshift-ci Bot requested review from enxebre and sjenning July 6, 2026 23:22

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

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 `@hypershift-operator/controllers/nodepool/config.go`:
- Around line 359-392: The hash computation in
ConfigGenerator.GetCloudConfigHash is duplicated with
LocalIgnitionProvider.writeCloudProviderConfig, so extract the sort-and-hash
logic into a shared helper in support/util and have both call it. Make the
helper accept ConfigMap data as map[string]string and return the hash, keeping
the exact same behavior on both paths. While refactoring, address the
concatenation ambiguity by using a deterministic delimiter or encoding so
different key/value pairs cannot collide, and ensure both callers use the same
helper implementation.
🪄 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 YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 0594b6c0-9732-400b-b318-74d99bbd8b7a

📥 Commits

Reviewing files that changed from the base of the PR and between dda6055 and b081c30.

📒 Files selected for processing (7)
  • hypershift-operator/controllers/nodepool/config.go
  • hypershift-operator/controllers/nodepool/config_test.go
  • hypershift-operator/controllers/nodepool/token.go
  • ignition-server/cmd/run_local_ignitionprovider.go
  • ignition-server/controllers/local_ignitionprovider.go
  • ignition-server/controllers/tokensecret_controller.go
  • ignition-server/controllers/tokensecret_controller_test.go

Comment thread hypershift-operator/controllers/nodepool/config.go
@twolff-gh

Copy link
Copy Markdown
Contributor Author

/test verify-deps

@twolff-gh
twolff-gh force-pushed the fix-ignition-cloud-config-hash-gate branch from b081c30 to 0760f42 Compare July 7, 2026 17:59

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
ignition-server/controllers/local_ignitionprovider_test.go (1)

1154-1177: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider adding OpenStack hash match/mismatch cases for symmetry.

The hash validation logic in writeCloudProviderConfig applies identically to both Azure and OpenStack (per local_ignitionprovider.go), but only Azure gets match/mismatch coverage here. Adding equivalent OpenStack cases would close the coverage gap for the same code path.

🤖 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 `@ignition-server/controllers/local_ignitionprovider_test.go` around lines 1154
- 1177, Add OpenStack hash validation coverage to the existing cloud config
tests in local_ignitionprovider_test.go so it mirrors the Azure cases. Extend
the table-driven cases around writeCloudProviderConfig to include both a
matching and mismatching cloudConfigHash for hyperv1.OpenStackPlatform, using
the same ConfigMap setup and expected write/error behavior, so the shared
hash-checking path in writeCloudProviderConfig is exercised for both providers.
ignition-server/controllers/tokensecret_controller.go (1)

278-278: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Avoid shadowing err inside the payload-generation closure.

Use distinct local names for the provider result/error to keep the control flow unambiguous.

Refactor to avoid shadowing
-		payload, err := r.IgnitionProvider.GetPayload(ctx, releaseImage, config.String(), pullSecretHash, additionalTrustBundleHash, hcConfigurationHash, cloudConfigHash)
-		if err != nil {
-			return nil, fmt.Errorf("error getting ignition payload: %w", err)
+		generatedPayload, providerErr := r.IgnitionProvider.GetPayload(ctx, releaseImage, config.String(), pullSecretHash, additionalTrustBundleHash, hcConfigurationHash, cloudConfigHash)
+		if providerErr != nil {
+			return nil, fmt.Errorf("error getting ignition payload: %w", providerErr)
 		}
 		duration := time.Since(start).Round(time.Second).Seconds()
 		log.Info("got ignition payload", "duration", duration)
 		PayloadGenerationSeconds.Observe(duration)
-		return payload, err
+		return generatedPayload, nil

As per coding guidelines, "**/*.go: Avoid variable shadowing."

🤖 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 `@ignition-server/controllers/tokensecret_controller.go` at line 278, Avoid
shadowing the outer err in the payload-generation closure by using distinct
local names for the result and error from IgnitionProvider.GetPayload in
tokensecret_controller.go. Update the closure that builds the payload so the
provider call assigns to new variables, then handle the error using that local
name before returning, keeping the control flow in the payload-generation path
unambiguous.

Source: Coding guidelines

🤖 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 `@hypershift-operator/controllers/nodepool/token.go`:
- Around line 365-371: The token Secret update in token.go can change the
cloud-config hash in place while keeping the same token ID, which lets the
ignition cache keep serving stale payloads. Update the token handling around the
tokenSecret.Data assignments in the token reconciliation path so cache entries
are keyed by the hash-bearing Secret data or are invalidated whenever
TokenSecretCloudConfigHashKey changes, and consider pairing the hash update with
token rotation to ensure fresh cloud.conf is served.

In `@ignition-server/controllers/tokensecret_controller.go`:
- Around line 275-278: The cached-token path in the token secret controller is
skipping the new cloud-config-hash validation, so update the cache-hit branch to
compare the current TokenSecretCloudConfigHashKey value before returning a
cached payload. In the token secret handling flow around cloudConfigHash and the
GetPayload call, make sure the same hash check runs for both cache misses and
cache hits so an in-place TokenSecret update cannot bypass validation.

---

Nitpick comments:
In `@ignition-server/controllers/local_ignitionprovider_test.go`:
- Around line 1154-1177: Add OpenStack hash validation coverage to the existing
cloud config tests in local_ignitionprovider_test.go so it mirrors the Azure
cases. Extend the table-driven cases around writeCloudProviderConfig to include
both a matching and mismatching cloudConfigHash for hyperv1.OpenStackPlatform,
using the same ConfigMap setup and expected write/error behavior, so the shared
hash-checking path in writeCloudProviderConfig is exercised for both providers.

In `@ignition-server/controllers/tokensecret_controller.go`:
- Line 278: Avoid shadowing the outer err in the payload-generation closure by
using distinct local names for the result and error from
IgnitionProvider.GetPayload in tokensecret_controller.go. Update the closure
that builds the payload so the provider call assigns to new variables, then
handle the error using that local name before returning, keeping the control
flow in the payload-generation path unambiguous.
🪄 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 YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: f0a4ff14-07f4-4310-a358-a2fbfcbacd29

📥 Commits

Reviewing files that changed from the base of the PR and between b081c30 and 0760f42.

📒 Files selected for processing (8)
  • hypershift-operator/controllers/nodepool/config.go
  • hypershift-operator/controllers/nodepool/config_test.go
  • hypershift-operator/controllers/nodepool/token.go
  • ignition-server/cmd/run_local_ignitionprovider.go
  • ignition-server/controllers/local_ignitionprovider.go
  • ignition-server/controllers/local_ignitionprovider_test.go
  • ignition-server/controllers/tokensecret_controller.go
  • ignition-server/controllers/tokensecret_controller_test.go
🚧 Files skipped from review as they are similar to previous changes (5)
  • ignition-server/controllers/tokensecret_controller_test.go
  • ignition-server/cmd/run_local_ignitionprovider.go
  • hypershift-operator/controllers/nodepool/config.go
  • hypershift-operator/controllers/nodepool/config_test.go
  • ignition-server/controllers/local_ignitionprovider.go

Comment thread hypershift-operator/controllers/nodepool/token.go
Comment thread ignition-server/controllers/tokensecret_controller.go Outdated
@twolff-gh
twolff-gh force-pushed the fix-ignition-cloud-config-hash-gate branch 3 times, most recently from 51be2af to 8d34581 Compare July 7, 2026 21:30
@codecov

codecov Bot commented Jul 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 80.18868% with 21 lines in your changes missing coverage. Please review.
✅ Project coverage is 44.15%. Comparing base (3eefe36) to head (077d180).
⚠️ Report is 28 commits behind head on main.

Files with missing lines Patch % Lines
...ition-server/controllers/tokensecret_controller.go 73.33% 5 Missing and 3 partials ⚠️
...erator/controllers/nodepool/nodepool_controller.go 74.07% 6 Missing and 1 partial ⚠️
hypershift-operator/controllers/nodepool/token.go 57.14% 2 Missing and 1 partial ⚠️
...ition-server/controllers/local_ignitionprovider.go 77.77% 2 Missing ⚠️
ignition-server/cmd/run_local_ignitionprovider.go 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8946      +/-   ##
==========================================
+ Coverage   44.13%   44.15%   +0.01%     
==========================================
  Files         772      779       +7     
  Lines       96260    98056    +1796     
==========================================
+ Hits        42488    43294     +806     
- Misses      50826    51729     +903     
- Partials     2946     3033      +87     
Files with missing lines Coverage Δ
hypershift-operator/controllers/nodepool/config.go 84.29% <100.00%> (+0.95%) ⬆️
ignition-server/controllers/cache.go 100.00% <ø> (ø)
support/util/util.go 46.07% <100.00%> (+4.02%) ⬆️
ignition-server/cmd/run_local_ignitionprovider.go 0.00% <0.00%> (ø)
...ition-server/controllers/local_ignitionprovider.go 39.53% <77.77%> (+0.50%) ⬆️
hypershift-operator/controllers/nodepool/token.go 82.15% <57.14%> (-0.56%) ⬇️
...erator/controllers/nodepool/nodepool_controller.go 44.43% <74.07%> (+1.08%) ⬆️
...ition-server/controllers/tokensecret_controller.go 67.82% <73.33%> (+8.64%) ⬆️

... and 9 files with indirect coverage changes

Flag Coverage Δ
cmd-support 38.29% <100.00%> (+0.02%) ⬆️
cpo-hostedcontrolplane 46.17% <ø> (ø)
cpo-other 45.21% <ø> (ø)
hypershift-operator 54.15% <79.59%> (+0.05%) ⬆️
other 33.84% <72.50%> (+1.65%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@enxebre

enxebre commented Jul 9, 2026

Copy link
Copy Markdown
Member

/approve

@openshift-ci

openshift-ci Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: enxebre, twolff-gh

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 Jul 9, 2026
@jparrill

jparrill commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

/retitle: ARO-24037: gate cloud config on hash to prevent serving stale content

@openshift-ci openshift-ci Bot changed the title fix(ignition): gate cloud config on hash to prevent serving stale content : ARO-24037: gate cloud config on hash to prevent serving stale content Jul 10, 2026
@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 10, 2026
@openshift-ci-robot

openshift-ci-robot commented Jul 10, 2026

Copy link
Copy Markdown

@twolff-gh: This pull request references ARO-24037 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the feature to target the "5.0.0" version, but no target version was set.

Details

In response to this:

Prevents stale cloud.conf from being served during the race between the CPO updating azure-cloud-config and the ignition server reading it.

Follows the existing pullSecretHash / additionalTrustBundleHash pattern: nodepool controller hashes the cloud config ConfigMap and stores it in the token secret; ignition server verifies the hash before writing cloud.conf, retrying on mismatch.

What this PR does / why we need it:

Which issue(s) this PR fixes:

Fixes https://redhat.atlassian.net/browse/ARO-24037

Related to #8865

Special notes for your reviewer:

Checklist:

  • Subject and description added to both, commit and PR.
  • Relevant issues have been referenced.
  • This change includes docs.
  • This change includes unit tests.

Summary by CodeRabbit

  • New Features

  • Added tracking of cloud provider configuration via a new cloud-config-hash value stored in token Secrets and propagated into ignition payload generation.

  • Ignition payload caching/reuse now records and considers this cloud configuration hash.

  • Bug Fixes

  • Azure/OpenStack ignition payloads now validate the retrieved cloud configuration content against the expected hash, preventing stale or out-of-date configuration.

  • Token secret reconciliation and payload cache invalidation are improved: payloads are regenerated when the cloud configuration hash changes.

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.

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

Dropped some comments. Thanks!

I've retitled the issue in order to fill the bot expectations

Comment thread hypershift-operator/controllers/nodepool/token.go
Comment thread support/util/util.go
@twolff-gh
twolff-gh force-pushed the fix-ignition-cloud-config-hash-gate branch from 86769f7 to 50e651b Compare July 14, 2026 15:49
@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
@twolff-gh
twolff-gh requested a review from jparrill July 14, 2026 22:06
@jparrill

Copy link
Copy Markdown
Contributor

/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label Jul 15, 2026
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-aks-4-22
/test e2e-aws-4-22
/test e2e-aks
/test e2e-aws
/test e2e-aws-upgrade-hypershift-operator
/test e2e-azure-v2-self-managed
/test e2e-kubevirt-aws-ovn-reduced
/test e2e-v2-aws
/test e2e-v2-gke

@jparrill

jparrill commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

/retitle ARO-24037: gate cloud config on hash to prevent serving stale content

@openshift-ci openshift-ci Bot changed the title : ARO-24037: gate cloud config on hash to prevent serving stale content ARO-24037: gate cloud config on hash to prevent serving stale content Jul 15, 2026
@jparrill

Copy link
Copy Markdown
Contributor

/label acknowledge-critical-fixes-only

@openshift-ci openshift-ci Bot added the acknowledge-critical-fixes-only Indicates if the issuer of the label is OK with the policy. label Jul 15, 2026
@hypershift-jira-solve-ci

hypershift-jira-solve-ci Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Test Failure Analysis Complete

Job Information

  • Prow Job: pull-ci-openshift-hypershift-main-e2e-aws-4-22
  • Build ID: 2077287664507162624
  • Target: e2e-aws-4-22
  • Result: 342 tests run, 20 skipped, 13 failures (6 unique top-level test failures)
  • Duration: 1h4m9s

Test Failure Analysis

Error

dial tcp: lookup api-{cluster}.service.ci.hypershift.devcluster.openshift.com on 172.30.0.10:53: no such host
Failed to wait for a successful connection to the guest API server in 10m0s: context deadline exceeded

Summary

All 13 hosted clusters created during the test run initially experienced ExternalDNS resolution failures (no such host) for their API server endpoints on the service.ci.hypershift.devcluster.openshift.com domain. Of these 13 clusters, 7 eventually recovered DNS resolution after ~2 minutes, while 6 never resolved within the 10-minute connection timeout. The 6 clusters that never recovered caused the failures in TestCreateCluster, TestCreateClusterHABreakGlassCredentials, TestNodePoolAutoscalingScaleFromZero, TestUpgradeControlPlane, TestKarpenterUpgradeControlPlane, and TestNodePool. The PR changes (ARO-24037: cloud config hash gating) only affect Azure/OpenStack platforms and are completely unrelated to AWS ExternalDNS behavior — this is a CI infrastructure flake.

Root Cause

This failure is caused by transient ExternalDNS / Route53 DNS propagation delays in the shared CI management cluster infrastructure, not by the PR changes.

Key evidence:

  1. All 13 hosted clusters created during the test run experienced the same no such host DNS lookup failure for their api-{name}.service.ci.hypershift.devcluster.openshift.com endpoints immediately after creation. This is a systemic issue affecting the entire test run, not specific to any test.

  2. 7 out of 13 clusters recovered DNS resolution after ~2 minutes (e.g., proxy-bzfqh resolved in 2m19s, autoscaling-wznfc in 1m59s) and their tests passed. The 6 clusters that never recovered within the 10-minute timeout caused all the test failures.

  3. The PR changes are irrelevant to this failure:

    • PR ARO-24037: gate cloud config on hash to prevent serving stale content #8946 adds cloud config hash gating for Azure and OpenStack platforms only
    • The GetCloudConfigHash() method returns an empty string for AWS (the platform used in this job)
    • The changes affect ignition server payload generation for worker node bootstrap, not ExternalDNS record creation or API server DNS resolution
    • No DNS, networking, ExternalDNS, or Route53 code paths are modified
  4. The failure pattern is characteristic of ExternalDNS propagation delays in the shared ci.hypershift.devcluster.openshift.com Route53 zone. When 20+ hosted clusters are created simultaneously (test parallelism = 20), ExternalDNS must create DNS records for all of them, and Route53 propagation is non-deterministic — some records propagate quickly while others are delayed.

  5. The failing clusters also showed downstream symptoms of DNS not resolving: NoWorkerNodesAvailable, ClusterOperatorsNotAvailable, ControlPlaneConnectionAvailable=False — all consequences of the hosted cluster API server being unreachable via its external DNS name.

Recommendations
  1. Rerun the job — this is a transient CI infrastructure flake related to ExternalDNS/Route53 propagation in the shared management cluster. A retry should succeed.

  2. This is not caused by the PR — the cloud config hash gating changes (ARO-24037) only apply to Azure/OpenStack platforms and do not modify any DNS, networking, or API server connectivity code paths. The PR is safe to merge once tests pass on retry.

  3. For persistent flakiness — if this pattern recurs frequently, the HyperShift CI team could consider:

    • Reducing test parallelism to decrease the burst of simultaneous DNS record creations
    • Increasing the guest API server connection timeout beyond 10 minutes
    • Adding retry logic with backoff for ExternalDNS record verification
Evidence
Evidence Detail
Failed tests TestCreateCluster, TestCreateClusterHABreakGlassCredentials, TestNodePoolAutoscalingScaleFromZero, TestUpgradeControlPlane, TestKarpenterUpgradeControlPlane, TestNodePool (6 unique)
Passing tests with same initial DNS error TestAutoscaling, TestCreateClusterCustomConfig, TestKarpenter, TestCreateClusterProxy, TestCreateClusterPrivate, TestCreateClusterPrivateWithRouteKAS, TestCreateClusterRequestServingIsolation (7 tests)
DNS error pattern lookup api-{name}.service.ci.hypershift.devcluster.openshift.com on 172.30.0.10:53: no such host — identical across all 13 clusters
Recovery time (passing tests) 1m59s – 2m44s for clusters that eventually resolved DNS
Timeout (failing tests) 10m0s — context deadline exceeded after exhausting guest API server connection timeout
PR scope 14 files changed, all in nodepool controller, ignition server, and support/util — Azure/OpenStack cloud config hash gating only
PR platform impact GetCloudConfigHash() returns empty string for AWS; hash validation skipped entirely on non-Azure/OpenStack platforms
Test parallelism 20 concurrent tests creating hosted clusters simultaneously
Total clusters created 13+ hosted clusters on service.ci.hypershift.devcluster.openshift.com domain

@twolff-gh

Copy link
Copy Markdown
Contributor Author

/test e2e-aws

@twolff-gh

Copy link
Copy Markdown
Contributor Author

/retest-required

@twolff-gh

Copy link
Copy Markdown
Contributor Author

/test e2e-azure-v2-self-managed

2 similar comments
@twolff-gh

Copy link
Copy Markdown
Contributor Author

/test e2e-azure-v2-self-managed

@twolff-gh

Copy link
Copy Markdown
Contributor Author

/test e2e-azure-v2-self-managed

…g stale content

- Add cloud config hash computation in NodePool config reconciliation
  using ConfigMap content from the HCP namespace
- Propagate cloud-config-hash through token secret data so the ignition
  server can validate content freshness before serving payloads
- Watch cloud config ConfigMaps (cloud-config, openshift-config-user-ca)
  for convergence before generating ignition tokens
- Add HashSimple utility in support/util for consistent content hashing

Signed-off-by: Todd Wolff <twolff@redhat.com>
Commit-Message-Assisted-by: Claude (via Claude Code)
…erver

- Add cloudConfigHash parameter to IgnitionProvider.GetPayload interface
  (appended after osStream to preserve existing parameter positions)
- Gate ignition payload generation on cloud config hash match in
  LocalIgnitionProvider, returning an error when the ConfigMap is stale
- Invalidate cached payloads when cloud config hash changes by storing
  the hash in CacheValue and comparing on reconciliation
- Report CloudConfigPending reason on token secret when hash validation
  fails so NodePool controller can observe convergence state

Signed-off-by: Todd Wolff <twolff@redhat.com>
Commit-Message-Assisted-by: Claude (via Claude Code)
@twolff-gh
twolff-gh force-pushed the fix-ignition-cloud-config-hash-gate branch from 6a66d36 to 077d180 Compare July 16, 2026 16:19
@openshift-ci openshift-ci Bot removed the lgtm Indicates that a PR is ready to be merged. label Jul 16, 2026
@twolff-gh

Copy link
Copy Markdown
Contributor Author

New changes are detected. LGTM label has been removed.
@jparrill
Fixed merge conflicts and ran restructure-commits. Had to force push

@jparrill

Copy link
Copy Markdown
Contributor

/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label Jul 17, 2026
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-aks-4-22
/test e2e-aws-4-22
/test e2e-aks
/test e2e-aws
/test e2e-aws-upgrade-hypershift-operator
/test e2e-azure-v2-self-managed
/test e2e-kubevirt-aws-ovn-reduced
/test e2e-v2-aws
/test e2e-v2-gke

@twolff-gh

Copy link
Copy Markdown
Contributor Author

/retest

@twolff-gh

Copy link
Copy Markdown
Contributor Author

/retest-required

2 similar comments
@twolff-gh

Copy link
Copy Markdown
Contributor Author

/retest-required

@twolff-gh

Copy link
Copy Markdown
Contributor Author

/retest-required

@openshift-ci

openshift-ci Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

@twolff-gh: 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

acknowledge-critical-fixes-only Indicates if the issuer of the label is OK with the policy. approved Indicates a PR has been approved by an approver from all required OWNERS files. area/control-plane-operator Indicates the PR includes changes for the control plane operator - in an OCP release area/hypershift-operator Indicates the PR includes changes for the hypershift operator and API - outside an OCP release jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lgtm Indicates that a PR is ready to be merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants