CNTRLPLANE-3552: Multi-stream CoreOS metadata parsing and stream resolution#8669
CNTRLPLANE-3552: Multi-stream CoreOS metadata parsing and stream resolution#8669jparrill wants to merge 2 commits into
Conversation
|
Pipeline controller notification For optional jobs, comment This repository is configured in: LGTM mode |
|
@jparrill: This pull request references CNTRLPLANE-3552 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. DetailsIn response to this:
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. |
|
Skipping CI for Draft Pull Request. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository YAML (base), Central YAML (inherited) Review profile: CHILL Plan: Enterprise Run ID: 📒 Files selected for processing (11)
🚧 Files skipped from review as they are similar to previous changes (9)
📝 WalkthroughWalkthroughThis PR adds multi-stream CoreOS metadata support: DeserializeImageMetadata returns single-stream and OSStreams maps; ReleaseImage gains OSStreams and StreamForName for per-stream lookup; registry providers populate OSStreams. GetRHELStream chooses rhel-9/rhel-10 (validating OCP major and runc compatibility). A new 5.0 fixture and expanded unit and integration tests exercise parsing, stream resolution, and legacy single-stream backward compatibility. sequenceDiagram
participant NodePool
participant GetRHELStream
participant ReleaseImage
participant DeserializeImageMetadata
participant ConfigMap
NodePool->>GetRHELStream: request(explicitStream, releaseVersion, usesRunc)
GetRHELStream->>ReleaseImage: StreamForName(streamName)
ReleaseImage->>DeserializeImageMetadata: need StreamMetadata/OSStreams
DeserializeImageMetadata->>ConfigMap: parse data.stream / data.streams
DeserializeImageMetadata-->>ReleaseImage: StreamMetadata + OSStreams
ReleaseImage-->>GetRHELStream: resolved stream metadata or error
GetRHELStream-->>NodePool: stream name or error
🚥 Pre-merge checks | ✅ 11✅ Passed checks (11 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: jparrill The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
There was a problem hiding this comment.
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 `@support/releaseinfo/deserialize.go`:
- Around line 41-48: The code currently initializes a zero-value
CoreOSStreamMetadata and returns its address even when the "stream" key is
absent; update the logic in the json unmarshal block and final return so that
when hasStreamData is false the function returns (nil, osStreams, nil) instead
of &coreOSMeta. Concretely, only allocate or populate coreOSMeta when
hasStreamData and json.Unmarshal succeeds (inside the if hasStreamData { ... }
block using json.Unmarshal into a local variable), and change the final return
to return the pointer to that populated struct or nil when hasStreamData was
false (i.e., return nil, osStreams, nil).
🪄 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: 39f31f55-c3e5-4714-a09f-53a65264d50e
📒 Files selected for processing (11)
hypershift-operator/controllers/nodepool/stream.gohypershift-operator/controllers/nodepool/stream_test.gosupport/releaseinfo/deserialize.gosupport/releaseinfo/deserialize_test.gosupport/releaseinfo/fixtures/5.0-installer-coreos-bootimages.yamlsupport/releaseinfo/fixtures/fixtures.gosupport/releaseinfo/registry_mirror_provider.gosupport/releaseinfo/registryclient_provider.gosupport/releaseinfo/releaseinfo.gosupport/releaseinfo/releaseinfo_test.gotest/integration/osstreams/osstreams_test.go
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #8669 +/- ##
==========================================
+ Coverage 41.43% 41.47% +0.04%
==========================================
Files 756 757 +1
Lines 93658 93713 +55
==========================================
+ Hits 38807 38870 +63
+ Misses 52128 52123 -5
+ Partials 2723 2720 -3
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
…m resolution Add support for parsing the new multi-stream boot image ConfigMap format introduced in OCP 5.0 payloads. The ConfigMap now carries a "streams" key alongside the legacy "stream" key, mapping stream names (rhel-9, rhel-10) to per-architecture boot image metadata. - Update DeserializeImageMetadata to parse both "streams" and "stream" keys, returning the parsed OSStreams map alongside the default metadata - Add OSStreams field to ReleaseImage for holding per-stream metadata - Add StreamForName convenience method on ReleaseImage for stream lookup - Add GetRHELStream pure function implementing the stream resolution table from the dual-stream RHEL enhancement - Add 5.0 boot image fixture extracted from 5.0.0-ec.2 release payload Signed-off-by: Juan Manuel Parrilla Madrid <jparrill@redhat.com> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Juan Manuel Parrilla Madrid <jparrill@redhat.com>
Integration test that validates the complete flow from real 5.0 EC payload parsing through stream resolution to boot image lookup: - Parse multi-stream ConfigMap from 5.0.0-ec.2 payload fixture - Resolve RHEL stream via GetRHELStream for each scenario - Look up stream-specific boot images via StreamForName - Verify correct AWS AMI, GCP image, aarch64 AMI, and KubeVirt digest-ref for the resolved stream Covers realistic 5.0+ scenarios only (implicit default, explicit rhel-9/rhel-10, runc fallback, error cases) plus legacy 4.10 backward compatibility with real fixture data. Signed-off-by: Juan Manuel Parrilla Madrid <jparrill@redhat.com> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Juan Manuel Parrilla Madrid <jparrill@redhat.com>
There was a problem hiding this comment.
🧹 Nitpick comments (3)
support/releaseinfo/deserialize_test.go (2)
20-26: ⚡ Quick winMark test helper as a helper for cleaner failure locations.
testConfigMapis a helper but does not mark itself witht.Helper(), which makes failures point to the helper body instead of the calling test.Suggested change
-func testConfigMap(dataFields map[string]string) []byte { +func testConfigMap(t *testing.T, dataFields map[string]string) []byte { + t.Helper() cm := "apiVersion: v1\nkind: ConfigMap\nmetadata:\n name: test\ndata:\n" for k, v := range dataFields { cm += fmt.Sprintf(" %s: %s\n", k, v) } return []byte(cm) }// Update call sites in this file: data: testConfigMap(t, map[string]string{ ... })As per coding guidelines, "Use
t.Helper()in Go helper functions to improve error tracebacks".🤖 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 `@support/releaseinfo/deserialize_test.go` around lines 20 - 26, testConfigMap is a test helper but doesn't call t.Helper() or accept *testing.T, so failures point into the helper; change the signature of testConfigMap to accept t *testing.T (e.g., testConfigMap(t *testing.T, dataFields map[string]string)), call t.Helper() at the top of that function, and update all call sites in this file (places that call testConfigMap(...)) to pass the test variable (e.g., testConfigMap(t, map[string]string{...})).
28-123: ⚡ Quick winRun these unit tests in parallel.
Both test functions and their subtests can run independently; adding
t.Parallel()aligns with repository test guidance and reduces suite runtime.Suggested change
func TestDeserializeImageMetadata(t *testing.T) { + t.Parallel() tests := []struct { ... } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() g := NewWithT(t) ... }) } } func TestDeserializeImageMetadataMultiStreamContent(t *testing.T) { + t.Parallel() defaultStream, osStreams, err := DeserializeImageMetadata(fixtures.CoreOSBootImagesYAML_5_0) ... for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() tt.assert(NewWithT(t)) }) } }As per coding guidelines, "Unit tests should use race detection and parallel execution".
Also applies to: 125-229
🤖 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 `@support/releaseinfo/deserialize_test.go` around lines 28 - 123, Add parallel execution to the tests: call t.Parallel() at the start of the top-level TestDeserializeImageMetadata function and also inside each subtest goroutine (the func passed to t.Run) so subtests run in parallel; do the same for the other test function referenced (the one around lines 125-229). Locate the test functions by name (TestDeserializeImageMetadata and the other test function in the same file) and add t.Parallel() both at the top of each test and at the start of each t.Run subtest closure, ensuring no shared mutable state is assumed.hypershift-operator/controllers/nodepool/stream_test.go (1)
11-171: ⚡ Quick winEnable parallel execution for this table-driven test.
This suite is a good candidate for
t.Parallel()at both parent and subtest level.Suggested change
func TestGetRHELStream(t *testing.T) { + t.Parallel() tests := []struct { ... } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() g := NewWithT(t) result, err := GetRHELStream(tt.explicitStream, tt.releaseVersion, tt.usesRunc) ... }) } }As per coding guidelines, "Unit tests should use race detection and parallel execution".
🤖 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 `@hypershift-operator/controllers/nodepool/stream_test.go` around lines 11 - 171, The test TestGetRHELStream should enable parallel execution to follow guidelines; add t.Parallel() as the first statement in TestGetRHELStream and also call t.Parallel() at the start of each subtest inside the t.Run closure so each case runs concurrently; locate TestGetRHELStream and the anonymous func passed to t.Run around the table loop and insert the t.Parallel() calls while ensuring no shared mutable state is accessed when invoking GetRHELStream.
🤖 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.
Nitpick comments:
In `@hypershift-operator/controllers/nodepool/stream_test.go`:
- Around line 11-171: The test TestGetRHELStream should enable parallel
execution to follow guidelines; add t.Parallel() as the first statement in
TestGetRHELStream and also call t.Parallel() at the start of each subtest inside
the t.Run closure so each case runs concurrently; locate TestGetRHELStream and
the anonymous func passed to t.Run around the table loop and insert the
t.Parallel() calls while ensuring no shared mutable state is accessed when
invoking GetRHELStream.
In `@support/releaseinfo/deserialize_test.go`:
- Around line 20-26: testConfigMap is a test helper but doesn't call t.Helper()
or accept *testing.T, so failures point into the helper; change the signature of
testConfigMap to accept t *testing.T (e.g., testConfigMap(t *testing.T,
dataFields map[string]string)), call t.Helper() at the top of that function, and
update all call sites in this file (places that call testConfigMap(...)) to pass
the test variable (e.g., testConfigMap(t, map[string]string{...})).
- Around line 28-123: Add parallel execution to the tests: call t.Parallel() at
the start of the top-level TestDeserializeImageMetadata function and also inside
each subtest goroutine (the func passed to t.Run) so subtests run in parallel;
do the same for the other test function referenced (the one around lines
125-229). Locate the test functions by name (TestDeserializeImageMetadata and
the other test function in the same file) and add t.Parallel() both at the top
of each test and at the start of each t.Run subtest closure, ensuring no shared
mutable state is assumed.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Central YAML (inherited)
Review profile: CHILL
Plan: Enterprise
Run ID: c73114df-faea-4ddf-bd9d-f0e03b64c080
📒 Files selected for processing (11)
hypershift-operator/controllers/nodepool/stream.gohypershift-operator/controllers/nodepool/stream_test.gosupport/releaseinfo/deserialize.gosupport/releaseinfo/deserialize_test.gosupport/releaseinfo/fixtures/5.0-installer-coreos-bootimages.yamlsupport/releaseinfo/fixtures/fixtures.gosupport/releaseinfo/registry_mirror_provider.gosupport/releaseinfo/registryclient_provider.gosupport/releaseinfo/releaseinfo.gosupport/releaseinfo/releaseinfo_test.gotest/integration/osstreams/osstreams_test.go
🚧 Files skipped from review as they are similar to previous changes (9)
- support/releaseinfo/fixtures/fixtures.go
- support/releaseinfo/releaseinfo_test.go
- support/releaseinfo/releaseinfo.go
- support/releaseinfo/registryclient_provider.go
- support/releaseinfo/registry_mirror_provider.go
- hypershift-operator/controllers/nodepool/stream.go
- support/releaseinfo/deserialize.go
- support/releaseinfo/fixtures/5.0-installer-coreos-bootimages.yaml
- test/integration/osstreams/osstreams_test.go
What this PR does / why we need it:
Add multi-stream CoreOS boot image parsing and RHEL stream resolution logic for the dual-stream RHEL 9/10 NodePool feature (Phase 1 of CNTRLPLANE-3018).
DeserializeImageMetadatato parse both the legacystreamkey (OCP < 5.0) and the newstreamskey (OCP >= 5.0) from the boot image ConfigMapOSStreamsfield toReleaseImageandStreamForName()method for stream-specific boot image lookupGetRHELStream()pure function implementing the stream resolution table from the dual-stream RHEL enhancement5.0.0-ec.2release payloadThis is preparatory code — not reachable in production until Phase 2 connects
GetRHELStreaminto the NodePool controller (NewToken(),validMachineConfigCondition). The multi-stream parsing only activates when a >= 5.0 payload carries thestreamsConfigMap key.Stream Resolution Table
""(legacy)rhel-10rhel-9(fallback)rhel-9rhel-9rhel-10rhel-10rhel-10rhel-10Which issue(s) this PR fixes:
Special notes for your reviewer:
5.0.0-ec.2payload (not synthetic)GetRHELStreamis exported for integration tests and future Phase 2 consumersOSStreamsfield lives onReleaseImage(notCoreOSStreamMetadata) to keep the JSON-deserialized struct cleanChecklist:
Test plan
Unit tests — parsing and stream resolution:
Integration tests — end-to-end flow with real 5.0 EC payload:
go test -tags integration ./test/integration/osstreams/... -v -count=1Note: requires
-tags integrationbuild tag. No cluster needed.Verification:
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Behavior / Validation
Tests