Skip to content

WIP: add OLMv1 controlplane hoists#8470

Draft
grokspawn wants to merge 1 commit intoopenshift:mainfrom
grokspawn:olmv1-hcp
Draft

WIP: add OLMv1 controlplane hoists#8470
grokspawn wants to merge 1 commit intoopenshift:mainfrom
grokspawn:olmv1-hcp

Conversation

@grokspawn
Copy link
Copy Markdown

@grokspawn grokspawn commented May 8, 2026

What this PR does / why we need it:

Which issue(s) this PR fixes:

Fixes

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 OLMv1 component support to hosted control planes with new deployments for catalogd, cluster-olm-operator, console-operator, and operator-controller
    • Implemented dual-API access support for cluster-olm-operator to manage resources across hosted and management clusters
  • Tests

    • Added comprehensive unit tests for new OLMv1 components
  • Documentation

    • Added documentation on HyperShift dual-API access patterns for cluster-olm-operator

Signed-off-by: grokspawn <jordan@nimblewidget.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 8, 2026

📝 Walkthrough

Walkthrough

This pull request registers OLMv1 components in the HostedControlPlane reconciler and implements four new OLM v1 control-plane components: catalogd (a service catalog), operator-controller (operator installation manager), console-operator (console integration), and cluster-olm-operator (main OLM operator). Each component includes deployment adaptation logic for kubeconfig injection, environment variables, and service configuration. The implementation supports dual-API access for the cluster-olm-operator to manage hosted-cluster resources while reporting to the management cluster, with comprehensive test coverage and documentation.

