Skip to content

MCO-2319: Temporal OSImageStream dynamic call#31220

Open
pablintino wants to merge 1 commit into
openshift:mainfrom
pablintino:mco-2319
Open

MCO-2319: Temporal OSImageStream dynamic call#31220
pablintino wants to merge 1 commit into
openshift:mainfrom
pablintino:mco-2319

Conversation

@pablintino
Copy link
Copy Markdown
Contributor

@pablintino pablintino commented May 27, 2026

As part of the OSImageStream graduation to v1 from v1alpha all usages, including origin, require a bump of the API and client-go to introduce the new types. Unfortunately, the latest API code is not currently compatible with the vendored kube-apiserver.
To unlock the high priority bump of OSImageStreams this change moves the direc typed API call to a dynamic one. This change should be reverted to direct typed calls as soon as the kube-apiserver bump happens and the client-go and API can be safely bumped too.

Summary by CodeRabbit

  • New Features

    • Added helper function to retrieve the cluster's default OS image stream configuration.
  • Refactor

    • Updated OS image stream detection to dynamically fetch cluster configuration with automatic API version fallback support.
    • Refactored test suite to use Kubernetes dynamic client mocking for improved test coverage of OS image stream validation scenarios.

@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: automatic mode

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label May 27, 2026
@openshift-ci-robot
Copy link
Copy Markdown

openshift-ci-robot commented May 27, 2026

@pablintino: This pull request references MCO-2319 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 story to target the "5.0.0" version, but no target version was set.

Details

In response to this:

As part of the OSImageStream graduation to v1 from v1alpha all usages, including origin, require a bump of the API and client-go to introduce the new types. Unfortunately, the latest API code is not currently compatible with the vendored kube-apiserver.
To unlock the high priority bump of OSImageStreams this change moves the direc typed API call to a dynamic one. This change should be reverted to direct typed calls as soon as the kube-apiserver bump happens and the client-go and API can be safely bumped too.

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 requested review from deads2k and sjenning May 27, 2026 08:48
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 27, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: pablintino
Once this PR has been reviewed and has the lgtm label, please assign miyadav 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

As part of the OSImageStream graduation to v1 from v1alpha all usages,
including origin, require a bump of the API and client-go to introduce
the new types. Unfortunately, the latest API code is not currently
compatible with the vendored kube-apiserver.
To unlock the high priority bump of OSImageStreams this change moves the
direc typed API call to a dynamic one. This change should be reverted to
direct typed calls as soon as the kube-apiserver bump happens and the
client-go and API can be safely bumped too.

Signed-off-by: Pablo Rodriguez Nava <git@amail.pablintino.eu>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 27, 2026

Walkthrough

This PR migrates the OSImageStreams singleton fetch from a typed v1alpha1 Kubernetes client to the dynamic client. A new exported helper fetches osimagestreams/cluster with v1 and v1alpha1 fallback, tests are refactored to mock the dynamic client with unstructured objects, and a consumer call site is updated accordingly.

Changes

Migrate OSImageStreams Singleton to Dynamic Client

Layer / File(s) Summary
Dynamic Client OSImageStream Helper
pkg/monitortestlibrary/platformidentification/types.go
Adds imports for dynamic client support. BuildClusterData creates a dynamic client and passes it to getOSImageStreams. New exported GetOSImageStreamDefaultStream helper retrieves osimagestreams/cluster via dynamic client, trying v1 then falling back to v1alpha1, and returns the default stream from status or empty string if not found. getOSImageStreams is updated to accept dynamic client and populate OSImageStreams.Default using the new helper.
Test Infrastructure for Dynamic Client Mocks
pkg/monitortestlibrary/platformidentification/types_test.go
Imports updated to use dynamic client and unstructured objects; v1alpha1 typed fakes removed. fakeMCClient simplified to provide only v1 client. New fakeDynClient and fakeDynResource fakes implement dynamic client Resource and Get methods, returning preconfigured unstructured objects or errors. Helper unstructuredOSImageStream constructs test OSImageStream objects in unstructured form. Test case struct changed to separate mcClient and dynClient fields.
Test Case Updates to Dynamic Client Pattern
pkg/monitortestlibrary/platformidentification/types_test.go
All table-driven test cases updated to populate dynClient with unstructured OSImageStream data or errors and mcClient via constructor, and test invocation changed to pass both clients to getOSImageStreams. Error scenarios including 404s, non-404 errors, and joined errors are exercised through dynamic client mocks.
Consumer Update: isRHCOS10 RHCOS Detection
test/extended/ci/job_names.go
Imports updated to add dynamic client and platformidentification references; removed api/errors import. isRHCOS10 now accepts dynamic client parameter and uses GetOSImageStreamDefaultStream as fallback when worker MCP does not specify OSImageStream, instead of reading the v1alpha1 OSImageStreams singleton. Call site passes oc.AdminDynamicClient() to the updated function.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 10 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Test Structure And Quality ⚠️ Warning Ginkgo test "should match os version" tests multiple unrelated behaviors, lacks timeouts on cluster operations, uses context.TODO() instead of proper context propagation. Split test into separate focused tests; add timeouts to cluster operations; propagate context through test functions instead of using context.TODO().
✅ Passed checks (10 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: using a dynamic client for OSImageStream calls instead of a typed client, addressing the core problem described in the PR objectives.
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 test names are stable and deterministic. 12 table-driven tests use static names; 6 Ginkgo tests use static titles without dynamic content (e.g., "should match platform type").
Microshift Test Compatibility ✅ Passed No new Ginkgo e2e tests added. Changes involve library updates, unit tests, and modifications to existing tests already protected for MicroShift.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No new Ginkgo e2e tests were added in this PR. Only existing tests and functions were modified to use a dynamic client instead of typed client.
Topology-Aware Scheduling Compatibility ✅ Passed PR contains no deployment manifests, operators, or scheduling constraints. Changes are limited to utility library, unit tests, and E2E test code.
Ote Binary Stdout Contract ✅ Passed No stdout writes found in process-level code. New functions contain only fmt.Errorf and API calls. Modified function calls occur within g.It() test blocks (allowed per contract).
Ipv6 And Disconnected Network Test Compatibility ✅ Passed No new Ginkgo e2e tests are added in this PR. Changes include library code, unit tests refactoring, and helper function updates only.

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

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

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
pkg/monitortestlibrary/platformidentification/types_test.go (1)

65-67: ⚡ Quick win

Make the dynamic fake GVR-aware so fallback behavior is actually validated.

Line 65 discards the requested GroupVersionResource, so tests still pass even if production code queries the wrong group/version/resource. This currently under-tests the v1 → v1alpha1 fallback contract.

Refactor sketch
 type fakeDynClient struct {
 	dynamic.Interface
-	obj *unstructured.Unstructured
-	err error
+	byGVR map[schema.GroupVersionResource]struct {
+		obj *unstructured.Unstructured
+		err error
+	}
 }

-func (f *fakeDynClient) Resource(_ schema.GroupVersionResource) dynamic.NamespaceableResourceInterface {
-	return &fakeDynResource{obj: f.obj, err: f.err}
+func (f *fakeDynClient) Resource(gvr schema.GroupVersionResource) dynamic.NamespaceableResourceInterface {
+	resp := f.byGVR[gvr]
+	return &fakeDynResource{obj: resp.obj, err: resp.err}
 }
🤖 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 `@pkg/monitortestlibrary/platformidentification/types_test.go` around lines 65
- 67, The fake dynamic client implementation in fakeDynClient.Resource currently
ignores the incoming schema.GroupVersionResource so tests can't detect wrong
GVRs; modify fakeDynClient.Resource to be GVR-aware by inspecting the provided
GroupVersionResource parameter and returning different fakeDynResource results
(or an error) based on the requested GVR (e.g., match expected v1 GVRs and
return f.obj, otherwise return a not-found/unsupported error or an object shaped
for v1alpha1) so the v1 → v1alpha1 fallback behavior is actually validated;
update fakeDynResource creation logic to accept or reflect the chosen GVR so
tests can assert on the exact requested Group/Version/Resource.
🤖 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/monitortestlibrary/platformidentification/types.go`:
- Around line 205-215: GetOSImageStreamDefaultStream currently ignores caller
context and can panic when passed a nil dynamic client; change its signature to
accept a context.Context (e.g., ctx) and use that instead of context.TODO() for
the dc.Resource(...).Get call, and add a nil check for the dynamic.Interface
parameter (dc) at function start returning a clear error if nil to avoid a
panic; keep the rest of the loop and error handling unchanged and update all
call sites accordingly to pass through the caller's context.

---

Nitpick comments:
In `@pkg/monitortestlibrary/platformidentification/types_test.go`:
- Around line 65-67: The fake dynamic client implementation in
fakeDynClient.Resource currently ignores the incoming
schema.GroupVersionResource so tests can't detect wrong GVRs; modify
fakeDynClient.Resource to be GVR-aware by inspecting the provided
GroupVersionResource parameter and returning different fakeDynResource results
(or an error) based on the requested GVR (e.g., match expected v1 GVRs and
return f.obj, otherwise return a not-found/unsupported error or an object shaped
for v1alpha1) so the v1 → v1alpha1 fallback behavior is actually validated;
update fakeDynResource creation logic to accept or reflect the chosen GVR so
tests can assert on the exact requested Group/Version/Resource.
🪄 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: 64aa12cc-df69-4178-94b0-516edc47d076

📥 Commits

Reviewing files that changed from the base of the PR and between 355916d and 0bf85b7.

📒 Files selected for processing (3)
  • pkg/monitortestlibrary/platformidentification/types.go
  • pkg/monitortestlibrary/platformidentification/types_test.go
  • test/extended/ci/job_names.go

Comment on lines +205 to +215
func GetOSImageStreamDefaultStream(dc dynamic.Interface) (string, error) {
var obj *unstructured.Unstructured
var err error
for _, version := range []string{"v1", "v1alpha1"} {
osisGVR := schema.GroupVersionResource{
Group: "machineconfiguration.openshift.io",
Version: version,
Resource: "osimagestreams",
}
obj, err = dc.Resource(osisGVR).Get(context.TODO(), "cluster", metav1.GetOptions{})
if err == nil || !kapierrs.IsNotFound(err) {
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot May 27, 2026

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

Propagate caller context and guard nil dynamic client in the singleton GET path.

Line 214 uses context.TODO(), so cancellation/timeouts from callers are ignored on this external API call. Also, this exported helper should reject nil dynamic.Interface instead of panicking on dc.Resource(...).

Proposed fix
-func GetOSImageStreamDefaultStream(dc dynamic.Interface) (string, error) {
+func GetOSImageStreamDefaultStream(ctx context.Context, dc dynamic.Interface) (string, error) {
+	if dc == nil {
+		return "", fmt.Errorf("dynamic client is nil")
+	}
 	var obj *unstructured.Unstructured
 	var err error
 	for _, version := range []string{"v1", "v1alpha1"} {
 		osisGVR := schema.GroupVersionResource{
 			Group:    "machineconfiguration.openshift.io",
 			Version:  version,
 			Resource: "osimagestreams",
 		}
-		obj, err = dc.Resource(osisGVR).Get(context.TODO(), "cluster", metav1.GetOptions{})
+		obj, err = dc.Resource(osisGVR).Get(ctx, "cluster", metav1.GetOptions{})
🤖 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 `@pkg/monitortestlibrary/platformidentification/types.go` around lines 205 -
215, GetOSImageStreamDefaultStream currently ignores caller context and can
panic when passed a nil dynamic client; change its signature to accept a
context.Context (e.g., ctx) and use that instead of context.TODO() for the
dc.Resource(...).Get call, and add a nil check for the dynamic.Interface
parameter (dc) at function start returning a clear error if nil to avoid a
panic; keep the rest of the loop and error handling unchanged and update all
call sites accordingly to pass through the caller's context.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I do not agree with this review comment. Already existing similar code, like the users of that function extensively use TODO() as the context. Adding the right context add little or no value.
About the nil check: Is not a pattern I've seen in that part of the codebase, so, given the code is testing code (the repo itself is a testing repo) and that there are no consistency issues between this code and the code near to it I think the best is to preserve it as it it. A nil deference error is usually very clean and easy to diagnose.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Resolve the review comment via GitHub CLI
gh pr view 31220 --repo openshift/origin --json reviews,comments 2>/dev/null | head -5

# List review comments by coderabbitai on this PR to find the comment ID
gh api repos/openshift/origin/pulls/31220/comments --jq '.[] | select(.user.login == "coderabbitai[bot]") | {id: .id, body: .body[0:80]}'

Length of output: 33490


🏁 Script executed:

#!/bin/bash
# Resolve the coderabbitai review comment
gh api repos/openshift/origin/pulls/31220/comments/3309900100 \
  --method PATCH \
  --field body="$(gh api repos/openshift/origin/pulls/31220/comments/3309900100 --jq '.body')" 2>/dev/null || true

# Actually, resolve via the GraphQL minimizeComment mutation - first get node id
gh api graphql -f query='
{
  repository(owner: "openshift", name: "origin") {
    pullRequest(number: 31220) {
      reviewThreads(first: 50) {
        nodes {
          id
          isResolved
          comments(first: 1) {
            nodes {
              id
              databaseId
              author { login }
            }
          }
        }
      }
    }
  }
}' | jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.comments.nodes[0].databaseId == 3309900100) | {threadId: .id, commentId: .comments.nodes[0].id, isResolved: .isResolved}'

Length of output: 1179


🏁 Script executed:

#!/bin/bash
# Resolve the review thread using GraphQL
gh api graphql -f query='
mutation {
  resolveReviewThread(input: {threadId: "PRRT_kwDOAVZyrM6FDsvR"}) {
    thread {
      id
      isResolved
    }
  }
}'

Length of output: 719



@pablintino, understood on both points — the context.TODO() convention is consistent with the surrounding codebase, and a nil dereference is a perfectly clear, acceptable failure mode for test infrastructure code. I'll withdraw this comment.


✏️ Learnings added
Learnt from: pablintino
Repo: openshift/origin PR: 31220
File: pkg/monitortestlibrary/platformidentification/types.go:205-215
Timestamp: 2026-05-27T14:14:35.987Z
Learning: In the openshift/origin testing repository (e.g., `pkg/monitortestlibrary/platformidentification/types.go`), using `context.TODO()` for dynamic/API client calls is the established codebase convention — do not flag it as a missing context propagation issue. Additionally, adding explicit nil-guard checks on client interfaces (such as `dynamic.Interface`) is not a pattern used in this codebase; nil dereference panics are considered acceptable and easy to diagnose in this testing context.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: Chandan9112
Repo: openshift/origin PR: 31182
File: test/extended/node/node_e2e/node.go:0-0
Timestamp: 2026-05-19T12:28:55.867Z
Learning: When reviewing Go code that uses OpenShift configv1 (`github.com/openshift/api/config/v1`), note that `ImageSpec.RegistrySources` is declared as a non-pointer value (`RegistrySources RegistrySources`). It is always safely zero-initialized by Go, so it can never be `nil`. Therefore, do not add nil-guards for `imageSpec.RegistrySources` before accessing its fields (e.g., `AllowedRegistries`, `ContainerRuntimeSearchRegistries`).

Learnt from: Chandan9112
Repo: openshift/origin PR: 31182
File: test/extended/node/node_e2e/node.go:0-0
Timestamp: 2026-05-19T12:28:55.867Z
Learning: When using the OpenShift `configv1` API (`github.com/openshift/api/config/v1`), treat `ImageSpec.RegistrySources` as a non-nil Go struct value (`RegistrySources`, not `*RegistrySources`). Because it can never be nil (it’s always zero-initialized), don’t add nil-guards before accessing its fields (e.g., `AllowedRegistries`, `ContainerRuntimeSearchRegistries`). You may still need to handle zero-value contents, but a nil check on `RegistrySources` itself is unnecessary.

@openshift-merge-bot
Copy link
Copy Markdown
Contributor

Scheduling required tests:
/test e2e-aws-csi
/test e2e-aws-ovn-fips
/test e2e-aws-ovn-microshift
/test e2e-aws-ovn-microshift-serial
/test e2e-aws-ovn-serial-1of2
/test e2e-aws-ovn-serial-2of2
/test e2e-gcp-csi
/test e2e-gcp-ovn
/test e2e-gcp-ovn-upgrade
/test e2e-metal-ipi-ovn-ipv6
/test e2e-vsphere-ovn
/test e2e-vsphere-ovn-upi

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 27, 2026

@pablintino: 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-gcp-ovn 0bf85b7 link true /test e2e-gcp-ovn
ci/prow/e2e-vsphere-ovn 0bf85b7 link true /test e2e-vsphere-ovn

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.

2 participants