Skip to content

CNTRLPLANE-1961: feat(nodepool )Add support for ImageTagMirrorSet config#7566

Open
mariusbertram wants to merge 1 commit intoopenshift:mainfrom
mariusbertram:itms
Open

CNTRLPLANE-1961: feat(nodepool )Add support for ImageTagMirrorSet config#7566
mariusbertram wants to merge 1 commit intoopenshift:mainfrom
mariusbertram:itms

Conversation

@mariusbertram
Copy link
Copy Markdown

@mariusbertram mariusbertram commented Jan 22, 2026

What this PR does / why we need it:

This PR Allows to set ImageTagMirrorSets to the config of nodepools.

Which issue(s) this PR fixes:

Fixes #5608

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

Release Notes

  • New Features

    • Added support for ImageTagMirrorSet (ITMS) configuration for tag-based image registry mirrors.
    • Added imageMirrorConfigRef field to enable ConfigMap-based image mirror configuration through a unified reference.
    • Added automatic capability detection for ImageTagMirrorSet support on management clusters.
  • Documentation

    • Added how-to guide for configuring image registry mirrors with step-by-step examples.
    • Added reference documentation covering mirror configuration types, detection mechanisms, and architectural workflows.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 22, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 4e68e2b3-2b93-4206-9c36-40c7d7e08a2b

📥 Commits

Reviewing files that changed from the base of the PR and between 3f16844 and f3d1ccf.

⛔ Files ignored due to path filters (27)
  • api/hypershift/v1beta1/zz_generated.deepcopy.go is excluded by !**/zz_generated*.go, !**/zz_generated*
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AAA_ungated.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDC.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HCPEtcdBackup.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ImageStreamImportMode.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/KMSEncryptionProvider.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/TLSAdherence.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDC.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HCPEtcdBackup.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/KMSEncryptionProvider.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/OpenStack.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/TLSAdherence.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
📒 Files selected for processing (2)
  • api/hypershift/v1beta1/hosted_controlplane.go
  • api/hypershift/v1beta1/hostedcluster_types.go

📝 Walkthrough

Walkthrough

This change adds support for ImageTagMirrorSet (ITMS) mirror configurations in HyperShift-hosted clusters. A new optional ImageMirrorConfigRef field is introduced in both HostedCluster and HostedControlPlane specs to reference a ConfigMap containing ImageDigestMirrorSet and/or ImageTagMirrorSet configurations. The system detects management cluster ITMS capability support, parses referenced ConfigMaps, validates ITMS as a supported NodePool config manifest type, reconciles ITMS resources into guest clusters, and generates combined IDMS+ITMS ignition configs for worker nodes. Management cluster ITMS resources are discovered and aggregated into unified registry override mappings.

Sequence Diagram

sequenceDiagram
    participant User
    participant HostedCluster
    participant HostedCluster Controller
    participant ConfigMap
    participant Config Parser
    participant IDMS/ITMS Reconciler
    participant Ignition Generator
    participant Guest Cluster

    User->>HostedCluster: Create with imageMirrorConfigRef
    HostedCluster Controller->>ConfigMap: Read referenced ConfigMap
    ConfigMap-->>HostedCluster Controller: Return YAML content (idms.yaml, itms.yaml)
    
    HostedCluster Controller->>Config Parser: Parse IDMS + ITMS from ConfigMap
    Config Parser->>Config Parser: Unmarshal YAML into typed objects
    Config Parser-->>HostedCluster Controller: Return ImageDigestMirrorSet + ImageTagMirrorSet
    
    HostedCluster Controller->>IDMS/ITMS Reconciler: Reconcile IDMS with base imageContentSources
    IDMS/ITMS Reconciler->>IDMS/ITMS Reconciler: Merge imageContentSources + additional IDMS
    
    HostedCluster Controller->>IDMS/ITMS Reconciler: Reconcile ITMS (when present)
    IDMS/ITMS Reconciler->>IDMS/ITMS Reconciler: Apply worker role labels
    
    HostedCluster Controller->>Ignition Generator: Generate ignition config from IDMS + ITMS
    Ignition Generator->>Ignition Generator: Serialize IDMS and ITMS to YAML
    Ignition Generator-->>HostedCluster Controller: Return combined ignition config
    
    HostedCluster Controller->>Guest Cluster: Create/update IDMS, ITMS, and ignition ConfigMap
    Guest Cluster-->>Guest Cluster: Worker nodes apply registries.conf from ignition
Loading
🚥 Pre-merge checks | ✅ 9 | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.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 Tests lack assertion messages. Example: line 170 "g.Expect(err).To(BeNil())" and line 1121 missing diagnostic text. Add messages to assertions: g.Expect(err).ToNot(HaveOccurred(),"describe the operation").
Title check ❓ Inconclusive Title is partially related to the changeset but uses vague phrasing 'feat(nodepool)' that doesn't clearly convey the full scope of changes. Revise title to clarify that this PR adds ImageTagMirrorSet support via ConfigMap and HostedCluster.imageMirrorConfigRef, not just NodePool. Example: 'Add ImageTagMirrorSet support via imageMirrorConfigRef ConfigMap references'
✅ Passed checks (9 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed The PR implements tag-based mirror support addressing #5608 by adding ITMS parsing, reconciliation, and ConfigMap-based configuration, plus HostedCluster.imageMirrorConfigRef for unified IDMS+ITMS management.
Out of Scope Changes check ✅ Passed All code changes are directly related to ImageTagMirrorSet support: API types, capability detection, image content source reconciliation, ignition config generation, controller logic, and comprehensive documentation.
Stable And Deterministic Test Names ✅ Passed All test names are static, deterministic strings with no dynamic values, timestamps, UUIDs, random IDs, or variable interpolation.
Microshift Test Compatibility ✅ Passed No Ginkgo e2e tests were added in this PR. All new tests are standard Go unit tests using testing.T and Gomega, not Ginkgo framework. The check is not applicable.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No new Ginkgo e2e tests assume multi-node clusters. ImageRegistry tests and custom MirrorConfigsTest have no SNO-incompatible assumptions.
Topology-Aware Scheduling Compatibility ✅ Passed PR adds ImageTagMirrorSet support via controller logic, API types, and documentation only. No deployment manifests, pod specs, or topology-unaware scheduling constraints introduced.
Ote Binary Stdout Contract ✅ Passed PR does not violate OTE Binary Stdout Contract. No process-level code (main, init, TestMain, BeforeSuite, AfterSuite) writes to stdout. Test files use only standard Go testing.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed No Ginkgo e2e tests added. All new tests are standard Go unit tests using testing.T and fake clients. No IPv4 hardcoding, IP family assumptions, or external connectivity requirements detected.

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

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

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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

@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 needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. area/control-plane-operator Indicates the PR includes changes for the control plane operator - in an OCP release labels Jan 22, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Jan 22, 2026

Hi @mariusbertram. Thanks for your PR.

I'm waiting for a openshift member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

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.

@openshift-ci openshift-ci Bot added 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 Jan 22, 2026
@mariusbertram mariusbertram changed the title Add support for ImageTagMirrorSet CNTRLPLANE-1961: feat(nodepool )Add support for ImageTagMirrorSet config Jan 22, 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 Jan 22, 2026
@openshift-ci-robot
Copy link
Copy Markdown

openshift-ci-robot commented Jan 22, 2026

@mariusbertram: This pull request references CNTRLPLANE-1961 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 "4.22.0" version, but no target version was set.

Details

In response to this:

What this PR does / why we need it:

This PR Allows to set ImageTagMirrorSets to the config of nodepools.

Which issue(s) this PR fixes:

Fixes #5608

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.

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.

@mariusbertram mariusbertram marked this pull request as ready for review January 22, 2026 10:23
@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 Jan 22, 2026
@openshift-ci openshift-ci Bot requested review from bryan-cox and jparrill January 22, 2026 10:23
@openshift-ci-robot
Copy link
Copy Markdown

openshift-ci-robot commented Jan 22, 2026

@mariusbertram: This pull request references CNTRLPLANE-1961 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 "4.22.0" version, but no target version was set.

Details

In response to this:

What this PR does / why we need it:

This PR Allows to set ImageTagMirrorSets to the config of nodepools.

Which issue(s) this PR fixes:

Fixes #5608

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.

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 added the area/documentation Indicates the PR includes changes for documentation label Jan 22, 2026
Copy link
Copy Markdown
Contributor

@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

🤖 Fix all issues with AI agents
In `@docs/content/reference/image-registry-mirrors.md`:
- Around line 147-158: Update the fenced code blocks under the headings
"Management Cluster Mirror Detection", "Guest Cluster IDMS (Automatic)" and
"Guest Cluster ITMS (Manual)" (and the other similar blocks referenced around
lines 160-171 and 173-184) to include a language identifier (e.g., "text") after
the opening ``` so markdownlint MD040 is satisfied; locate the blocks by the
heading text (e.g., "Management Cluster Mirror Detection", "Guest Cluster IDMS
(Automatic)", "Guest Cluster ITMS (Manual)") and add the language token to each
opening fence.
🧹 Nitpick comments (2)
docs/content/reference/aggregated-docs.md (1)

41824-41836: Hardcoded line numbers will require frequent maintenance.

The "Implementation Details" section includes specific line numbers for code locations. These will become stale quickly as the codebase evolves, creating a maintenance burden and potentially misleading readers.

Consider either:

  • Removing the specific line numbers and keeping just the file paths and function names
  • Adding a note that line numbers are approximate and subject to change
  • Using symbolic references (e.g., "search for CapabilityITMS in the file")
♻️ Proposed approach without hardcoded line numbers
 ### Code Locations
 
 **NodePool Validation**: `hypershift-operator/controllers/nodepool/config.go`
-- Line 297: ImageTagMirrorSet case added to validation switch
+- ImageTagMirrorSet case in validation switch
 
 **Capability System**: `support/capabilities/management_cluster_capabilities.go`
-- Lines 69-70: CapabilityITMS constant
-- Lines 214-221: ITMS API detection logic
+- CapabilityITMS constant definition
+- ITMS API detection logic
 
 **Mirror Extraction**: `support/globalconfig/imagecontentsource.go`
-- Lines 66-89: Factory functions for ITMS
-- Lines 194-229: getImageTagMirrorSets() function
+- Factory functions for ITMS
+- getImageTagMirrorSets() function
 - Updated GetAllImageRegistryMirrors() with ITMS parameter
 
 **Control Plane Operator**: `control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources.go`
-- Lines 2971-2991: reconcileImageContentPolicyType() - creates IDMS only
+- reconcileImageContentPolicyType() - creates IDMS only
support/globalconfig/imagecontentsource_test.go (1)

156-162: Avoid taking the address of the range variable.
Using &itms can alias the same variable if this list grows beyond one item. Consider indexing the slice directly (and align the other loops if you want consistency).

♻️ Proposed refactor
-			itmsObjs := make([]client.Object, len(tc.itms.Items))
-			for i, itms := range tc.itms.Items {
-				itmsObjs[i] = &itms
-			}
+			itmsObjs := make([]client.Object, len(tc.itms.Items))
+			for i := range tc.itms.Items {
+				itmsObjs[i] = &tc.itms.Items[i]
+			}

Comment thread docs/content/reference/image-registry-mirrors.md Outdated
Copy link
Copy Markdown
Contributor

@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

🤖 Fix all issues with AI agents
In `@docs/content/reference/aggregated-docs.md`:
- Around line 10366-10519: The added documentation uses fenced code blocks
(```yaml and ```bash) under headings like "Configure Digest-based Mirrors
(IDMS)", "Configure Tag-based Mirrors (ITMS)" and the "Verify Configuration"
sections which triggers markdownlint MD046; fix by converting each fenced block
(the YAML snippets for hostedcluster.yaml, itms-config.yaml, nodepool.yaml and
the bash snippets for oc apply/oc get/cat commands) to indented code blocks
(prefix each code line with four spaces) or alternatively add a file-level rule
to disable MD046 for this aggregated docs page if fenced blocks are desired.

Comment thread docs/content/reference/aggregated-docs.md Outdated
@mariusbertram
Copy link
Copy Markdown
Author

@coderabbitai help

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 23, 2026

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

CodeRabbit commands

These commands are invoked using PR/Issue comments.

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai evaluate custom pre-merge check --instructions <custom-checks-instructions> --name <custom-checks-title> [--mode <error|warning>] to validate the custom pre-merge checks instructions. Defaults to error when --mode is omitted.
    • @coderabbitai ignore pre-merge checks to override pre-merge checks and get an approval on PR.
    • @coderabbitai run pre-merge checks to run pre-merge checks on the pull request.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve to resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai generate configuration to create a PR that adds the current resolved configuration as .coderabbit.yaml (or show it if already present).
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit configuration file (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, support, documentation and community

  • Visit our status page to check the current availability of CodeRabbit.
  • Create a ticket on our support page for assistance with any issues or questions.
  • Visit our documentation site for detailed information on how to use CodeRabbit.
  • Join our Discord community to connect with other users and get help from the community.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown
Contributor

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

🤖 Fix all issues with AI agents
In `@docs/content/how-to/configure-image-registry-mirrors.md`:
- Line 3: Replace the unhyphenated phrase "HyperShift hosted" with the
hyphenated compound adjective "HyperShift-hosted" in the document; search for
the exact string "HyperShift hosted clusters" (or any occurrence of "HyperShift
hosted") and update it to "HyperShift-hosted clusters" to correct the compound
adjective.

In `@docs/content/reference/aggregated-docs.md`:
- Line 41682: The text incorrectly states ImageContentSourcePolicy (ICSP) was
"removed in OpenShift 4.17"; update the phrasing for the ICSP entries (search
for "ImageContentSourcePolicy" or "ICSP") to say it was "deprecated in OpenShift
4.17 and is still supported; it will be removed in a future release" (or similar
wording indicating deprecation only), and ensure the ITMS availability statement
for 4.13+ (reference "ITMS") is left unchanged.
♻️ Duplicate comments (1)
docs/content/reference/aggregated-docs.md (1)

10370-10511: Markdownlint MD046: fenced blocks vs indented blocks.

The code examples use fenced code blocks (yaml, bash), but markdownlint expects indented blocks. This was already identified in a previous review.

🧹 Nitpick comments (4)
docs/content/reference/image-registry-mirrors.md (1)

126-139: Line number references in documentation may become stale.

The "Code Locations" section references specific line numbers (e.g., "Line 297", "Lines 69-70", "Lines 214-221"). These will likely become outdated as the codebase evolves.

Consider removing line numbers and referencing only file paths and function/type names, or using code search links instead.

support/globalconfig/imagecontentsource.go (1)

117-117: Consider using a struct or options pattern for capability flags.

The function signature now has three consecutive boolean parameters (mgmtClusterHasIDMSCapability, mgmtClusterHasITMSCapability, mgmtClusterHasICSPCapability), which can be error-prone at call sites. The parameter order (IDMS, ITMS, ICSP) doesn't follow alphabetical or chronological order.

This is acceptable for now, but if more capability flags are added in the future, consider refactoring to use a struct or passing the CapabiltyChecker directly.

support/globalconfig/imagecontentsource_test.go (1)

286-437: Consider adding ITMS test coverage to TestReconcileMgmtImageRegistryOverrides.

The TestReconcileMgmtImageRegistryOverrides test only covers ICSP and IDMS capabilities. Consider adding a test case that includes CapabilityITMS to ensure the CommonRegistryProvider correctly handles ITMS mirrors.

docs/content/reference/aggregated-docs.md (1)

41797-41812: Implementation details reference specific line numbers.

The documentation references specific code locations and line numbers (e.g., "Line 297", "Lines 69-70", "Lines 214-221"). While this is valuable for current reference, these line numbers will become outdated as the codebase evolves.

Consider adding a note that line numbers are approximate and may shift, or establish a process to update these references periodically.

Comment thread docs/content/how-to/configure-image-registry-mirrors.md Outdated
Comment thread docs/content/reference/aggregated-docs.md Outdated
@jparrill
Copy link
Copy Markdown
Contributor

Hey @mariusbertram thanks for the PR. I've been going through the code and I have a preliminar feedback before going deep in more detail:

Concern about execution mode consistency

The design for ImageTagMirrorSet (ITMS) differs from ImageDigestMirrorSet (IDMS), which may confuse users.
Currently:

  • IDMS: Configured via imageContentSources in the HostedCluster spec and automatically reconciled through ReconcileImageDigestMirrors().
  • ITMS: Only configurable via ConfigMap in NodePool config, with no automatic reconciliation from the HostedCluster spec.

This inconsistency means users must use different approaches for similar functionality. Consider aligning ITMS with IDMS by:

  1. Adding a ReconcileImageTagMirrors() function similar to ReconcileImageDigestMirrors().
  2. Supporting automatic reconciliation from the HostedCluster spec (or a similar field) for tag-based mirrors.

This would provide a consistent experience and reduce confusion. If there’s a reason for the different approach, documenting it would help.

@mariusbertram
Copy link
Copy Markdown
Author

Hey @mariusbertram thanks for the PR. I've been going through the code and I have a preliminar feedback before going deep in more detail:

Concern about execution mode consistency

The design for ImageTagMirrorSet (ITMS) differs from ImageDigestMirrorSet (IDMS), which may confuse users. Currently:

  • IDMS: Configured via imageContentSources in the HostedCluster spec and automatically reconciled through ReconcileImageDigestMirrors().
  • ITMS: Only configurable via ConfigMap in NodePool config, with no automatic reconciliation from the HostedCluster spec.

This inconsistency means users must use different approaches for similar functionality. Consider aligning ITMS with IDMS by:

  1. Adding a ReconcileImageTagMirrors() function similar to ReconcileImageDigestMirrors().
  2. Supporting automatic reconciliation from the HostedCluster spec (or a similar field) for tag-based mirrors.

This would provide a consistent experience and reduce confusion. If there’s a reason for the different approach, documenting it would help.

Hi @jparrill,
thanks for your feedback. I understand the reasoning behind the current design, and I could implement such an extension if we agree on the direction.

In our production environment we operate a larger HCP setup backed by oVirt. From an operational workflow and automation perspective, managing the ImageDigestMirrorSet (IDMS) configuration via a referenced ConfigMap has proven to be the most efficient and user‑friendly approach. The ConfigMap‑based method allows us to version, template, and distribute IDMS configuration through GitOps pipelines without having to touch each cluster individually.

At the moment, we maintain 10 HostedControlPlane (HCP) clusters, and we plan to scale this to more than 200 clusters within this year.

Proposal

My proposal is to extend the HostedCluster API surface with a new field that allows referencing a ConfigMap containing both ITMS and IDMS configuration. This would unify the handling of digest‑ and tag‑based mirrors.

Conceptually, something like:

Hostedcluster CR:

spec:
  imageMirrorConfigRef:
    name: global-image-mirror-config
    namespace: my-config-namespace

The referenced ConfigMap could contain structured keys such as:

data:
  idms.yaml: |
    apiVersion: config.openshift.io/v1
    kind: ImageDigestMirrorSet
    spec:
      imageDigestMirrors:
      - source: quay.io/example
        mirrors:
        - mirror.registry.local

  itms.yaml: |
    apiVersion: config.openshift.io/v1
    kind: ImageTagMirrorSet
    spec:
      imageTagMirrors:
      - source: quay.io/example/app
        mirrors:
        - mirror.registry.local/app

Benefits

  1. Consistency:
    Both IDMS and ITMS would follow the same reconciliation flow via a ReconcileImageTagMirrors() mechanism similar to ReconcileImageDigestMirrors().

  2. GitOps‑friendly:
    Configurations can be versioned, templated, and pushed automatically to hundreds of clusters.

  3. Fleet‑scalability:
    A central configuration reference avoids repetitive manual updates across hundreds of HCPs.

@openshift-ci-robot
Copy link
Copy Markdown

openshift-ci-robot commented Feb 26, 2026

@mariusbertram: This pull request references CNTRLPLANE-1961 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 "4.22.0" version, but no target version was set.

Details

In response to this:

What this PR does / why we need it:

This PR Allows to set ImageTagMirrorSets to the config of nodepools.

Which issue(s) this PR fixes:

Fixes #5608

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

Release Notes

  • New Features

  • Added support for ImageTagMirrorSet (ITMS) as an alternative to ImageDigestMirrorSet (IDMS) for image mirror configuration.

  • Introduced imageMirrorConfigRef field on HostedCluster and HostedControlPlane to reference a ConfigMap containing unified image mirror configurations.

  • ConfigMap entries merge with existing ImageContentSources, enabling flexible override strategies.

  • Documentation

  • Added comprehensive guides for configuring image registry mirrors and managing image mirror configurations.

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.

Copy link
Copy Markdown
Contributor

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

🧹 Nitpick comments (5)
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AutoNodeKarpenter.yaml (1)

2535-2537: Use JSON field names in the user-facing description.

On Line 2535-Line 2537, the text uses ImageContentSources and ImageMirrorConfigRef. Using imageContentSources and imageMirrorConfigRef would better match what users write in YAML.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AutoNodeKarpenter.yaml`
around lines 2535 - 2537, The user-facing description uses Go-style field names
`ImageContentSources` and `ImageMirrorConfigRef`; change those to the JSON/YAML
field names `imageContentSources` and `imageMirrorConfigRef` in the description
text so it matches what users write in manifests (update the lines referencing
ImageContentSources and ImageMirrorConfigRef accordingly).
api/hypershift/v1beta1/hostedcluster_types.go (1)

752-765: Consider aligning documentation between HostedClusterSpec and HostedControlPlaneSpec.

The ImageMirrorConfigRef documentation in HostedClusterSpec is more comprehensive than the corresponding field in HostedControlPlaneSpec (in hosted_controlplane.go). While users primarily interact with HostedCluster, consider adding the merge behavior explanation to HostedControlPlaneSpec for consistency, especially if developers or operators inspect the HCP directly.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/hypershift/v1beta1/hostedcluster_types.go` around lines 752 - 765, The
docs for ImageMirrorConfigRef on HostedClusterSpec explain merge behavior and
rollout triggers but the same field on HostedControlPlaneSpec
(hosted_controlplane.go) lacks that detail; update the comment for
ImageMirrorConfigRef in the HostedControlPlaneSpec to match: mention that
ConfigMap entries are merged after ImageContentSources (allowing overrides),
that controllers perform the merge during reconciliation, and that changes
trigger NodePool rollouts; ensure you reference the same field name
ImageMirrorConfigRef and keep the +optional and +rollout annotations consistent
with the HostedClusterSpec comment.
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml (1)

3010-3013: Prefer CRD JSON field names in description text for clarity.

Using imageContentSources and imageMirrorConfigRef (JSON names) instead of Go-style names would better match what users set in YAML manifests and kubectl explain.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml`
around lines 3010 - 3013, The description currently uses Go-style field names
"ImageContentSources" and "ImageMirrorConfigRef"; update the human-facing
description to use CRD/JSON field names "imageContentSources" and
"imageMirrorConfigRef" so it matches YAML manifests and kubectl explain (search
for the description text that mentions ImageContentSources/ImageMirrorConfigRef
and replace with the JSON names, and scan adjacent descriptions to update any
other Go-style field name occurrences).
control-plane-operator/controllers/hostedcontrolplane/ignition/reconcile.go (1)

63-75: Extract shared image-content YAML serializer construction to one helper.

Line 63-Line 75 duplicates Line 126-Line 137. Centralizing this avoids drift in scheme registration/serializer options.

Refactor sketch
+func newImageContentYAMLSerializer() (*runtime.Scheme, *jsonserializer.Serializer, error) {
+	scheme := runtime.NewScheme()
+	if err := operatorv1alpha1.Install(scheme); err != nil {
+		return nil, nil, err
+	}
+	if err := configv1.Install(scheme); err != nil {
+		return nil, nil, err
+	}
+	serializer := jsonserializer.NewSerializerWithOptions(
+		jsonserializer.DefaultMetaFactory, scheme, scheme,
+		jsonserializer.SerializerOptions{Yaml: true, Pretty: true, Strict: true},
+	)
+	return scheme, serializer, nil
+}
+
 func ReconcileImageSourceMirrorsIgnitionConfigFromIDMSAndITMS(...) error {
-	scheme := runtime.NewScheme()
-	err := operatorv1alpha1.Install(scheme)
-	...
-	yamlSerializer := jsonserializer.NewSerializerWithOptions(...)
+	_, yamlSerializer, err := newImageContentYAMLSerializer()
+	if err != nil {
+		return err
+	}
 	...
 }
 
 func reconcileImageContentTypeIgnitionConfigMap(...) error {
-	scheme := runtime.NewScheme()
-	err := operatorv1alpha1.Install(scheme)
-	...
-	yamlSerializer := jsonserializer.NewSerializerWithOptions(...)
+	_, yamlSerializer, err := newImageContentYAMLSerializer()
+	if err != nil {
+		return err
+	}
 	...
 }

Also applies to: 125-137

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@control-plane-operator/controllers/hostedcontrolplane/ignition/reconcile.go`
around lines 63 - 75, Duplicate construction of the image-content YAML
serializer (runtime.NewScheme + operatorv1alpha1.Install + configv1.Install +
jsonserializer.NewSerializerWithOptions) should be extracted into a single
helper function; create a helper (e.g., newImageContentYAMLSerializer) that
builds a scheme, calls operatorv1alpha1.Install(scheme) and
configv1.Install(scheme), then returns the serializer created by
jsonserializer.NewSerializerWithOptions using the same SerializerOptions
{Yaml:true, Pretty:true, Strict:true}, and replace both inline blocks that
assign yamlSerializer with a call to this helper so scheme registration and
serializer options remain identical.
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-Default.crd.yaml (1)

3106-3125: Enforce non-empty imageMirrorConfigRef.name when the ref is set

Right now, imageMirrorConfigRef can be provided as an empty object ({}) because name is optional with default "" (Line 3115 onward). That permits an invalid reconcile target and pushes validation failure to runtime.

Proposed schema validation
               imageMirrorConfigRef:
                 description: |-
                   imageMirrorConfigRef is a local reference to a ConfigMap containing both ImageDigestMirrorSet (IDMS)
                   and ImageTagMirrorSet (ITMS) configurations. The ConfigMap should contain keys "idms.yaml" and/or "itms.yaml"
                   with the respective mirror configurations.
                   This provides a unified and GitOps-friendly way to manage image mirror configurations for both digest-based
                   and tag-based mirrors.
                   When set, the controllers will parse the ConfigMap and reconcile both IDMS and ITMS configurations.
                 properties:
                   name:
                     default: ""
                     description: |-
                       Name of the referent.
                       This field is effectively required, but due to backwards compatibility is
                       allowed to be empty. Instances of this type with an empty value here are
                       almost certainly wrong.
                       More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
                     type: string
                 type: object
                 x-kubernetes-map-type: atomic
+                x-kubernetes-validations:
+                - message: imageMirrorConfigRef.name must not be empty when imageMirrorConfigRef is set
+                  rule: self.name != ""
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-Default.crd.yaml`
around lines 3106 - 3125, The schema currently allows imageMirrorConfigRef to be
an empty object because imageMirrorConfigRef.name has a default of "" and isn't
required; change the CRD schema for imageMirrorConfigRef so that name is
mandatory and cannot be empty by removing the default "" and adding a required
constraint (e.g., add required: ["name"] under imageMirrorConfigRef or set a
non-empty validation like minLength: 1 or a non-empty pattern on the property).
Update the imageMirrorConfigRef.name property (notably the symbol
imageMirrorConfigRef.name) and keep x-kubernetes-map-type: atomic; ensure
validators and defaults are adjusted so an empty object is rejected at
validation time.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AutoNodeKarpenter.yaml`:
- Around line 2542-2550: The CRD currently permits imageMirrorConfigRef: {} or
imageMirrorConfigRef.name = ""; update the AutoNodeKarpenter CRD schema so that
the imageMirrorConfigRef object requires a name and that name is non-empty: add
required: ["name"] to the imageMirrorConfigRef schema and add a minLength: 1 (or
an equivalent non-empty string validation) to the imageMirrorConfigRef.name
property so empty objects or empty strings are rejected at API validation.

In
`@api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yaml`:
- Around line 2412-2431: The schema currently allows imageMirrorConfigRef: {} or
name: "" which can't resolve a ConfigMap; update the imageMirrorConfigRef schema
by removing the default: "" on the name property, add validation to require a
non-empty string (e.g., add minLength: 1 to the name property) and mark the name
as required for the imageMirrorConfigRef object (add required: ["name"]) so that
an empty object is rejected; reference the imageMirrorConfigRef.name property in
the AAA_ungated.yaml fragment and ensure the changes prevent
imageMirrorConfigRef from being provided without a resolvable name.

In
`@cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-CustomNoUpgrade.crd.yaml`:
- Around line 3351-3361: The schema currently defaults imageMirrorConfigRef.name
to "" which allows an empty reference; update the CRD schema for the field
imageMirrorConfigRef.name to disallow empty strings by removing the default ""
and adding a validation constraint such as minLength: 1 (or an equivalent
non-empty pattern) so that if imageMirrorConfigRef is provided its name must be
non-empty; locate the imageMirrorConfigRef.name definition in the CRD (the
property block with description "Name of the referent.") and apply these
changes.

---

Nitpick comments:
In `@api/hypershift/v1beta1/hostedcluster_types.go`:
- Around line 752-765: The docs for ImageMirrorConfigRef on HostedClusterSpec
explain merge behavior and rollout triggers but the same field on
HostedControlPlaneSpec (hosted_controlplane.go) lacks that detail; update the
comment for ImageMirrorConfigRef in the HostedControlPlaneSpec to match: mention
that ConfigMap entries are merged after ImageContentSources (allowing
overrides), that controllers perform the merge during reconciliation, and that
changes trigger NodePool rollouts; ensure you reference the same field name
ImageMirrorConfigRef and keep the +optional and +rollout annotations consistent
with the HostedClusterSpec comment.

In
`@api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AutoNodeKarpenter.yaml`:
- Around line 2535-2537: The user-facing description uses Go-style field names
`ImageContentSources` and `ImageMirrorConfigRef`; change those to the JSON/YAML
field names `imageContentSources` and `imageMirrorConfigRef` in the description
text so it matches what users write in manifests (update the lines referencing
ImageContentSources and ImageMirrorConfigRef accordingly).

In
`@api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml`:
- Around line 3010-3013: The description currently uses Go-style field names
"ImageContentSources" and "ImageMirrorConfigRef"; update the human-facing
description to use CRD/JSON field names "imageContentSources" and
"imageMirrorConfigRef" so it matches YAML manifests and kubectl explain (search
for the description text that mentions ImageContentSources/ImageMirrorConfigRef
and replace with the JSON names, and scan adjacent descriptions to update any
other Go-style field name occurrences).

In
`@cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-Default.crd.yaml`:
- Around line 3106-3125: The schema currently allows imageMirrorConfigRef to be
an empty object because imageMirrorConfigRef.name has a default of "" and isn't
required; change the CRD schema for imageMirrorConfigRef so that name is
mandatory and cannot be empty by removing the default "" and adding a required
constraint (e.g., add required: ["name"] under imageMirrorConfigRef or set a
non-empty validation like minLength: 1 or a non-empty pattern on the property).
Update the imageMirrorConfigRef.name property (notably the symbol
imageMirrorConfigRef.name) and keep x-kubernetes-map-type: atomic; ensure
validators and defaults are adjusted so an empty object is rejected at
validation time.

In `@control-plane-operator/controllers/hostedcontrolplane/ignition/reconcile.go`:
- Around line 63-75: Duplicate construction of the image-content YAML serializer
(runtime.NewScheme + operatorv1alpha1.Install + configv1.Install +
jsonserializer.NewSerializerWithOptions) should be extracted into a single
helper function; create a helper (e.g., newImageContentYAMLSerializer) that
builds a scheme, calls operatorv1alpha1.Install(scheme) and
configv1.Install(scheme), then returns the serializer created by
jsonserializer.NewSerializerWithOptions using the same SerializerOptions
{Yaml:true, Pretty:true, Strict:true}, and replace both inline blocks that
assign yamlSerializer with a call to this helper so scheme registration and
serializer options remain identical.

ℹ️ Review info

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

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between e99c28c and dfb8cde.

⛔ Files ignored due to path filters (1)
  • api/hypershift/v1beta1/zz_generated.deepcopy.go is excluded by !**/zz_generated*
📒 Files selected for processing (39)
  • api/hypershift/v1beta1/hosted_controlplane.go
  • api/hypershift/v1beta1/hostedcluster_types.go
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AAA_ungated.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AutoNodeKarpenter.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDC.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ImageStreamImportMode.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/KMSEncryptionProvider.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/NetworkDiagnosticsConfig.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AutoNodeKarpenter.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDC.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/KMSEncryptionProvider.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/NetworkDiagnosticsConfig.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/OpenStack.yaml
  • client/applyconfiguration/hypershift/v1beta1/hostedclusterspec.go
  • client/applyconfiguration/hypershift/v1beta1/hostedcontrolplanespec.go
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-CustomNoUpgrade.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-CustomNoUpgrade.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-Default.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-TechPreviewNoUpgrade.crd.yaml
  • control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go
  • control-plane-operator/controllers/hostedcontrolplane/ignition/params.go
  • control-plane-operator/controllers/hostedcontrolplane/ignition/reconcile.go
🚧 Files skipped from review as they are similar to previous changes (14)
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AAA_ungated.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/NetworkDiagnosticsConfig.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yaml
  • client/applyconfiguration/hypershift/v1beta1/hostedclusterspec.go
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/KMSEncryptionProvider.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-TechPreviewNoUpgrade.crd.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/OpenStack.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-CustomNoUpgrade.crd.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml

@openshift-ci-robot
Copy link
Copy Markdown

openshift-ci-robot commented Mar 8, 2026

@mariusbertram: This pull request references CNTRLPLANE-1961 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 "4.22.0" version, but no target version was set.

Details

In response to this:

What this PR does / why we need it:

This PR Allows to set ImageTagMirrorSets to the config of nodepools.

Which issue(s) this PR fixes:

Fixes #5608

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

  • Support for ImageTagMirrorSet (ITMS) alongside ImageDigestMirrorSet (IDMS).

  • New imageMirrorConfigRef field on HostedCluster and HostedControlPlane to reference a ConfigMap with unified mirror configs (idms.yaml and/or itms.yaml); entries merge with ImageContentSources and trigger NodePool rollouts on change.

  • Documentation

  • Added comprehensive how-to and reference guides for configuring and migrating image registry mirrors.

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.

Copy link
Copy Markdown
Contributor

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

♻️ Duplicate comments (3)
docs/content/reference/aggregated-docs.md (1)

45214-45214: ⚠️ Potential issue | 🟡 Minor

ICSP removal timeline remains incorrect.

Line 45214 states ICSP "will be removed in OpenShift 4.17," which contradicts the official documentation. Per past review verification, ICSP is "deprecated in OpenShift 4.17 and will be removed in a future release" (no specific removal version).

This issue was previously flagged and marked as addressed, but the incorrect wording persists in the current code.

📝 Suggested correction
-ImageContentSourcePolicy (ICSP) is deprecated and will be removed in OpenShift 4.17. HyperShift automatically:
+ImageContentSourcePolicy (ICSP) is deprecated in OpenShift 4.17 and will be removed in a future release. HyperShift automatically:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/content/reference/aggregated-docs.md` at line 45214, Update the
incorrect removal timeline text: find the sentence "ImageContentSourcePolicy
(ICSP) is deprecated and will be removed in OpenShift 4.17." and change it to
reflect the official guidance, e.g. "ImageContentSourcePolicy (ICSP) is
deprecated in OpenShift 4.17 and will be removed in a future release." Ensure
the revised sentence replaces the original exact phrase so the documentation
accurately states deprecation in 4.17 with removal in a future release.
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-CustomNoUpgrade.crd.yaml (1)

3348-3358: ⚠️ Potential issue | 🟡 Minor

Reject empty imageMirrorConfigRef.name at the schema level.

As written, imageMirrorConfigRef: {} is valid because name defaults to "". For a new field, that defers a malformed reference to reconciliation instead of failing fast at admission.

🔧 Suggested schema change
               imageMirrorConfigRef:
                 properties:
                   name:
-                    default: ""
+                    minLength: 1
                     description: |-
                       Name of the referent.
-                      This field is effectively required, but due to backwards compatibility is
-                      allowed to be empty. Instances of this type with an empty value here are
-                      almost certainly wrong.
                       More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
                     type: string
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-CustomNoUpgrade.crd.yaml`
around lines 3348 - 3358, The schema allows imageMirrorConfigRef.name to default
to "" so empty objects pass validation; update the CRD schema for the
imageMirrorConfigRef property so that name is required and cannot be empty:
remove the default: "" for name, add a required: ["name"] entry on the
imageMirrorConfigRef object and enforce a non-empty constraint (e.g., minLength:
1 or a pattern) for imageMirrorConfigRef.name so imageMirrorConfigRef: {} is
rejected at admission.
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yaml (1)

2412-2431: ⚠️ Potential issue | 🟡 Minor

Require a non-empty imageMirrorConfigRef.name.

This schema still admits imageMirrorConfigRef: {} / name: "", which cannot resolve a ConfigMap and defers a bad spec to reconcile time. Please make name required and non-empty in the source API markers so the generated CRD rejects it at admission.

Suggested schema hardening
               imageMirrorConfigRef:
                 description: |-
                   imageMirrorConfigRef is a local reference to a ConfigMap containing both ImageDigestMirrorSet (IDMS)
                   and ImageTagMirrorSet (ITMS) configurations. The ConfigMap should contain keys "idms.yaml" and/or "itms.yaml"
                   with the respective mirror configurations.
                   This provides a unified and GitOps-friendly way to manage image mirror configurations for both digest-based
                   and tag-based mirrors.
                   When set, the controllers will parse the ConfigMap and reconcile both IDMS and ITMS configurations.
                 properties:
                   name:
-                    default: ""
                     description: |-
                       Name of the referent.
-                      This field is effectively required, but due to backwards compatibility is
-                      allowed to be empty. Instances of this type with an empty value here are
-                      almost certainly wrong.
                       More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+                    minLength: 1
                     type: string
+                required:
+                - name
                 type: object
                 x-kubernetes-map-type: atomic
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yaml`
around lines 2412 - 2431, The imageMirrorConfigRef.name currently allows empty
values; update the API markers on the ImageMirrorConfigRef struct's Name field
to make it required and non-empty by adding validation markers (e.g.
+kubebuilder:validation:Required and +kubebuilder:validation:MinLength=1) and
remove "omitempty" from the json tag if present so the generated CRD enforces
presence and a non-empty string for name.
🧹 Nitpick comments (6)
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml (1)

2867-2874: Document how this combines with imageContentSources.

The new field sits next to imageContentSources, but the CRD text does not say whether the two inputs are merged, whether one overrides the other, or what happens on conflicts. Since this description is part of the user-facing API contract, please spell that out here as well so kubectl explain users do not have to infer controller behavior from code.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml`
around lines 2867 - 2874, Update the description for imageMirrorConfigRef to
explicitly state how it interacts with imageContentSources: explain whether the
controller merges entries from the referenced ConfigMap with the cluster's
imageContentSources, which source takes precedence on conflict (e.g.,
imageMirrorConfigRef overrides imageContentSources or vice versa), how duplicate
entries are resolved (last-wins, namespace-scoped, or key-based deduplication),
and note that both IDMS and ITMS from the ConfigMap will be reconciled together
with any existing imageContentSources by the controller; reference the fields
imageMirrorConfigRef and imageContentSources in the text so kubectl explain
users can see the merge/override and conflict-resolution behavior clearly.
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AutoNodeKarpenter.yaml (1)

2448-2455: Document how this combines with spec.imageContentSources.

This CRD text introduces a second image-mirror input right next to imageContentSources, but it never states whether the two are additive, which source wins on conflicts, or whether duplicates are deduplicated/rejected. Since this text becomes the API contract users see, please encode the merge/precedence rule in the source type comment so every generated CRD stays unambiguous.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AutoNodeKarpenter.yaml`
around lines 2448 - 2455, Update the imageMirrorConfigRef property description
to explicitly describe how it interacts with spec.imageContentSources: state
whether the entries from imageMirrorConfigRef (idms.yaml and itms.yaml) are
merged with spec.imageContentSources, which source takes precedence on conflicts
(e.g., imageMirrorConfigRef overrides spec.imageContentSources or vice versa),
and whether duplicate entries are deduplicated or rejected; reference the
specific config keys (idms.yaml, itms.yaml) and the field name
spec.imageContentSources so the CRD comment unambiguously defines merge
semantics, conflict resolution, and validation behavior for IDMS/ITMS vs
spec.imageContentSources.
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yaml (1)

2422-2428: Document merge and rollout semantics in the CRD description.

The description explains the ConfigMap shape, but not the two behaviors operators need to know up front: whether this content is merged with spec.imageContentSources, and whether changing the ref/content triggers NodePool rollouts. Please add that to the source Go doc so the generated CRD matches runtime behavior.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yaml`
around lines 2422 - 2428, Update the Go doc comment for the imageMirrorConfigRef
field (the ImageMirrorConfigRef field on the HostedControlPlane API type) to
explicitly state the runtime merge semantics with spec.imageContentSources
(e.g., whether the ConfigMap entries are merged into, appended to, or replace
spec.imageContentSources) and the rollout semantics (whether changing the
ConfigMap reference or its contents will trigger NodePool rollouts and how that
rollout is performed). Put this text directly above the ImageMirrorConfigRef
field declaration so the generated CRD description includes the behavior, and
then regenerate the CRD manifests so the updated description appears in
ImageStreamImportMode.yaml.
cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-Default.crd.yaml (1)

3107-3114: Document how this combines with imageContentSources.

This new public field sits next to imageContentSources, but the description never says whether entries are merged, deduplicated, or which input wins on conflicts. That ambiguity makes overlapping mirror configs hard to reason about for callers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-Default.crd.yaml`
around lines 3107 - 3114, Update the imageMirrorConfigRef description to
explicitly state how it interacts with imageContentSources: explain whether
entries are merged or replaced, how deduplication is performed, and which source
wins on conflicts (e.g., "entries from imageMirrorConfigRef are merged with
imageContentSources; duplicates are deduplicated by exact source+mirror match;
imageMirrorConfigRef entries take precedence on conflict"). Mention that
controllers will parse both sources and reconcile combined configuration
accordingly, and include examples of keys expected ("idms.yaml"/"itms.yaml")
only as supporting detail.
control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go (1)

2037-2055: Design consideration: IDMS/ITMS configuration asymmetry.

The implementation correctly branches between IDMS+ITMS and IDMS-only ignition config reconciliation. However, per the PR discussion, this introduces an asymmetry in configuration approaches:

  • IDMS: Configured via HostedCluster.spec.imageContentSources with automatic reconciliation via ReconcileImageDigestMirrors
  • ITMS: Configured only via ImageMirrorConfigRef ConfigMap without a direct spec field

The code implementation is correct, but this design divergence may impact user experience consistency. Consider documenting this difference or aligning both approaches in a future iteration as suggested by reviewer jparrill.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go`
around lines 2037 - 2055, The code branches correctly between IDMS+ITMS and
IDMS-only flows (see globalconfig.ReconcileImageTagMirrors and
ignition.ReconcileImageSourceMirrorsIgnitionConfigFromIDMSAndITMS /
ReconcileImageSourceMirrorsIgnitionConfigFromIDMS), but this creates a UX
asymmetry because IDMS is driven from HostedCluster.spec.imageContentSources
while ITMS is only provided via ImageMirrorConfigRef ConfigMap; update the
codebase by adding a concise TODO and user-facing documentation: add a TODO
comment near the conditional referencing the functions above and the fields
HostedCluster.spec.imageContentSources and ImageMirrorConfigRef to signal
planned alignment, and add or update documentation (release notes or relevant
README) explaining the current asymmetry and recommended user workflow so
consumers know the difference and the intended future alignment.
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml (1)

2926-2932: Clarify how this composes with imageContentSources.

imageContentSources is still available immediately above this field, so the CRD description should say whether the two inputs are merged, whether one wins on conflicts, and whether this ref augments or replaces digest mirrors. Right now the API docs are ambiguous for users reading oc explain.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml`
around lines 2926 - 2932, Update the description for imageMirrorConfigRef to
explicitly state how it composes with imageContentSources: specify that
controllers will merge imageMirrorConfigRef-derived ImageDigestMirrorSet (IDMS)
and ImageTagMirrorSet (ITMS) entries with imageContentSources entries (not
replace them), explain conflict resolution (e.g., entries with identical source
repository keys are deduplicated and the ConfigMap entries take precedence or
vice versa), and clarify whether the ref augments both digest and tag mirrors or
only one type; keep the existing note that controllers parse the ConfigMap and
reconcile IDMS and ITMS so readers of oc explain understand the merge behavior
and precedence between imageMirrorConfigRef and imageContentSources.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml`:
- Around line 2494-2505: The schema currently allows imageMirrorConfigRef.name
to be empty; update the source API type that generates
ClusterVersionOperatorConfiguration (the imageMirrorConfigRef field/type) so
that the name property is required or has minLength: 1, ensuring the generated
CRD for imageMirrorConfigRef includes either a "required: ['name']" entry or
"minLength: 1" for the name string; change the struct/tag or openAPI annotations
on the imageMirrorConfigRef type (the field/type referenced by
imageMirrorConfigRef and the name property) so the CRD rejects empty names at
admission time.

In
`@api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml`:
- Around line 2957-2968: The schema for the reference currently inherits
empty-name behavior allowing imageMirrorConfigRef: {} — remove the default: ""
on the properties.name and add a required constraint so the object forces a
non-empty name; specifically update the object schema for the reference (the
properties.name entry and its enclosing type: object) to remove default and
include required: ["name"] (and optionally add a minLength: 1 on name) so
imageMirrorConfigRef must contain a valid name.

In
`@api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml`:
- Around line 2517-2527: The schema currently allows imageMirrorConfigRef.name
to be empty; make the field required and non-empty by removing the permissive
empty default and adding a non-empty constraint (e.g., mark
imageMirrorConfigRef.name as required on the parent object and/or add minLength:
1) so that imageMirrorConfigRef cannot be admitted as {} — update the schema
entries referencing imageMirrorConfigRef and the name property
(imageMirrorConfigRef.name) to enforce a non-empty string and remove the legacy
“allowed to be empty” default.

In
`@api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml`:
- Around line 2411-2422: The manifest allows an empty LocalObjectReference for
spec.imageMirrorConfigRef which lets spec.imageMirrorConfigRef: {} pass
admission; update the API to require a non-empty name by making the `name` field
required (or add a non-empty validation like minLength: 1) on the source type
used by imageMirrorConfigRef (the LocalObjectReference-derived field) and then
regenerate the CRD so ClusterVersionOperatorConfiguration's schema enforces a
non-empty `name`; target the schema for imageMirrorConfigRef /
LocalObjectReference and ensure the generated CRD includes `required: ["name"]`
or an equivalent non-empty constraint.

In
`@api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml`:
- Around line 2933-2944: Add an API-level validation so an empty
LocalObjectReference.name is rejected when imageMirrorConfigRef is provided:
update the CRD schema for imageMirrorConfigRef/LocalObjectReference to include a
conditional validation (e.g., an allOf/anyOf JSONSchema entry) that enforces
name is a non-empty string (minLength: 1 or pattern: .+) whenever
imageMirrorConfigRef is present; target the properties "imageMirrorConfigRef"
and "name" (the LocalObjectReference.name) and ensure the validation is
expressed using x-kubernetes validation-compatible schema constructs so CRD
validation fails for imageMirrorConfigRef: {}.

In
`@cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yaml`:
- Around line 3229-3238: The CRD description incorrectly states the ConfigMap
can "add or override" entries; instead update the description for
ImageMirrorConfigRef/ImageContentSources to reflect actual behavior in
support/globalconfig/imagecontentsource.go and ReconcileImageTagMirrors: for
IDMS entries are concatenated in order (HostedCluster ImageContentSources first,
then ConfigMap entries) with no deduplication or override semantics (duplicates
may appear), and for ITMS the controller currently ignores HostedCluster
ImageContentSources so only ConfigMap entries are used; mention this asymmetry
explicitly so the documentation matches implementation.

In
`@cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-TechPreviewNoUpgrade.crd.yaml`:
- Around line 3150-3169: The schema currently allows imageMirrorConfigRef: {}
because the property "name" defaults to "" and is not required; update the CRD
schema for imageMirrorConfigRef to require a valid non-empty name by adding a
required: ["name"] entry under imageMirrorConfigRef and remove the default empty
string on the name property (or add minLength: 1 to name) so empty objects are
rejected; also consider setting additionalProperties: false on
imageMirrorConfigRef to prevent silent empty payloads. Ensure you modify the
imageMirrorConfigRef and its name property (as seen in the diff) to enforce
these constraints.

In `@docs/content/reference/api.md`:
- Around line 8172-8187: The docs for
HostedControlPlaneSpec.imageMirrorConfigRef are missing the same merge-order and
rollout behaviour details that exist for HostedClusterSpec.imageMirrorConfigRef;
update the source comment that generates the HostedControlPlaneSpec section to
include the same wording about how the ConfigMap is merged with
imageContentSources (specifying precedence/merge order) and how controllers
trigger rollout/reconciliation when mirrors change so both generated references
describe identical semantics for imageMirrorConfigRef in HostedControlPlaneSpec
and HostedClusterSpec.

---

Duplicate comments:
In
`@api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yaml`:
- Around line 2412-2431: The imageMirrorConfigRef.name currently allows empty
values; update the API markers on the ImageMirrorConfigRef struct's Name field
to make it required and non-empty by adding validation markers (e.g.
+kubebuilder:validation:Required and +kubebuilder:validation:MinLength=1) and
remove "omitempty" from the json tag if present so the generated CRD enforces
presence and a non-empty string for name.

In
`@cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-CustomNoUpgrade.crd.yaml`:
- Around line 3348-3358: The schema allows imageMirrorConfigRef.name to default
to "" so empty objects pass validation; update the CRD schema for the
imageMirrorConfigRef property so that name is required and cannot be empty:
remove the default: "" for name, add a required: ["name"] entry on the
imageMirrorConfigRef object and enforce a non-empty constraint (e.g., minLength:
1 or a pattern) for imageMirrorConfigRef.name so imageMirrorConfigRef: {} is
rejected at admission.

In `@docs/content/reference/aggregated-docs.md`:
- Line 45214: Update the incorrect removal timeline text: find the sentence
"ImageContentSourcePolicy (ICSP) is deprecated and will be removed in OpenShift
4.17." and change it to reflect the official guidance, e.g.
"ImageContentSourcePolicy (ICSP) is deprecated in OpenShift 4.17 and will be
removed in a future release." Ensure the revised sentence replaces the original
exact phrase so the documentation accurately states deprecation in 4.17 with
removal in a future release.

---

Nitpick comments:
In
`@api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AutoNodeKarpenter.yaml`:
- Around line 2448-2455: Update the imageMirrorConfigRef property description to
explicitly describe how it interacts with spec.imageContentSources: state
whether the entries from imageMirrorConfigRef (idms.yaml and itms.yaml) are
merged with spec.imageContentSources, which source takes precedence on conflicts
(e.g., imageMirrorConfigRef overrides spec.imageContentSources or vice versa),
and whether duplicate entries are deduplicated or rejected; reference the
specific config keys (idms.yaml, itms.yaml) and the field name
spec.imageContentSources so the CRD comment unambiguously defines merge
semantics, conflict resolution, and validation behavior for IDMS/ITMS vs
spec.imageContentSources.

In
`@api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml`:
- Around line 2926-2932: Update the description for imageMirrorConfigRef to
explicitly state how it composes with imageContentSources: specify that
controllers will merge imageMirrorConfigRef-derived ImageDigestMirrorSet (IDMS)
and ImageTagMirrorSet (ITMS) entries with imageContentSources entries (not
replace them), explain conflict resolution (e.g., entries with identical source
repository keys are deduplicated and the ConfigMap entries take precedence or
vice versa), and clarify whether the ref augments both digest and tag mirrors or
only one type; keep the existing note that controllers parse the ConfigMap and
reconcile IDMS and ITMS so readers of oc explain understand the merge behavior
and precedence between imageMirrorConfigRef and imageContentSources.

In
`@api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml`:
- Around line 2867-2874: Update the description for imageMirrorConfigRef to
explicitly state how it interacts with imageContentSources: explain whether the
controller merges entries from the referenced ConfigMap with the cluster's
imageContentSources, which source takes precedence on conflict (e.g.,
imageMirrorConfigRef overrides imageContentSources or vice versa), how duplicate
entries are resolved (last-wins, namespace-scoped, or key-based deduplication),
and note that both IDMS and ITMS from the ConfigMap will be reconciled together
with any existing imageContentSources by the controller; reference the fields
imageMirrorConfigRef and imageContentSources in the text so kubectl explain
users can see the merge/override and conflict-resolution behavior clearly.

In
`@api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yaml`:
- Around line 2422-2428: Update the Go doc comment for the imageMirrorConfigRef
field (the ImageMirrorConfigRef field on the HostedControlPlane API type) to
explicitly state the runtime merge semantics with spec.imageContentSources
(e.g., whether the ConfigMap entries are merged into, appended to, or replace
spec.imageContentSources) and the rollout semantics (whether changing the
ConfigMap reference or its contents will trigger NodePool rollouts and how that
rollout is performed). Put this text directly above the ImageMirrorConfigRef
field declaration so the generated CRD description includes the behavior, and
then regenerate the CRD manifests so the updated description appears in
ImageStreamImportMode.yaml.

In
`@cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-Default.crd.yaml`:
- Around line 3107-3114: Update the imageMirrorConfigRef description to
explicitly state how it interacts with imageContentSources: explain whether
entries are merged or replaced, how deduplication is performed, and which source
wins on conflicts (e.g., "entries from imageMirrorConfigRef are merged with
imageContentSources; duplicates are deduplicated by exact source+mirror match;
imageMirrorConfigRef entries take precedence on conflict"). Mention that
controllers will parse both sources and reconcile combined configuration
accordingly, and include examples of keys expected ("idms.yaml"/"itms.yaml")
only as supporting detail.

In
`@control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go`:
- Around line 2037-2055: The code branches correctly between IDMS+ITMS and
IDMS-only flows (see globalconfig.ReconcileImageTagMirrors and
ignition.ReconcileImageSourceMirrorsIgnitionConfigFromIDMSAndITMS /
ReconcileImageSourceMirrorsIgnitionConfigFromIDMS), but this creates a UX
asymmetry because IDMS is driven from HostedCluster.spec.imageContentSources
while ITMS is only provided via ImageMirrorConfigRef ConfigMap; update the
codebase by adding a concise TODO and user-facing documentation: add a TODO
comment near the conditional referencing the functions above and the fields
HostedCluster.spec.imageContentSources and ImageMirrorConfigRef to signal
planned alignment, and add or update documentation (release notes or relevant
README) explaining the current asymmetry and recommended user workflow so
consumers know the difference and the intended future alignment.

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Pro

Run ID: f276e166-1ce8-4cdd-9582-f7f0b8aac125

📥 Commits

Reviewing files that changed from the base of the PR and between dfb8cde and 1a7120f.

📒 Files selected for processing (37)
  • api/hypershift/v1beta1/hostedcluster_types.go
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AAA_ungated.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AutoNodeKarpenter.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDC.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ImageStreamImportMode.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/KMSEncryptionProvider.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/NetworkDiagnosticsConfig.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AutoNodeKarpenter.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDC.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/KMSEncryptionProvider.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/NetworkDiagnosticsConfig.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/OpenStack.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-CustomNoUpgrade.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-CustomNoUpgrade.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-Default.crd.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-TechPreviewNoUpgrade.crd.yaml
  • control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources.go
  • docs/content/reference/aggregated-docs.md
  • docs/content/reference/api.md
🚧 Files skipped from review as they are similar to previous changes (15)
  • api/hypershift/v1beta1/hostedcluster_types.go
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/NetworkDiagnosticsConfig.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDC.yaml
  • control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources.go
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDC.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-CustomNoUpgrade.crd.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/KMSEncryptionProvider.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/OpenStack.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AAA_ungated.yaml
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ImageStreamImportMode.yaml

Comment thread docs/content/reference/api.md Outdated
@openshift-ci-robot
Copy link
Copy Markdown

openshift-ci-robot commented Mar 17, 2026

@mariusbertram: This pull request references CNTRLPLANE-1961 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 "4.22.0" version, but no target version was set.

Details

In response to this:

What this PR does / why we need it:

This PR Allows to set ImageTagMirrorSets to the config of nodepools.

Which issue(s) this PR fixes:

Fixes #5608

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

  • Support for ImageTagMirrorSet (ITMS) alongside ImageDigestMirrorSet (IDMS).

  • New imageMirrorConfigRef on HostedCluster/HostedControlPlane to reference a ConfigMap (idms.yaml and/or itms.yaml); entries merge with ImageContentSources and trigger NodePool rollouts.

  • Automatic detection of management-cluster ITMS capability to enable ITMS behavior.

  • Tests

  • Added/expanded tests covering ITMS parsing, reconciliation, and merging scenarios.

  • Documentation

  • Added how-to and reference guides for configuring and migrating image registry mirrors.

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.

Copy link
Copy Markdown
Contributor

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go (1)

2017-2037: ⚠️ Potential issue | 🟠 Major

ConfigMap-based ITMS/IDMS will be ignored when no inline ImageContentSources are specified.

The early return at lines 2018-2025 occurs before parsing ImageMirrorConfigRef (lines 2027-2037). If a user uses only the ConfigMap-based approach without inline ImageContentSources, p.HasImageMirrorPolicies will be false, causing the function to return early without applying the ConfigMap contents.

🐛 Proposed fix to account for ConfigMap reference
 	imageContentPolicyIgnitionConfig := manifests.ImageContentPolicyIgnitionConfig(hcp.GetNamespace())
-	if !p.HasImageMirrorPolicies {
+	if !p.HasImageMirrorPolicies && hcp.Spec.ImageMirrorConfigRef == nil {
 		_, err := util.DeleteIfNeeded(ctx, r.Client, imageContentPolicyIgnitionConfig)
 		if err != nil {
 			return fmt.Errorf("failed to delete image content source policy configuration configmap: %w", err)
 		}
 
 		return nil
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go`
around lines 2017 - 2037, The code returns early when p.HasImageMirrorPolicies
is false before ever parsing hcp.Spec.ImageMirrorConfigRef, causing
ConfigMap-based ImageTag/ ImageDigestMirrorSets to be ignored; fix by moving the
ParseImageMirrorConfigMap call (globalconfig.ParseImageMirrorConfigMap) so it
runs before the p.HasImageMirrorPolicies check (populate
additionalIDMS/additionalITMS from hcp.Spec.ImageMirrorConfigRef first), then
change the early-return logic to only delete imageContentPolicyIgnitionConfig
and return if both p.HasImageMirrorPolicies is false AND no
additionalIDMS/additionalITMS were parsed; references:
imageContentPolicyIgnitionConfig, p.HasImageMirrorPolicies,
hcp.Spec.ImageMirrorConfigRef, globalconfig.ParseImageMirrorConfigMap.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In
`@control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go`:
- Around line 2017-2037: The code returns early when p.HasImageMirrorPolicies is
false before ever parsing hcp.Spec.ImageMirrorConfigRef, causing ConfigMap-based
ImageTag/ ImageDigestMirrorSets to be ignored; fix by moving the
ParseImageMirrorConfigMap call (globalconfig.ParseImageMirrorConfigMap) so it
runs before the p.HasImageMirrorPolicies check (populate
additionalIDMS/additionalITMS from hcp.Spec.ImageMirrorConfigRef first), then
change the early-return logic to only delete imageContentPolicyIgnitionConfig
and return if both p.HasImageMirrorPolicies is false AND no
additionalIDMS/additionalITMS were parsed; references:
imageContentPolicyIgnitionConfig, p.HasImageMirrorPolicies,
hcp.Spec.ImageMirrorConfigRef, globalconfig.ParseImageMirrorConfigMap.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: ad18ab53-d009-4a37-8a5c-75b73a1f4bd9

📥 Commits

Reviewing files that changed from the base of the PR and between 1a7120f and 60111e4.

⛔ Files ignored due to path filters (35)
  • api/hypershift/v1beta1/zz_generated.deepcopy.go is excluded by !**/zz_generated*.go
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AAA_ungated.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AutoNodeKarpenter.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDC.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ImageStreamImportMode.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/KMSEncryptionProvider.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/NetworkDiagnosticsConfig.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AutoNodeKarpenter.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDC.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/KMSEncryptionProvider.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/NetworkDiagnosticsConfig.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/OpenStack.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-CustomNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/**, !cmd/install/assets/**/*.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml is excluded by !**/zz_generated.crd-manifests/**, !cmd/install/assets/**/*.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/**, !cmd/install/assets/**/*.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-CustomNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/**, !cmd/install/assets/**/*.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-Default.crd.yaml is excluded by !**/zz_generated.crd-manifests/**, !cmd/install/assets/**/*.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-TechPreviewNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/**, !cmd/install/assets/**/*.yaml
  • docs/content/reference/aggregated-docs.md is excluded by !docs/content/reference/aggregated-docs.md
  • docs/content/reference/api.md is excluded by !docs/content/reference/api.md
📒 Files selected for processing (5)
  • api/hypershift/v1beta1/hosted_controlplane.go
  • api/hypershift/v1beta1/hostedcluster_types.go
  • control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources.go
  • hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go
🚧 Files skipped from review as they are similar to previous changes (4)
  • api/hypershift/v1beta1/hosted_controlplane.go
  • hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources.go
  • api/hypershift/v1beta1/hostedcluster_types.go

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Apr 1, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

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

@openshift-ci-robot
Copy link
Copy Markdown

openshift-ci-robot commented Apr 1, 2026

@mariusbertram: This pull request references CNTRLPLANE-1961 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 "4.22.0" version, but no target version was set.

Details

In response to this:

What this PR does / why we need it:

This PR Allows to set ImageTagMirrorSets to the config of nodepools.

Which issue(s) this PR fixes:

Fixes #5608

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

Release Notes

  • New Features

  • Added support for ImageTagMirrorSet (ITMS) configuration alongside existing ImageDigestMirrorSet (IDMS)

  • New imageMirrorConfigRef field enables ConfigMap-based image mirror management for both digest-based and tag-based mirrors

  • Unified approach automatically merges mirror configurations from ImageContentSources and referenced ConfigMap

  • Documentation

  • Added how-to guide for configuring image registry mirrors

  • Added comprehensive reference documentation covering IDMS, ITMS, and unified configuration approaches

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-robot
Copy link
Copy Markdown

openshift-ci-robot commented Apr 1, 2026

@mariusbertram: This pull request references CNTRLPLANE-1961 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 "4.22.0" version, but no target version was set.

Details

In response to this:

What this PR does / why we need it:

This PR Allows to set ImageTagMirrorSets to the config of nodepools.

Which issue(s) this PR fixes:

Fixes #5608

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

  • Support for tag-based ImageTagMirrorSet (ITMS) alongside digest-based IDMS

  • New imageMirrorConfigRef field to reference a ConfigMap for unified IDMS+ITMS mirror configuration

  • Management-cluster detection of ITMS capability to include tag mirrors in aggregated registry overrides

  • Behavioral

  • Changes to referenced ConfigMap or its name now influence NodePool rollout behavior

  • Documentation

  • Added how-to and reference docs for configuring image registry mirrors (IDMS/ITMS)

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.

Copy link
Copy Markdown
Contributor

@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)
support/globalconfig/imagecontentsource.go (1)

157-160: Use strict decoding for ConfigMap-backed mirror manifests.

yaml.Unmarshal is permissive here, so unknown fields or the wrong kind can decode into a zero-value IDMS/ITMS and fail later, if at all. Failing fast at parse time will make GitOps misconfigurations much easier to diagnose.

Possible direction
-		if err := yaml.Unmarshal([]byte(idmsYAML), idms); err != nil {
+		if err := sigsyaml.UnmarshalStrict([]byte(idmsYAML), idms); err != nil {
 			return nil, nil, fmt.Errorf("failed to parse idms.yaml from ConfigMap: %w", err)
 		}
+		if idms.APIVersion != configv1.GroupVersion.String() || idms.Kind != "ImageDigestMirrorSet" {
+			return nil, nil, fmt.Errorf("idms.yaml must contain %s ImageDigestMirrorSet", configv1.GroupVersion.String())
+		}
@@
-		if err := yaml.Unmarshal([]byte(itmsYAML), itms); err != nil {
+		if err := sigsyaml.UnmarshalStrict([]byte(itmsYAML), itms); err != nil {
 			return nil, nil, fmt.Errorf("failed to parse itms.yaml from ConfigMap: %w", err)
 		}
+		if itms.APIVersion != configv1.GroupVersion.String() || itms.Kind != "ImageTagMirrorSet" {
+			return nil, nil, fmt.Errorf("itms.yaml must contain %s ImageTagMirrorSet", configv1.GroupVersion.String())
+		}

Also applies to: 165-168

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@support/globalconfig/imagecontentsource.go` around lines 157 - 160, Replace
the permissive yaml.Unmarshal call that parses idmsYAML into idms (type
ImageDigestMirrorSet) with a strict decoder (e.g., yaml.UnmarshalStrict or a
YAML decoder configured to disallow unknown fields) so unknown fields cause a
parse error; after strict-unmarshal, also validate the decoded object's
TypeMeta/Kind (ensure it/its Kind equals "ImageDigestMirrorSet" or that required
fields are present) and return a clear error on mismatch. Do the same change for
the analogous ITMS parsing code paths (the other yaml.Unmarshal usages) so
ConfigMap-backed mirror manifests fail fast on unknown fields or wrong kinds.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@support/globalconfig/imagecontentsource.go`:
- Around line 123-137: The caller currently invokes ReconcileImageDigestMirrors
unconditionally but only calls ReconcileImageTagMirrors when additionalITMS !=
nil, which leaves stale ITMS objects when the config is removed; update the
caller to invoke ReconcileImageTagMirrors unconditionally (passing nil when no
additionalITMS) just like ReconcileImageDigestMirrors, or if you prefer, add an
explicit cleanup branch in the caller that calls ReconcileImageTagMirrors with
additionalITMS=nil to clear itms.Spec.ImageTagMirrors; locate the calls to
ReconcileImageDigestMirrors and ReconcileImageTagMirrors and make the invocation
behavior consistent so ReconcileImageTagMirrors always runs.

---

Nitpick comments:
In `@support/globalconfig/imagecontentsource.go`:
- Around line 157-160: Replace the permissive yaml.Unmarshal call that parses
idmsYAML into idms (type ImageDigestMirrorSet) with a strict decoder (e.g.,
yaml.UnmarshalStrict or a YAML decoder configured to disallow unknown fields) so
unknown fields cause a parse error; after strict-unmarshal, also validate the
decoded object's TypeMeta/Kind (ensure it/its Kind equals "ImageDigestMirrorSet"
or that required fields are present) and return a clear error on mismatch. Do
the same change for the analogous ITMS parsing code paths (the other
yaml.Unmarshal usages) so ConfigMap-backed mirror manifests fail fast on unknown
fields or wrong kinds.
🪄 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), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: e7bff817-9dd1-49d1-b092-3d3a0ff8062d

📥 Commits

Reviewing files that changed from the base of the PR and between 615dde6 and 833c0d2.

⛔ Files ignored due to path filters (40)
  • api/hypershift/v1beta1/zz_generated.deepcopy.go is excluded by !**/zz_generated*.go
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AAA_ungated.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AutoNodeKarpenter.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDC.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HCPEtcdBackup.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ImageStreamImportMode.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/KMSEncryptionProvider.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AutoNodeKarpenter.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDC.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HCPEtcdBackup.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/KMSEncryptionProvider.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/OpenStack.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • client/applyconfiguration/hypershift/v1beta1/hostedclusterspec.go is excluded by !client/**
  • client/applyconfiguration/hypershift/v1beta1/hostedcontrolplanespec.go is excluded by !client/**
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-CustomNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/**, !cmd/install/assets/**/*.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml is excluded by !**/zz_generated.crd-manifests/**, !cmd/install/assets/**/*.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/**, !cmd/install/assets/**/*.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-CustomNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/**, !cmd/install/assets/**/*.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-Default.crd.yaml is excluded by !**/zz_generated.crd-manifests/**, !cmd/install/assets/**/*.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-TechPreviewNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/**, !cmd/install/assets/**/*.yaml
  • docs/content/reference/aggregated-docs.md is excluded by !docs/content/reference/aggregated-docs.md
  • docs/content/reference/api.md is excluded by !docs/content/reference/api.md
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hosted_controlplane.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_types.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go is excluded by !vendor/**, !**/vendor/**, !**/zz_generated*.go
📒 Files selected for processing (14)
  • api/hypershift/v1beta1/hosted_controlplane.go
  • api/hypershift/v1beta1/hostedcluster_types.go
  • control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go
  • control-plane-operator/controllers/hostedcontrolplane/ignition/params.go
  • control-plane-operator/controllers/hostedcontrolplane/ignition/reconcile.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources.go
  • docs/content/how-to/configure-image-registry-mirrors.md
  • docs/content/reference/image-registry-mirrors.md
  • hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go
  • hypershift-operator/controllers/nodepool/config.go
  • hypershift-operator/controllers/nodepool/nto_test.go
  • support/capabilities/management_cluster_capabilities.go
  • support/globalconfig/imagecontentsource.go
  • support/globalconfig/imagecontentsource_test.go
✅ Files skipped from review due to trivial changes (4)
  • hypershift-operator/controllers/nodepool/nto_test.go
  • docs/content/how-to/configure-image-registry-mirrors.md
  • docs/content/reference/image-registry-mirrors.md
  • api/hypershift/v1beta1/hostedcluster_types.go
🚧 Files skipped from review as they are similar to previous changes (6)
  • control-plane-operator/controllers/hostedcontrolplane/ignition/params.go
  • hypershift-operator/controllers/nodepool/config.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources.go
  • hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go
  • control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go
  • control-plane-operator/controllers/hostedcontrolplane/ignition/reconcile.go

Comment thread support/globalconfig/imagecontentsource.go
@mariusbertram
Copy link
Copy Markdown
Author

@coderabbitai resume

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 1, 2026

✅ Actions performed

Reviews resumed.

@openshift-ci-robot
Copy link
Copy Markdown

openshift-ci-robot commented Apr 1, 2026

@mariusbertram: This pull request references CNTRLPLANE-1961 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 "4.22.0" version, but no target version was set.

Details

In response to this:

What this PR does / why we need it:

This PR Allows to set ImageTagMirrorSets to the config of nodepools.

Which issue(s) this PR fixes:

Fixes #5608

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 support for tag-based ImageTagMirrorSet (ITMS) alongside digest-based IDMS.

  • New imageMirrorConfigRef field to reference a ConfigMap for unified IDMS+ITMS configuration.

  • Management-cluster detection of ITMS capability so tag mirrors are included in aggregated registry overrides.

  • Behavioral

  • Changes to the referenced ConfigMap or its name affect NodePool rollouts and mirror reconciliation.

  • Tests

  • Expanded tests to cover ITMS parsing and reconciliation.

  • Documentation

  • Added how-to and reference guides for configuring image registry mirrors (IDMS/ITMS).

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.

Copy link
Copy Markdown
Contributor

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@support/globalconfig/imagecontentsource.go`:
- Around line 156-169: The idms.yaml and itms.yaml parsing accepts wrong
payloads silently; after unmarshalling into idms (configv1.ImageDigestMirrorSet)
and itms (configv1.ImageTagMirrorSet) validate that the parsed object's
TypeMeta.Kind equals "ImageDigestMirrorSet" or "ImageTagMirrorSet" respectively
(or at minimum that critical spec fields like ImageDigestMirrors/ImageTagMirrors
are non-empty) and return a descriptive error if the kind/required fields don't
match, so the reconciler won't accept swapped/malformed configs from the
"idms.yaml" and "itms.yaml" keys.
🪄 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), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 4d9c5548-0bf6-4450-86ce-c477e4821338

📥 Commits

Reviewing files that changed from the base of the PR and between 615dde6 and 833c0d2.

⛔ Files ignored due to path filters (40)
  • api/hypershift/v1beta1/zz_generated.deepcopy.go is excluded by !**/zz_generated*.go
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AAA_ungated.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AutoNodeKarpenter.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDC.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HCPEtcdBackup.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ImageStreamImportMode.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/KMSEncryptionProvider.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AutoNodeKarpenter.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDC.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HCPEtcdBackup.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/KMSEncryptionProvider.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/OpenStack.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • client/applyconfiguration/hypershift/v1beta1/hostedclusterspec.go is excluded by !client/**
  • client/applyconfiguration/hypershift/v1beta1/hostedcontrolplanespec.go is excluded by !client/**
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-CustomNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/**, !cmd/install/assets/**/*.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml is excluded by !**/zz_generated.crd-manifests/**, !cmd/install/assets/**/*.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/**, !cmd/install/assets/**/*.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-CustomNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/**, !cmd/install/assets/**/*.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-Default.crd.yaml is excluded by !**/zz_generated.crd-manifests/**, !cmd/install/assets/**/*.yaml
  • cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-TechPreviewNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/**, !cmd/install/assets/**/*.yaml
  • docs/content/reference/aggregated-docs.md is excluded by !docs/content/reference/aggregated-docs.md
  • docs/content/reference/api.md is excluded by !docs/content/reference/api.md
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hosted_controlplane.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_types.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go is excluded by !vendor/**, !**/vendor/**, !**/zz_generated*.go
📒 Files selected for processing (14)
  • api/hypershift/v1beta1/hosted_controlplane.go
  • api/hypershift/v1beta1/hostedcluster_types.go
  • control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go
  • control-plane-operator/controllers/hostedcontrolplane/ignition/params.go
  • control-plane-operator/controllers/hostedcontrolplane/ignition/reconcile.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources.go
  • docs/content/how-to/configure-image-registry-mirrors.md
  • docs/content/reference/image-registry-mirrors.md
  • hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go
  • hypershift-operator/controllers/nodepool/config.go
  • hypershift-operator/controllers/nodepool/nto_test.go
  • support/capabilities/management_cluster_capabilities.go
  • support/globalconfig/imagecontentsource.go
  • support/globalconfig/imagecontentsource_test.go
✅ Files skipped from review due to trivial changes (5)
  • hypershift-operator/controllers/nodepool/nto_test.go
  • docs/content/how-to/configure-image-registry-mirrors.md
  • control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources.go
  • docs/content/reference/image-registry-mirrors.md
  • api/hypershift/v1beta1/hostedcluster_types.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • control-plane-operator/controllers/hostedcontrolplane/ignition/params.go
  • hypershift-operator/controllers/nodepool/config.go
  • hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go

Comment thread support/globalconfig/imagecontentsource.go
@openshift-ci-robot
Copy link
Copy Markdown

openshift-ci-robot commented Apr 1, 2026

@mariusbertram: This pull request references CNTRLPLANE-1961 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 "4.22.0" version, but no target version was set.

Details

In response to this:

What this PR does / why we need it:

This PR Allows to set ImageTagMirrorSets to the config of nodepools.

Which issue(s) this PR fixes:

Fixes #5608

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 tag-based ImageTagMirrorSet (ITMS) support and a new imageMirrorConfigRef to supply unified IDMS+ITMS from a ConfigMap.

  • Management-cluster detection now discovers ITMS capability and includes tag mirrors in aggregated registry overrides.

  • Behavioral

  • ConfigMap reference or content changes trigger NodePool rollouts; guest ignition and image-source handling now include ITMS when provided.

  • Tests

  • Expanded unit tests to cover ITMS parsing and reconciliation.

  • Documentation

  • Added how-to and reference guides for configuring image registry mirrors (IDMS/ITMS).

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-bot
Copy link
Copy Markdown

Stale PRs are closed after 21d of inactivity.

If this PR is still relevant, comment to refresh it or remove the stale label.
Mark the PR as fresh by commenting /remove-lifecycle stale.

If this PR is safe to close now please do so with /close.

/lifecycle stale

@openshift-ci openshift-ci Bot added lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale. needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. labels May 2, 2026
@hypershift-jira-solve-ci
Copy link
Copy Markdown

Now I have the full picture for both failures. Let me produce the final report.

Test Failure Analysis Complete

Job Information

Test Failure Analysis

Error

tide: "Not mergeable. PR has a merge conflict."

Deploy Preview: Cloudflare API authentication error [code: 10000]
  A request to the Cloudflare API (/accounts/***/pages/projects/hypershift) failed.
  Authentication error — ensure the API token has the correct permissions for this operation.

Summary

Neither failure is caused by the PR's code changes. The tide error is a merge gate rejection because the PR has a merge conflict with main (mergeable: CONFLICTING, mergeStateStatus: DIRTY). Additionally, the PR carries needs-ok-to-test (author is not an org member) and lifecycle/stale labels, which block all 6 Prow e2e jobs in PENDING state. The Deploy Preview failure is a Cloudflare API authentication error — the API token used by cloudflare/wrangler-action@v3 is expired, revoked, or lacks permissions. This is a repo-wide infrastructure issue unrelated to this PR.

Root Cause

Tide Error — Merge Conflict:
The itms branch has diverged from main and has conflicting changes. Prow's tide component correctly identifies the PR as unmergeable and applies the needs-rebase label automatically. No CI tests have actually run or failed — all 6 e2e jobs (e2e-aks, e2e-aws, e2e-aws-upgrade-hypershift-operator, e2e-azure-self-managed, e2e-kubevirt-aws-ovn-reduced, e2e-v2-aws) are stuck in PENDING because the needs-ok-to-test label blocks them (the author mariusbertram is not an org member).

Deploy Preview — Cloudflare Auth Failure:
The GitHub Actions workflow Docs Preview uses cloudflare/wrangler-action@v3 to deploy a documentation preview to Cloudflare Pages. The Cloudflare API token stored in the repository's GitHub Actions secrets (CLOUDFLARE_API_TOKEN) is returning authentication error code 10000. This means the token is either expired, revoked, or no longer has the required Cloudflare Pages deployment permissions. The failed command was:

npx wrangler pages deploy site --project-name=hypershift --branch=pr-7566 --commit-dirty=true

A secondary non-fatal error (EACCES: permission denied, mkdir '/.config') indicates HOME is unset or set to / on the runner, but this alone does not cause the deployment failure.

Recommendations

For the PR author (mariusbertram):

  1. Rebase the itms branch onto current main to resolve the merge conflict
  2. Request an org member to comment /ok-to-test on the PR to unblock CI jobs

For repository maintainers:
3. Rotate or update the CLOUDFLARE_API_TOKEN secret in the repo's GitHub Actions settings — this is a repo-wide issue affecting all PR doc previews, not just this PR
4. Consider fixing the HOME environment variable in the Deploy Preview workflow to prevent the EACCES log noise

Evidence
Evidence Detail
Tide status error — "Not mergeable. PR has a merge conflict."
PR mergeable state CONFLICTING (mergeStateStatus: DIRTY)
Blocking labels needs-rebase, needs-ok-to-test, lifecycle/stale
Prow e2e jobs All 6 jobs in PENDING — blocked by needs-ok-to-test
Deploy Preview job GitHub Actions run 23867501359, failed in 24s
Deploy Preview failed step "Deploy to Cloudflare Pages"
Cloudflare error API authentication error [code: 10000] on /accounts/.../pages/projects/hypershift
Wrangler command npx wrangler pages deploy site --project-name=hypershift --branch=pr-7566 --commit-dirty=true
Secondary error EACCES: permission denied, mkdir '/.config' (non-fatal, runner HOME issue)
Actual test failures None — no CI tests have executed

Comment thread api/hypershift/v1beta1/hosted_controlplane.go Outdated
Implement support for HostedCluster.spec.imageMirrorConfig to enable
unified ImageDigestMirrorSet (IDMS) and ImageTagMirrorSet (ITMS)
configuration from a single ConfigMap reference. This provides a
cluster-wide, GitOps-friendly approach for managing image registry
mirrors that applies to all NodePools automatically.

API changes:
- Add imageMirrorConfig field to HostedCluster and HostedControlPlane specs
- Add ParseImageMirrorConfigMap() to parse ConfigMap with idms.yaml/itms.yaml keys
- Update ReconcileImageDigestMirrors() and ReconcileImageTagMirrors() to merge
  additional mirrors from ConfigMap

Controller changes:
- HostedCluster controller copies imageMirrorConfig to HostedControlPlane
- HostedControlPlane controller parses and reconciles IDMS/ITMS from ConfigMap
- Add ReconcileImageSourceMirrorsIgnitionConfigFromIDMSAndITMS() for combined configs
- Update globalConfigString() to include imageMirrorConfig in rollout hash
- Update HasImageMirrorPolicies check to include imageMirrorConfig
- Update getCoreConfigs() to expect additional config when imageMirrorConfig is set

Testing:
- Add TestParseImageMirrorConfigMap with 4 test cases
- Add TestReconcileImageDigestMirrorsWithAdditional
- Add TestReconcileImageTagMirrorsWithAdditional
- Fix loop variable pointer bug in existing tests

Documentation:
- Add comprehensive how-to guide for configure-image-registry-mirrors.md
- Update reference docs to cover both cluster-wide and per-NodePool approaches
- Convert indented code blocks to fenced blocks for syntax highlighting
- Document unified configuration pattern with both IDMS and ITMS

This implementation maintains backward compatibility with existing
imageContentSources and per-NodePool configurations while providing a
more scalable approach for fleet management.

Signed-off-by: Marius Bertram <marius@brtrm.de>
@openshift-ci openshift-ci Bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label May 9, 2026
@openshift-ci-robot
Copy link
Copy Markdown

openshift-ci-robot commented May 9, 2026

@mariusbertram: This pull request references CNTRLPLANE-1961 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:

What this PR does / why we need it:

This PR Allows to set ImageTagMirrorSets to the config of nodepools.

Which issue(s) this PR fixes:

Fixes #5608

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

Release Notes

  • New Features

  • Added support for ImageTagMirrorSet (ITMS) configuration for tag-based image registry mirrors.

  • Added imageMirrorConfigRef field to enable ConfigMap-based image mirror configuration through a unified reference.

  • Added automatic capability detection for ImageTagMirrorSet support on management clusters.

  • Documentation

  • Added how-to guide for configuring image registry mirrors with step-by-step examples.

  • Added reference documentation covering mirror configuration types, detection mechanisms, and architectural workflows.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/api Indicates the PR includes changes for the API area/cli Indicates the PR includes changes for CLI area/control-plane-operator Indicates the PR includes changes for the control plane operator - in an OCP release area/documentation Indicates the PR includes changes for documentation 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. lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale. needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support for ImageTagMirrorSet via ImageContentSource in HostedCluster

6 participants