🚥 Pre-merge checks | ✅ 10 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.52% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'WIP: add OLMv1 controlplane hoists' is partially related to the changeset but uses vague terminology ('hoists') that doesn't clearly convey the main changes. Clarify the title to more specifically describe what 'hoists' means or what OLMv1 components are being added (e.g., 'Add OLMv1 control plane components: catalogd, cluster-olm-operator, console-operator, and operator-controller').
✅ Passed checks (10 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed PR uses standard Go testing (testing.T), not Ginkgo. All test names are static string literals with no dynamic content. Test names are clear and descriptive.
Test Structure And Quality ✅ Passed Tests meet quality standards: single responsibility, table-driven, meaningful assertions, proper fixtures, and codebase consistency. No cluster access means setup/cleanup and timeouts not required.
Microshift Test Compatibility ✅ Passed No Ginkgo e2e tests were added in this PR. All new tests are standard Go unit tests using the testing package with Gomega assertions. The check requirement does not apply.
Single Node Openshift (Sno) Test Compatibility ✅ Passed PR adds only standard Go unit tests, not Ginkgo e2e tests. No Ginkgo patterns (It, Describe, Context, When) found. Check not applicable.
Topology-Aware Scheduling Compatibility ✅ Passed Components follow framework patterns used by existing code. MultiZoneSpread components apply standard affinity rules. No new topology-unaware constraints introduced beyond existing design.
Ote Binary Stdout Contract ✅ Passed No OTE Stdout Contract violations found. Code contains no main(), init(), TestMain() or Ginkgo suite setup. Tests use standard Go testing. No fmt/log/klog/os.Stdout writes at process level.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed PR adds standard Go unit tests, not Ginkgo e2e tests. Custom check scoped to Ginkgo e2e tests only. Not applicable to this PR.

✏️ 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


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@codecov
Copy link
Copy Markdown

codecov Bot commented May 8, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 37.68%. Comparing base (bded456) to head (3fbf303).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8470      +/-   ##
==========================================
+ Coverage   37.53%   37.68%   +0.15%     
==========================================
  Files         751      399     -352     
  Lines       92026    63717   -28309     
==========================================
- Hits        34544    24014   -10530     
+ Misses      54841    37838   -17003     
+ Partials     2641     1865     -776     

see 352 files with indirect coverage changes

Flag Coverage Δ
cmd-support 32.76% <ø> (ø)
cpo-hostedcontrolplane ?
cpo-other ?
hypershift-operator 47.93% <ø> (ø)
other 27.77% <ø> (ø)

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

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

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: 4

🧹 Nitpick comments (2)
control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/catalogd/deployment.go (1)

23-31: ⚡ Quick win

Guard against duplicate --external-address / --system-namespace args

container.Args = append(...) is unconditional. If the base deployment manifest already includes --external-address or --system-namespace, the container will receive duplicate flags. Most cobra/pflag-based binaries treat duplicate flags as a fatal error, causing the pod to crash-loop.

♻️ Proposed fix
-		if container.Name == ComponentName {
-			container.Args = append(container.Args,
-				fmt.Sprintf("--external-address=%s", externalAddress),
-				fmt.Sprintf("--system-namespace=%s", cpContext.HCP.Namespace),
-			)
-		}
+		if container.Name == ComponentName {
+			upsertArg := func(args []string, flag, value string) []string {
+				prefix := flag + "="
+				for _, a := range args {
+					if strings.HasPrefix(a, prefix) {
+						return args // already set, skip
+					}
+				}
+				return append(args, fmt.Sprintf("%s=%s", flag, value))
+			}
+			container.Args = upsertArg(container.Args, "--external-address", externalAddress)
+			container.Args = upsertArg(container.Args, "--system-namespace", cpContext.HCP.Namespace)
+		}

(Add "strings" to the import block.)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/catalogd/deployment.go`
around lines 23 - 31, The code unconditionally appends flags to container.Args
causing duplicate --external-address or --system-namespace flags; update the
loop that finds the container (container :=
&deployment.Spec.Template.Spec.Containers[i]) to first scan container.Args
(using strings.HasPrefix) for existing "--external-address=" and
"--system-namespace=" entries and only append the corresponding fmt.Sprintf(...)
args when they are not already present; add "strings" to the import block to use
strings.HasPrefix and reference ComponentName, externalAddress and
cpContext.HCP.Namespace when constructing the flags.
control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/util/util.go (1)

33-51: ⚡ Quick win

Prefer podspec.UpsertEnvVars for env var injection and add volume dedup guards

Three raw append calls here (Volumes, VolumeMounts, Env) have no duplicate checks. If the base deployment manifest already declares a "kubeconfig" volume or a "KUBECONFIG" env var, calling this function will:

  • Create a duplicate volume → Kubernetes admission will reject the pod.
  • Create duplicate env vars → only consistent by convention with the last-wins rule, not intent.

The env var injection is inconsistent with the podspec.UpsertEnvVars pattern used by the other OLMv1 adapters (clusterolmoperator, consoleoperator). Apply the same approach here and guard the volume/mount injection:

♻️ Proposed fix
-	deployment.Spec.Template.Spec.Volumes = append(deployment.Spec.Template.Spec.Volumes, hostedKubeconfigVolume)
+	// Only add the volume if it is not already present (idempotency)
+	volumeExists := false
+	for _, v := range deployment.Spec.Template.Spec.Volumes {
+		if v.Name == "kubeconfig" {
+			volumeExists = true
+			break
+		}
+	}
+	if !volumeExists {
+		deployment.Spec.Template.Spec.Volumes = append(deployment.Spec.Template.Spec.Volumes, hostedKubeconfigVolume)
+	}

 	for i := range deployment.Spec.Template.Spec.Containers {
 		container := &deployment.Spec.Template.Spec.Containers[i]

-		container.VolumeMounts = append(container.VolumeMounts, corev1.VolumeMount{
-			Name:      "kubeconfig",
-			MountPath: "/etc/openshift/kubeconfig",
-			ReadOnly:  true,
-		})
-
-		container.Env = append(container.Env, corev1.EnvVar{
-			Name:  "KUBECONFIG",
-			Value: kubeconfigPath,
-		})
+		// Only add the volume mount if not already present
+		mountExists := false
+		for _, vm := range container.VolumeMounts {
+			if vm.Name == "kubeconfig" {
+				mountExists = true
+				break
+			}
+		}
+		if !mountExists {
+			container.VolumeMounts = append(container.VolumeMounts, corev1.VolumeMount{
+				Name:      "kubeconfig",
+				MountPath: "/etc/openshift/kubeconfig",
+				ReadOnly:  true,
+			})
+		}
+		// Use UpsertEnvVars for idempotent env var injection
+		podspec.UpsertEnvVars(container, []corev1.EnvVar{
+			{Name: "KUBECONFIG", Value: kubeconfigPath},
+		})
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/util/util.go`
around lines 33 - 51, The code currently appends a "kubeconfig" Volume,
per-container VolumeMount and a raw EnvVar "KUBECONFIG" unconditionally (see
deployment.Spec.Template.Spec.Volumes, corev1.VolumeMount{Name: "kubeconfig"},
and EnvVar{Name: "KUBECONFIG"}), which can create duplicates; update the logic
to first check for an existing volume named "kubeconfig" and only append if
missing, check each container.VolumeMounts for an existing mount named
"kubeconfig" before appending, and replace the raw container.Env append with the
shared podspec.UpsertEnvVars utility to upsert the "KUBECONFIG" env var (use
UpsertEnvVars on each container) so envs follow the established pattern and
avoid duplicate env entries.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/catalogd/component.go`:
- Line 40: The call to InjectAvailabilityProberContainer is passing the wrong
type namespace: replace component.AvailabilityProberOpts with
podspec.AvailabilityProberOpts where InjectAvailabilityProberContainer(...) is
invoked (e.g., in the function(s) that call InjectAvailabilityProberContainer in
component.go and the sibling operatorcontroller/component.go), so the passed
struct type matches the method signature and the rest of the codebase.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/clusterolmoperator/deployment.go`:
- Around line 31-36: Update the stale comment that references IN_CLUSTER_MODE to
correctly reference the actual environment variable HYPERSHIFT_MODE used in the
deployment (the env entry {Name: "HYPERSHIFT_MODE", Value: "true"}); edit the
comment text above that env var so it describes HYPERSHIFT_MODE and its
semantics (use HOSTED_KUBECONFIG for ClusterCatalog/ClusterExtension and
in-cluster config for ClusterOperator status reporting) to avoid confusion when
cross-referencing operator env-var docs.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/clusterolmoperator/HYPERSHIFT_DUAL_API.md`:
- Around line 190-192: Update the three local filesystem references in
HYPERSHIFT_DUAL_API.md (the entries for the Enhancement Proposal, HyperShift
Component, and Shared Kubeconfig Utility) to use repository-relative paths or
canonical GitHub URLs instead of `~/devel/...`; locate the three lines listing
`~/devel/openshift/enhancements/enhancements/olm/olmv1-hypershift-support.md`,
`~/devel/openshift/hypershift/control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/clusterolmoperator/`,
and
`~/devel/openshift/hypershift/control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/util/util.go`
and replace each with the appropriate repo-relative path (e.g., relative path
from repo root) or full GitHub URL to the target file/directory. Ensure links
are valid and use the same markdown list format.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/consoleoperator/component.go`:
- Around line 39-46: The availability prober is configured with
KubeconfigVolumeName: "kubeconfig" but adaptDeployment never injects that
volume; update adaptDeployment to call util.InjectHostedClusterKubeconfig so the
"kubeconfig" volume is created (matching other OLMv1 components) and keep
InjectAvailabilityProberContainer(...) as-is, or alternatively change
InjectAvailabilityProberContainer call to set KubeconfigVolumeName to "" if you
intend to use in-cluster config; also reconcile the NeedsManagementKASAccess()
return/comment to reflect the chosen approach.

---

Nitpick comments:
In
`@control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/catalogd/deployment.go`:
- Around line 23-31: The code unconditionally appends flags to container.Args
causing duplicate --external-address or --system-namespace flags; update the
loop that finds the container (container :=
&deployment.Spec.Template.Spec.Containers[i]) to first scan container.Args
(using strings.HasPrefix) for existing "--external-address=" and
"--system-namespace=" entries and only append the corresponding fmt.Sprintf(...)
args when they are not already present; add "strings" to the import block to use
strings.HasPrefix and reference ComponentName, externalAddress and
cpContext.HCP.Namespace when constructing the flags.

In `@control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/util/util.go`:
- Around line 33-51: The code currently appends a "kubeconfig" Volume,
per-container VolumeMount and a raw EnvVar "KUBECONFIG" unconditionally (see
deployment.Spec.Template.Spec.Volumes, corev1.VolumeMount{Name: "kubeconfig"},
and EnvVar{Name: "KUBECONFIG"}), which can create duplicates; update the logic
to first check for an existing volume named "kubeconfig" and only append if
missing, check each container.VolumeMounts for an existing mount named
"kubeconfig" before appending, and replace the raw container.Env append with the
shared podspec.UpsertEnvVars utility to upsert the "KUBECONFIG" env var (use
UpsertEnvVars on each container) so envs follow the established pattern and
avoid duplicate env entries.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: 4056123a-540f-481f-94c8-e63e7f8f5c91

📥 Commits

Reviewing files that changed from the base of the PR and between bded456 and 3fbf303.

📒 Files selected for processing (18)
  • control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/assets/catalogd/service.yaml
  • control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/catalogd/component.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/catalogd/deployment.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/catalogd/service.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/clusterolmoperator/HYPERSHIFT_DUAL_API.md
  • control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/clusterolmoperator/component.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/clusterolmoperator/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/clusterolmoperator/deployment.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/clusterolmoperator/deployment_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/component.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/consoleoperator/component.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/consoleoperator/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/consoleoperator/deployment.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/consoleoperator/deployment_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/operatorcontroller/component.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/operatorcontroller/deployment.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/util/util.go

"service.yaml",
component.WithAdaptFunction(adaptService),
).
InjectAvailabilityProberContainer(component.AvailabilityProberOpts{
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== InjectAvailabilityProberContainer signatures =="
rg -n --type=go 'InjectAvailabilityProberContainer\s*\('

echo
echo "== AvailabilityProberOpts type declarations/aliases =="
rg -n --type=go 'type\s+AvailabilityProberOpts\b'

echo
echo "== Call sites in new OLMv1 components =="
rg -n --type=go 'InjectAvailabilityProberContainer\(' control-plane-operator/controllers/hostedcontrolplane/v2/olmv1

Repository: openshift/hypershift

Length of output: 5203


Use podspec.AvailabilityProberOpts instead of component.AvailabilityProberOpts to match the method signature.

Line 40 uses the non-existent component.AvailabilityProberOpts type. The InjectAvailabilityProberContainer method expects podspec.AvailabilityProberOpts. Additionally, the sibling operatorcontroller/component.go:36 in the same olmv1 group has the same issue. All other components in the codebase correctly use podspec.AvailabilityProberOpts.

Fix
 import (
 	component "github.com/openshift/hypershift/support/controlplane-component"
+	"github.com/openshift/hypershift/support/podspec"
 	"k8s.io/apimachinery/pkg/runtime/schema"
 )
@@
-		InjectAvailabilityProberContainer(component.AvailabilityProberOpts{
+		InjectAvailabilityProberContainer(podspec.AvailabilityProberOpts{
 			KubeconfigVolumeName: "kubeconfig",
 			RequiredAPIs: []schema.GroupVersionKind{
 				{Group: "olm.operatorframework.io", Version: "v1", Kind: "ClusterCatalog"},
 			},
 		}).
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
InjectAvailabilityProberContainer(component.AvailabilityProberOpts{
import (
component "github.com/openshift/hypershift/support/controlplane-component"
"github.com/openshift/hypershift/support/podspec"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// ... other code ...
InjectAvailabilityProberContainer(podspec.AvailabilityProberOpts{
KubeconfigVolumeName: "kubeconfig",
RequiredAPIs: []schema.GroupVersionKind{
{Group: "olm.operatorframework.io", Version: "v1", Kind: "ClusterCatalog"},
},
}).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/catalogd/component.go`
at line 40, The call to InjectAvailabilityProberContainer is passing the wrong
type namespace: replace component.AvailabilityProberOpts with
podspec.AvailabilityProberOpts where InjectAvailabilityProberContainer(...) is
invoked (e.g., in the function(s) that call InjectAvailabilityProberContainer in
component.go and the sibling operatorcontroller/component.go), so the passed
struct type matches the method signature and the rest of the codebase.

Comment on lines +31 to +36
// IN_CLUSTER_MODE tells cluster-olm-operator it's running in HyperShift mode
// In this mode, it should:
// - Use HOSTED_KUBECONFIG client for ClusterCatalog/ClusterExtension
// - Use in-cluster config for ClusterOperator status reporting to management cluster
{Name: "HYPERSHIFT_MODE", Value: "true"},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Stale comment — says IN_CLUSTER_MODE but the env var is HYPERSHIFT_MODE

The comment on line 34 describes IN_CLUSTER_MODE while the actual env var injected is HYPERSHIFT_MODE. This will confuse anyone cross-referencing the operator's env-var documentation.

📝 Proposed fix
-			// IN_CLUSTER_MODE tells cluster-olm-operator it's running in HyperShift mode
-			// In this mode, it should:
-			// - Use HOSTED_KUBECONFIG client for ClusterCatalog/ClusterExtension
-			// - Use in-cluster config for ClusterOperator status reporting to management cluster
+			// HYPERSHIFT_MODE tells cluster-olm-operator it's running in HyperShift mode.
+			// In this mode, it should:
+			// - Use HOSTED_KUBECONFIG client for ClusterCatalog/ClusterExtension
+			// - Use in-cluster config for ClusterOperator status reporting to management cluster
 			{Name: "HYPERSHIFT_MODE", Value: "true"},
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/clusterolmoperator/deployment.go`
around lines 31 - 36, Update the stale comment that references IN_CLUSTER_MODE
to correctly reference the actual environment variable HYPERSHIFT_MODE used in
the deployment (the env entry {Name: "HYPERSHIFT_MODE", Value: "true"}); edit
the comment text above that env var so it describes HYPERSHIFT_MODE and its
semantics (use HOSTED_KUBECONFIG for ClusterCatalog/ClusterExtension and
in-cluster config for ClusterOperator status reporting) to avoid confusion when
cross-referencing operator env-var docs.

Comment on lines +190 to +192
- Enhancement Proposal: `~/devel/openshift/enhancements/enhancements/olm/olmv1-hypershift-support.md`
- HyperShift Component: `~/devel/openshift/hypershift/control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/clusterolmoperator/`
- Shared Kubeconfig Utility: `~/devel/openshift/hypershift/control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/util/util.go`
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Replace local filesystem references with repo/URL links

Line 190–192 use ~/devel/... paths, which are not usable for other contributors. Please switch to repository-relative paths or canonical GitHub URLs.

Suggested patch
-- Enhancement Proposal: `~/devel/openshift/enhancements/enhancements/olm/olmv1-hypershift-support.md`
-- HyperShift Component: `~/devel/openshift/hypershift/control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/clusterolmoperator/`
-- Shared Kubeconfig Utility: `~/devel/openshift/hypershift/control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/util/util.go`
+- Enhancement Proposal: `https://github.com/openshift/enhancements/blob/master/enhancements/olm/olmv1-hypershift-support.md`
+- HyperShift Component: `control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/clusterolmoperator/`
+- Shared Kubeconfig Utility: `control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/util/util.go`
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- Enhancement Proposal: `~/devel/openshift/enhancements/enhancements/olm/olmv1-hypershift-support.md`
- HyperShift Component: `~/devel/openshift/hypershift/control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/clusterolmoperator/`
- Shared Kubeconfig Utility: `~/devel/openshift/hypershift/control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/util/util.go`
- Enhancement Proposal: `https://github.com/openshift/enhancements/blob/master/enhancements/olm/olmv1-hypershift-support.md`
- HyperShift Component: `control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/clusterolmoperator/`
- Shared Kubeconfig Utility: `control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/util/util.go`
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/clusterolmoperator/HYPERSHIFT_DUAL_API.md`
around lines 190 - 192, Update the three local filesystem references in
HYPERSHIFT_DUAL_API.md (the entries for the Enhancement Proposal, HyperShift
Component, and Shared Kubeconfig Utility) to use repository-relative paths or
canonical GitHub URLs instead of `~/devel/...`; locate the three lines listing
`~/devel/openshift/enhancements/enhancements/olm/olmv1-hypershift-support.md`,
`~/devel/openshift/hypershift/control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/clusterolmoperator/`,
and
`~/devel/openshift/hypershift/control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/util/util.go`
and replace each with the appropriate repo-relative path (e.g., relative path
from repo root) or full GitHub URL to the target file/directory. Ensure links
are valid and use the same markdown list format.

Comment on lines +39 to +46
InjectAvailabilityProberContainer(podspec.AvailabilityProberOpts{
KubeconfigVolumeName: "kubeconfig",
RequiredAPIs: []schema.GroupVersionKind{
{Group: "", Version: "v1", Kind: "Service"},
{Group: "", Version: "v1", Kind: "ConfigMap"},
},
}).
Build()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if the console-operator base deployment manifest provides a "kubeconfig" volume
# and compare with other OLMv1 component manifests
fd -t f -e yaml . | xargs grep -l "console-operator" 2>/dev/null | head -20

# Check the embedded asset directories for OLMv1 manifests
rg -n "kubeconfig" --type=yaml --iglob "*console-operator*" 2>/dev/null

# Check for assets/console-operator directory
fd -t d "console-operator" | head -10

# Check how InjectAvailabilityProberContainer uses KubeconfigVolumeName
ast-grep --pattern 'func InjectAvailabilityProberContainer($$$) {
  $$$
}'

# Also check how other OLMv1 components reference kubeconfig volumes
rg -n "KubeconfigVolumeName" --type=go -A2 -B2

Repository: openshift/hypershift

Length of output: 20480


🏁 Script executed:

#!/bin/bash

# Find the adaptDeployment function in consoleoperator
echo "=== consoleoperator adaptDeployment ==="
cat control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/consoleoperator/component.go | head -50

echo -e "\n=== catalogd adaptDeployment ==="
fd component.go control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/catalogd/ | xargs cat | head -50

echo -e "\n=== operatorcontroller adaptDeployment ==="
fd component.go control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/operatorcontroller/ | xargs cat | head -50

# Search for InjectHostedClusterKubeconfig usage
echo -e "\n=== InjectHostedClusterKubeconfig usage ==="
rg "InjectHostedClusterKubeconfig" -A2 -B2 control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/

# Search for util package that might have this function
echo -e "\n=== Search for util.InjectHostedClusterKubeconfig or similar ==="
rg "InjectHostedClusterKubeconfig" --type=go -A2 -B2

Repository: openshift/hypershift

Length of output: 12276


🏁 Script executed:

#!/bin/bash

# Find and read the consoleoperator deployment.go file
echo "=== consoleoperator deployment.go (adaptDeployment) ==="
find control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/consoleoperator -name "*.go" -type f
echo ""
cat control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/consoleoperator/deployment.go

echo -e "\n=== util.InjectHostedClusterKubeconfig implementation ==="
cat control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/util/util.go

Repository: openshift/hypershift

Length of output: 3961


KubeconfigVolumeName: "kubeconfig" references a volume that is never injected into the console-operator pod

The console-operator's adaptDeployment only sets proxy environment variables and RELEASE_VERSION—it never calls util.InjectHostedClusterKubeconfig, which is required to inject the "kubeconfig" volume. Every other OLMv1 component (catalogd, operatorcontroller, clusterolmoperator) calls this function. The availability prober's volumeMount will reference a non-existent volume, causing Kubernetes to reject the pod at admission.

Additionally, the design is inconsistent: NeedsManagementKASAccess() returns false with the comment "Only needs hosted cluster API access via in-cluster config", yet the availability prober is configured to use a kubeconfig file. Either:

  1. Call util.InjectHostedClusterKubeconfig in adaptDeployment (to match other OLMv1 components and provide the kubeconfig volume), or
  2. Set KubeconfigVolumeName to an empty string if in-cluster config is sufficient.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/consoleoperator/component.go`
around lines 39 - 46, The availability prober is configured with
KubeconfigVolumeName: "kubeconfig" but adaptDeployment never injects that
volume; update adaptDeployment to call util.InjectHostedClusterKubeconfig so the
"kubeconfig" volume is created (matching other OLMv1 components) and keep
InjectAvailabilityProberContainer(...) as-is, or alternatively change
InjectAvailabilityProberContainer call to set KubeconfigVolumeName to "" if you
intend to use in-cluster config; also reconcile the NeedsManagementKASAccess()
return/comment to reflect the chosen approach.

@grokspawn grokspawn changed the title add OLMv1 controlplane hoists WIP: add OLMv1 controlplane hoists May 8, 2026
@hypershift-jira-solve-ci
Copy link
Copy Markdown

CI Failure Analysis: PR #8470 — "WIP: add OLMv1 controlplane hoists"

Repository: openshift/hypershift
PR: #8470
Analysis Date: 2026-05-09
Mode: --fast (no must-gather)


Shared Root Causes

All 6 failing jobs trace back to 3 compilation errors in newly-added OLMv1 component files and 1 commit-message lint error. The compilation errors are in 4 files under control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/.


Job Failures

1. pull-ci-openshift-hypershift-main-verify

Status: ❌ FAILED — gitlint commit message validation

Root Cause

The commit title add OLMv1 controlplane hoists violates the repository's Conventional Commits format enforced by gitlint rule CT1. The title must match the pattern type(optional-scope): description (e.g. feat:, fix:, chore:).

Recommendations
  • Amend the commit message to follow Conventional Commits format, e.g.:
    feat: add OLMv1 controlplane hoists
    
  • Valid type prefixes include: feat, fix, chore, docs, refactor, test, ci.
Evidence
1: CT1 Title does not follow ConventionalCommits format 'type(optional-scope): description'
1: "add OLMv1 controlplane hoists"

2. pull-ci-openshift-hypershift-main-unit-cpo-other

Status: ❌ FAILED — Go compilation errors (3 distinct)

Root Cause

Three compilation errors prevent the control-plane-operator from building. All originate in new files added by this PR:

Error A — RolloutOnSecretChange undefined:
Files catalogd/component.go (line 35) and operatorcontroller/component.go (line 35) call .RolloutOnSecretChange("admin-kubeconfig") on controlPlaneWorkloadBuilder. This method is documented in the README.md but does not exist in support/controlplane-component/builder.go. The builder's actual method set is: WithAdaptFunction, WithPredicate, WithManifestAdapter, WithDependencies, InjectKonnectivityContainer, InjectAvailabilityProberContainer, InjectTokenMinterContainer, WithCustomOperandsRolloutCheckFunc, MonitorOperandsRolloutStatus, Build.

Error B — component.AvailabilityProberOpts undefined:
Files catalogd/component.go (line 40) and operatorcontroller/component.go (line 36) reference component.AvailabilityProberOpts{}. The type AvailabilityProberOpts lives in support/podspec, not in support/controlplane-component. The existing OLMv0 component (v2/olm/catalog_operator/component.go) correctly uses podspec.AvailabilityProberOpts{} with import "github.com/openshift/hypershift/support/podspec".

Error C — testutil.FakeReleaseImageProvider undefined:
Files clusterolmoperator/deployment_test.go (line 41) and consoleoperator/deployment_test.go (line 41) instantiate &testutil.FakeReleaseImageProvider{Version: "4.17.0"}. No such exported type exists in support/testutil/fake.go. The exported API is a constructor function testutil.FakeImageProvider(opts ...FakeImageProviderOpt) with option testutil.WithVersion("4.17.0").

Recommendations

Fix A: Remove .RolloutOnSecretChange("admin-kubeconfig") from the builder chains in catalogd/component.go and operatorcontroller/component.go. Alternatively, implement the method on controlPlaneWorkloadBuilder in support/controlplane-component/builder.go if the functionality is actually needed.

Fix B: In catalogd/component.go and operatorcontroller/component.go:

  • Add import: "github.com/openshift/hypershift/support/podspec"
  • Replace component.AvailabilityProberOpts{}podspec.AvailabilityProberOpts{}
  • Reference the existing pattern in v2/olm/catalog_operator/component.go.

Fix C: In clusterolmoperator/deployment_test.go and consoleoperator/deployment_test.go:

  • Replace:
    &testutil.FakeReleaseImageProvider{Version: "4.17.0"}
    with:
    testutil.FakeImageProvider(testutil.WithVersion("4.17.0"))
Evidence
control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/catalogd/component.go:35:4:
  builder.RolloutOnSecretChange undefined (type *component.controlPlaneWorkloadBuilder has no field or method RolloutOnSecretChange)

control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/catalogd/component.go:40:30:
  undefined: component.AvailabilityProberOpts

control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/operatorcontroller/component.go:35:4:
  builder.RolloutOnSecretChange undefined (type *component.controlPlaneWorkloadBuilder has no field or method RolloutOnSecretChange)

control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/operatorcontroller/component.go:36:30:
  undefined: component.AvailabilityProberOpts

control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/clusterolmoperator/deployment_test.go:41:26:
  undefined: testutil.FakeReleaseImageProvider

control-plane-operator/controllers/hostedcontrolplane/v2/olmv1/consoleoperator/deployment_test.go:41:26:
  undefined: testutil.FakeReleaseImageProvider

Correct pattern from existing v2/olm/catalog_operator/component.go:

import "github.com/openshift/hypershift/support/podspec"
// ...
InjectAvailabilityProberContainer(podspec.AvailabilityProberOpts{})
// No RolloutOnSecretChange call

Correct pattern from support/testutil/fake.go:

func FakeImageProvider(opts ...FakeImageProviderOpt) *fakeImageProvider { ... }
func WithVersion(version string) FakeImageProviderOpt { ... }

3. pull-ci-openshift-hypershift-main-unit-cpo-hypershift

Status: ❌ FAILED — same 3 compilation errors as job #2

Root Cause

Identical compilation failures (Errors A, B, C above). This test shard compiles the same control-plane-operator package and fails at the same build stage.

Recommendations

Same fixes as job #2. Fixing the 4 source files resolves this job.

Evidence

Same compiler output as job #2 — all 6 error lines from the same 4 files under v2/olmv1/.


4. pull-ci-openshift-hypershift-main-unit-hypershift-operator

Status: ❌ FAILED — same 3 compilation errors as job #2

Root Cause

Identical compilation failures (Errors A, B, C). The hypershift-operator unit tests transitively depend on the control-plane-operator packages including the new OLMv1 components. The build fails before any tests execute.

Recommendations

Same fixes as job #2. No hypershift-operator-specific changes needed.

Evidence

Same compiler output as job #2 — transitive dependency chain: hypershift-operatorcontrol-plane-operatorv2/olmv1/*.


5. pull-ci-openshift-hypershift-main-unit-util

Status: ❌ FAILED — same 3 compilation errors as job #2

Root Cause

Identical compilation failures (Errors A, B, C). The util unit test shard also has a transitive compile-time dependency on the OLMv1 packages.

Recommendations

Same fixes as job #2.

Evidence

Same compiler output as job #2.


6. pull-ci-openshift-hypershift-main-build-images (Konflux)

Status: ❌ FAILED — build-images step fails during make control-plane-operator

Root Cause

The Konflux PipelineRun reaches the build-images step which invokes make control-plane-operator. This triggers the Go compiler, which hits the same 3 compilation errors (A, B, C) in the OLMv1 packages. The build exits with a non-zero status and the pipeline fails.

Recommendations

Same fixes as job #2. The Konflux build is a downstream consumer of go build — once the source compiles cleanly, this pipeline will pass.

Evidence

Pipeline step build-images logs show make invoking go build for control-plane-operator, which produces the same 6 compiler error lines from the 4 OLMv1 files.


Summary

# Job Root Cause Fix
1 verify Commit title violates ConventionalCommits (CT1) Rename to feat: add OLMv1 controlplane hoists
2 unit-cpo-other 3 compilation errors in 4 new OLMv1 files See Errors A/B/C fixes
3 unit-cpo-hypershift Same compilation errors (direct dependency) Same fixes
4 unit-hypershift-operator Same compilation errors (transitive dependency) Same fixes
5 unit-util Same compilation errors (transitive dependency) Same fixes
6 build-images Same compilation errors (makego build) Same fixes

Total unique bugs: 4 (3 compilation + 1 lint)
Files to fix: catalogd/component.go, operatorcontroller/component.go, clusterolmoperator/deployment_test.go, consoleoperator/deployment_test.go, plus the commit message.


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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant