Skip to content

OCPBUGS-90560: Resolve GCP boot image from worker machines#1512

Open
nader-ziada wants to merge 2 commits into
openshift:mainfrom
nader-ziada:fix-gcp-boot-image
Open

OCPBUGS-90560: Resolve GCP boot image from worker machines#1512
nader-ziada wants to merge 2 commits into
openshift:mainfrom
nader-ziada:fix-gcp-boot-image

Conversation

@nader-ziada

@nader-ziada nader-ziada commented Jun 23, 2026

Copy link
Copy Markdown

Instead of hardcoding a stale RHCOS 4.14 boot disk image for GCP defaults, resolve the image dynamically from existing worker machines at webhook startup. Falls back to the hardcoded default when no workers are found. Filters by architecture (x86-64/aarch64) to avoid selecting the wrong image on mixed-arch clusters.

Introduces ResolveDefaulterConfig() so both Machine and MachineSet defaulters share a single client and boot image resolution call.

Summary by CodeRabbit

  • New Features
    • Improved GCP boot disk defaulting for both Machine and MachineSet webhooks by selecting the most appropriate boot image using architecture-aware matching, with automatic fallback to existing defaults when no match is available.
  • Refactor
    • Updated webhook defaulting to use a shared, configuration-driven setup so Machine and MachineSet behave consistently.
  • Tests
    • Expanded unit test coverage for GCP boot image resolution (including architecture selection), resolved-image defaulting, and fallback behavior across both webhooks.

@openshift-ci-robot openshift-ci-robot added jira/severity-important Referenced Jira bug's severity is important for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. labels Jun 23, 2026
@openshift-ci-robot

Copy link
Copy Markdown
Contributor

@nader-ziada: This pull request references Jira Issue OCPBUGS-90560, which is invalid:

  • expected the bug to target the "5.0.0" version, but no target version was set

Comment /jira refresh to re-evaluate validity if changes to the Jira bug are made, or edit the title of this pull request to link to a different bug.

The bug has been updated to refer to the pull request using the external bug tracker.

Details

In response to this:

Instead of hardcoding a stale RHCOS 4.14 boot disk image for GCP defaults, resolve the image dynamically from existing worker machines at webhook startup. Falls back to the hardcoded default when no workers are found. Filters by architecture (x86-64/aarch64) to avoid selecting the wrong image on mixed-arch clusters.

Introduces ResolveDefaulterConfig() so both Machine and MachineSet defaulters share a single client and boot image resolution call.

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.

@openshift-ci

openshift-ci Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

[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 joelspeed 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 commented Jun 23, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: 85494c31-9a84-4120-acd5-859df749eeb3

📥 Commits

Reviewing files that changed from the base of the PR and between 41d5f0b and d6c686f.

⛔ Files ignored due to path filters (8)
  • go.sum is excluded by !**/*.sum
  • vendor/github.com/coreos/stream-metadata-go/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/coreos/stream-metadata-go/arch/arch.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/coreos/stream-metadata-go/stream/artifact_utils.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/coreos/stream-metadata-go/stream/rhcos/rhcos.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/coreos/stream-metadata-go/stream/stream.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/coreos/stream-metadata-go/stream/stream_utils.go is excluded by !**/vendor/**, !vendor/**
  • vendor/modules.txt is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (5)
  • go.mod
  • pkg/webhooks/machine_webhook.go
  • pkg/webhooks/machine_webhook_test.go
  • pkg/webhooks/machineset_webhook.go
  • pkg/webhooks/machineset_webhook_test.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • go.mod
  • pkg/webhooks/machineset_webhook_test.go
  • pkg/webhooks/machine_webhook.go

Walkthrough

Adds shared webhook defaulter configuration containing platform status, cluster ID, and boot image stream data. Machine and MachineSet GCP defaulting selects architecture-specific images from that stream and falls back to the existing static image. Startup wiring and tests are updated for configuration injection.

Changes

GCP boot image configuration and Machine defaulting

Layer / File(s) Summary
Shared defaulter configuration
pkg/webhooks/machine_webhook.go, pkg/webhooks/machineset_webhook.go, cmd/machineset/main.go, go.mod
Resolves platform and cluster data, loads coreos-bootimages stream metadata, and injects shared configuration into Machine and MachineSet webhook construction.
Machine GCP disk selection
pkg/webhooks/machine_webhook.go, pkg/webhooks/machine_webhook_test.go
Derives architecture, selects the matching stream image, applies it to missing boot disk images, and retains the static fallback with focused tests.
MachineSet GCP disk selection
pkg/webhooks/machineset_webhook.go, pkg/webhooks/machineset_webhook_test.go
Passes stream metadata through MachineSet admission configuration and tests resolved-image and fallback behavior.

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

Sequence Diagram(s)

sequenceDiagram
  participant WebhookStartup
  participant ResolveDefaulterConfig
  participant BootImagesConfigMap
  participant MachineDefaulter
  participant MachineSetDefaulter
  WebhookStartup->>ResolveDefaulterConfig: resolve shared defaulter configuration
  ResolveDefaulterConfig->>BootImagesConfigMap: load coreos-bootimages stream data
  BootImagesConfigMap-->>ResolveDefaulterConfig: return stream payload
  ResolveDefaulterConfig-->>WebhookStartup: return DefaulterConfig
  WebhookStartup->>MachineDefaulter: construct with DefaulterConfig
  WebhookStartup->>MachineSetDefaulter: construct with DefaulterConfig
Loading

Suggested reviewers: theobarberbany

🚥 Pre-merge checks | ✅ 13 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title mentions resolving from worker machines, but the changes switch defaulting to the coreos-bootimages ConfigMap instead. Rename it to describe the actual change, e.g. "Resolve GCP boot image from coreos-bootimages ConfigMap".
Docstring Coverage ⚠️ Warning Docstring coverage is 9.38% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (13 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
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 No Ginkgo titles or subtest names in the modified tests include dynamic values; added names are static and descriptive.
Test Structure And Quality ✅ Passed PASS: The added tests are focused unit tests, use table-driven subtests, clean up created resources in existing integration tests, and add clear failure messages; no new indefinite waits.
Microshift Test Compatibility ✅ Passed The added tests are plain testing.T unit tests, not Ginkgo e2e specs, and none reference MicroShift-unsupported OpenShift APIs.
Single Node Openshift (Sno) Test Compatibility ✅ Passed PASS: The added coverage is plain Go unit tests (Test* with Gomega), not Ginkgo e2e specs, and shows no SNO/multi-node assumptions.
Topology-Aware Scheduling Compatibility ✅ Passed PASS: The PR only changes webhook defaulting/config resolution; no node selectors, anti-affinity, replicas, or topology spread constraints were added.
Ote Binary Stdout Contract ✅ Passed Changed main/TestMain paths use stderr-safe logging; no fmt.Print/Stdout writes were added in process-level code.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed The PR adds Go unit tests only; no Ginkgo e2e tests or IPv4/external-network assumptions were introduced.
No-Weak-Crypto ✅ Passed No MD5/SHA1/DES/RC4/3DES/Blowfish/ECB, custom crypto, or secret/token comparisons were added; changes are boot-image and webhook wiring only.
Container-Privileges ✅ Passed PR only changes Go code/deps; no K8s manifests or privilege flags (privileged, hostNetwork, hostIPC, allowPrivilegeEscalation, SYS_ADMIN) appear in touched files.
No-Sensitive-Data-In-Logs ✅ Passed Changed logs only mention ConfigMap names, arch, and boot-image fallback paths; no secrets, tokens, PII, hostnames, or customer data found.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions
The command is terminated due to an error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions


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

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

🤖 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 `@pkg/webhooks/machine_webhook_test.go`:
- Line 6805: The TestResolveGCPBootImage test cases have hardcoded expected and
mismatch image values that are specific to x86-64 architecture, but the
resolveGCPBootImage function filters results by the arch parameter. Make the
test architecture-aware by parameterizing the expected image assertions based on
the architecture being tested (such as by deriving expected images from the arch
field in each test case) so that assertions pass for both x86-64 and ARM64
architectures. This should be applied to all the test cases mentioned at the
specified line ranges.
- Line 6827: In the machine_webhook_test.go file, the json.Marshal calls at
lines 6827, 6857, 6887, 6911, and 6941 are currently ignoring errors by using
blank identifier (_). Instead of discarding the error, capture it in a variable
and check for non-nil errors. When json.Marshal fails, the test should fail
immediately using the testing.T helper (commonly using t.Fatalf or t.Errorf) to
prevent invalid ProviderSpec payloads from being silently used in the test
fixtures. This ensures test reliability and follows the project guideline of
never ignoring error returns in Go files.

In `@pkg/webhooks/machine_webhook.go`:
- Around line 354-366: The function resolveGCPBootImage currently treats all
List API failures as "no image found" by returning an empty string, which masks
RBAC and API outages. Modify resolveGCPBootImage to return both a string and an
error instead of just a string. When the c.List() call fails in the error
handling block, return the actual error along with an empty string rather than
silently returning an empty string. Reserve the empty string return for
successful list operations that find no matching worker machines. Additionally,
replace context.Background() with a context that supports cancellation and
timeouts, such as one derived from a timeout or cancellation mechanism
appropriate to your codebase standards.
- Around line 378-379: The loop iterating over providerSpec.Disks dereferences
each disk element without checking if it is nil, which will cause a panic if the
slice contains nil elements. Add a nil guard check inside the for loop that
iterates over providerSpec.Disks to ensure each disk is not nil before accessing
its Boot and Image fields.
- Around line 378-380: In the disk iteration loop where you check disk.Boot and
disk.Image, replace the strings.Contains call with strings.HasSuffix to ensure
the architecture suffix matches exactly at the end of the image path rather than
anywhere within it. This prevents accidentally selecting the wrong image variant
if the suffix text appears elsewhere in the image path.
🪄 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: 4245399b-3c94-4d86-a8ab-a45017c1c659

📥 Commits

Reviewing files that changed from the base of the PR and between d7772c6 and fef4618.

📒 Files selected for processing (5)
  • cmd/machineset/main.go
  • pkg/webhooks/machine_webhook.go
  • pkg/webhooks/machine_webhook_test.go
  • pkg/webhooks/machineset_webhook.go
  • pkg/webhooks/machineset_webhook_test.go

Comment thread pkg/webhooks/machine_webhook_test.go Outdated
Comment thread pkg/webhooks/machine_webhook_test.go Outdated
Comment thread pkg/webhooks/machine_webhook.go Outdated
Comment thread pkg/webhooks/machine_webhook.go Outdated
Comment thread pkg/webhooks/machine_webhook.go Outdated
Instead of hardcoding a stale RHCOS 4.14 boot disk image for GCP
defaults, resolve the image dynamically from existing worker machines
at webhook startup. Falls back to the hardcoded default when no workers
are found. Filters by architecture (x86-64/aarch64) to avoid selecting
the wrong image on mixed-arch clusters.

Introduces ResolveDefaulterConfig() so both Machine and MachineSet
defaulters share a single client and boot image resolution call.
@nader-ziada

Copy link
Copy Markdown
Author

/retest

@theobarberbany

Copy link
Copy Markdown
Contributor

/pipeline auto

@theobarberbany

Copy link
Copy Markdown
Contributor

/test ?

@theobarberbany

Copy link
Copy Markdown
Contributor

/test e2e-gcp-ovn
/test e2e-gcp-operator

@nader-ziada

Copy link
Copy Markdown
Author

/retest

@nader-ziada

Copy link
Copy Markdown
Author

@theobarberbany all the tests passed, is there other specific tests to kick off?

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

This is quite an old code. And there has been work in this area that we could leverage. (4.19+ GA). I think we can reuse the coreos-bootimages configmap for the images used in defaulting. This is already used to update MachineSet Images on AWS and GCP. Other platforms I am unsure of the status but generic solution where we can add platforms later on would be great.

---AI
The MCO's golden ConfigMap coreos-bootimages in openshift-machine-config-operator is the canonical source of truth for boot images. Key properties:

  • Updated by the CVO during upgrades, so it always matches the release payload
  • Multi-platform: Contains images for GCP, AWS, Azure, vSphere — organized by architecture and platform
  • Structured data: The stream key contains JSON structured as .architectures..images..

For GCP specifically, the MCO BIC already reads it like this:go
newBootImage := fmt.Sprintf("projects/%s/global/images/%s",
streamData.Architectures[arch].Images.Gcp.Project,
streamData.Architectures[arch].Images.Gcp.Name)

If the webhook defaulter read from this ConfigMap instead of using a hardcoded value, you would:

  1. Eliminate the staleness problem entirely — the default always matches the current release
  2. Get a solution that generalizes to all platforms (AWS AMIs per region, Azure URNs, etc.)
  3. Align the webhook with the same source of truth the MCO already uses
  4. Avoid the indirection of "look at what workers happen to have" which the current PR does
    --AI

Comment thread pkg/webhooks/machine_webhook.go Outdated

func resolveGCPBootImage(c client.Client) string {
archSuffix := "x86-64"
if arch == ARM64 {

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.

arch is the webhook pod arch not the machine you are defaulting.

Comment thread pkg/webhooks/machine_webhook.go Outdated
archSuffix = "aarch64"
}

machineList := &machinev1beta1.MachineList{}

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.

MachineSets images are being updated by MCO's Boot Image Controller. So they are better source if we stick to this approach.

Comment thread pkg/webhooks/machine_webhook.go Outdated

machineList := &machinev1beta1.MachineList{}
if err := c.List(context.Background(), machineList,
client.InNamespace(defaultSecretNamespace),

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.

defaultSecretNamespace?

Comment thread pkg/webhooks/machine_webhook.go Outdated
dnsDisconnected bool
client client.Client
featureGates featuregate.MutableFeatureGate
gcpBootImage string

@RadekManak RadekManak Jul 23, 2026

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.

Having one platform image here is a code smell. This is generic struct. With platform field added on onto it which is useless on all platforms but GCP. Either make it generic or another solution entirely.

@openshift-ci-robot

Copy link
Copy Markdown
Contributor

@nader-ziada: This pull request references Jira Issue OCPBUGS-90560, which is invalid:

  • expected the bug to target the "5.0.0" version, but no target version was set
  • expected the bug to be in one of the following states: NEW, ASSIGNED, POST, but it is MODIFIED instead

Comment /jira refresh to re-evaluate validity if changes to the Jira bug are made, or edit the title of this pull request to link to a different bug.

Details

In response to this:

Instead of hardcoding a stale RHCOS 4.14 boot disk image for GCP defaults, resolve the image dynamically from existing worker machines at webhook startup. Falls back to the hardcoded default when no workers are found. Filters by architecture (x86-64/aarch64) to avoid selecting the wrong image on mixed-arch clusters.

Introduces ResolveDefaulterConfig() so both Machine and MachineSet defaulters share a single client and boot image resolution call.

Summary by CodeRabbit

  • New Features
  • Improved GCP boot disk defaulting for both Machine and MachineSet webhooks by resolving the most appropriate boot image using architecture-aware matching, with automatic fallback to existing hardcoded defaults when no match is found.
  • Refactor
  • Updated webhook defaulter setup to use a shared, configuration-driven approach so Machine and MachineSet defaulting behave consistently.
  • Tests
  • Expanded unit test coverage for GCP boot image resolution, resolved-image defaulting, and fallback behavior across both webhooks, including architecture selection logic.

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.

@nader-ziada

Copy link
Copy Markdown
Author

hello @RadekManak, tried to follow a similar approach to MCO. would appreciate another review

    resolve GCP boot image from coreos-bootimages ConfigMap
    
    Replace worker-machine-based boot image resolution with reading the
    coreos-bootimages ConfigMap from openshift-machine-config-operator,
    the canonical source updated by CVO on upgrades.
    
    - Store *stream.Stream in admissionConfig instead of platform-specific
      gcpBootImage string, making the approach generic across platforms
    - Detect target machine architecture via annotation with pod arch
      fallback, matching MCO's Boot Image Controller pattern
    - Fall back to hardcoded defaults if ConfigMap is unavailable

@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 `@go.mod`:
- Line 119: Remove the stale // indirect marker from the
github.com/coreos/stream-metadata-go dependency in go.mod, making it a direct
dependency while preserving its existing version.
🪄 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: 1d96524d-ecda-4d6f-89f1-23970646cc54

📥 Commits

Reviewing files that changed from the base of the PR and between 8389bf4 and 41d5f0b.

⛔ Files ignored due to path filters (8)
  • go.sum is excluded by !**/*.sum
  • vendor/github.com/coreos/stream-metadata-go/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/coreos/stream-metadata-go/arch/arch.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/coreos/stream-metadata-go/stream/artifact_utils.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/coreos/stream-metadata-go/stream/rhcos/rhcos.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/coreos/stream-metadata-go/stream/stream.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/coreos/stream-metadata-go/stream/stream_utils.go is excluded by !**/vendor/**, !vendor/**
  • vendor/modules.txt is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (5)
  • go.mod
  • pkg/webhooks/machine_webhook.go
  • pkg/webhooks/machine_webhook_test.go
  • pkg/webhooks/machineset_webhook.go
  • pkg/webhooks/machineset_webhook_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/webhooks/machineset_webhook_test.go

Comment thread go.mod Outdated
Replace worker-machine-based boot image resolution with reading the
coreos-bootimages ConfigMap from openshift-machine-config-operator,
the canonical source updated by CVO on upgrades.

- Store *stream.Stream in admissionConfig instead of platform-specific
  gcpBootImage string, making the approach generic across platforms
- Detect target machine architecture via annotation with pod arch
  fallback, matching MCO's Boot Image Controller pattern
- Fall back to hardcoded defaults if ConfigMap is unavailable

Signed-off-by: Nader Ziada <nziada@redhat.com>
@openshift-ci

openshift-ci Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

@nader-ziada: 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/e2e-aws-ovn-upgrade d6c686f link true /test e2e-aws-ovn-upgrade
ci/prow/e2e-metal-ipi-virtualmedia d6c686f link true /test e2e-metal-ipi-virtualmedia
ci/prow/e2e-metal-ipi-ovn-ipv6 d6c686f link true /test e2e-metal-ipi-ovn-ipv6
ci/prow/e2e-metal-ipi d6c686f link true /test e2e-metal-ipi

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/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. jira/severity-important Referenced Jira bug's severity is important for the branch this PR is targeting. 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.

4 participants