Skip to content

OCPCLOUD-2208: Add cluster-wide proxy support for CAPI controllers#517

Open
lunarwhite wants to merge 3 commits intoopenshift:mainfrom
lunarwhite:proxy
Open

OCPCLOUD-2208: Add cluster-wide proxy support for CAPI controllers#517
lunarwhite wants to merge 3 commits intoopenshift:mainfrom
lunarwhite:proxy

Conversation

@lunarwhite
Copy link
Copy Markdown
Contributor

@lunarwhite lunarwhite commented Apr 2, 2026

Summary

When an OpenShift cluster is configured with a cluster-wide proxy (oc get proxy cluster), CAPI provider Deployments need the proxy environment variables to reach external endpoints.

This PR reads the proxy configuration from proxy.Status and injects env vars during manifest rendering:

  • Add pkg/util/proxy.go to read the Proxy CR status and inject env vars into Deployment containers.
  • Add WithProxyConfig render option to the revision generator for proxy injection during manifest rendering.
  • RevisionController watches configv1.Proxy and triggers new revisions on proxy changes.
  • InstallerController reads Proxy to keep content IDs consistent when re-rendering revisions.
  • Env vars with the same name as a proxy var are not overwritten. Only non-empty status fields produce env vars.

What have been tested

@openshift-ci-robot
Copy link
Copy Markdown

Pipeline controller notification
This repo is configured to use the pipeline controller. Second-stage tests will be triggered either automatically or after lgtm label is added, depending on the repository configuration. The pipeline controller will automatically detect which contexts are required and will utilize /test Prow commands to trigger the second stage.

For optional jobs, comment /test ? to see a list of all defined jobs. To trigger manually all jobs from second stage use /pipeline required command.

This repository is configured in: LGTM mode

@openshift-ci openshift-ci bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Apr 2, 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 Apr 2, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci bot commented Apr 2, 2026

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@openshift-ci-robot
Copy link
Copy Markdown

openshift-ci-robot commented Apr 2, 2026

@lunarwhite: This pull request references OCPCLOUD-2208 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:

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.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 2, 2026

Important

Review skipped

Auto reviews are limited based on label configuration.

🚫 Review skipped — only excluded labels are configured. (1)
  • do-not-merge/work-in-progress

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

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

Review profile: CHILL

Plan: Pro

Run ID: 70085e84-1d4a-492e-9622-298fb83813d1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

This change adds cluster-wide proxy configuration support to the installer and revision controllers. Controllers now read proxy settings from the configv1.Proxy resource, convert them to environment variables, inject them into provider Deployments during manifest rendering, and watch proxy resource changes to trigger reconciliation.

Changes

Cohort / File(s) Summary
Controllers - Proxy Integration
pkg/controllers/capiinstaller/capi_installer_controller.go, pkg/controllers/installer/installer_controller.go, pkg/controllers/revision/revision_controller.go
Each controller now reads cluster-wide proxy configuration via util.GetProxy, derives environment variables via util.ProxyEnvVars, logs when present, and passes proxy config as render options to revision generation. Controllers also extend their watch sets to trigger reconciliation on configv1.Proxy resource changes.
Revision Reconciliation
pkg/controllers/installer/revision_reconciler.go
Updated constructor to accept variadic render options and composite them with object collectors during manifest rendering via NewInstallerRevisionFromAPI.
Proxy Utilities
pkg/util/proxy.go, pkg/util/proxy_test.go
New file implements proxy configuration retrieval (GetProxy), conversion to environment variables (ProxyEnvVars), and injection into both typed Deployments and unstructured manifests (InjectProxyEnvVarsIntoDeployment, InjectProxyEnvVarsIntoUnstructured). Comprehensive test coverage validates env var generation, injection into containers and init containers, and behavior with various workload types.
Revision Generation
pkg/revisiongenerator/revision.go, pkg/revisiongenerator/revision_test.go
Exported RevisionRenderOption type; added WithProxyConfig option to store proxy environment variables; updated manifest processing to inject proxy env vars into Deployments via unstructured object mutation during rendering. Tests verify proxy configuration alters revision ContentID and env vars are correctly injected.
Test Helpers
pkg/controllers/installer/helpers_test.go, pkg/controllers/revision/helpers_test.go, pkg/controllers/revision/suite_test.go
Extended fixtures to create configv1.Proxy singleton resources; added helper to create render options with proxy config; introduced makeDeploymentAvailable helper for test setup; added new deploymentProviderImgs fixture containing provider images with Deployment manifests.
Integration Tests
pkg/controllers/installer/installer_controller_test.go, pkg/controllers/revision/revision_controller_test.go
New test suites validate proxy injection into deployed Deployments and verify revision ContentID changes when proxy configuration is added or removed. Tests assert proxy env vars appear in container specs only when proxy is configured.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~28 minutes

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

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

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci bot commented Apr 2, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

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

Comment on lines +122 to +134
// Read cluster-wide proxy configuration
proxy, err := util.GetProxy(ctx, r.Client)
if err != nil {
return ctrl.Result{}, fmt.Errorf("fetching proxy: %w", err)
}

proxyEnvVars := util.ProxyEnvVars(proxy)

if len(proxyEnvVars) > 0 {
log.Info("Injecting proxy configuration into provider deployments",
"httpProxy", proxy.Status.HTTPProxy, "httpsProxy", proxy.Status.HTTPSProxy, "noProxy", proxy.Status.NoProxy)
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I haven't given a careful read but
We would probably want to do this before starting these controllers, so before setting up the controller-runtime manager.
Then inject that down to each controller to use it.

Copy link
Copy Markdown
Contributor Author

@lunarwhite lunarwhite Apr 10, 2026

Choose a reason for hiding this comment

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

Thanks for your review @damdo. Are you suggesting 'read once, inject at startup'? I thought that, in this case, proxy changes (can change at runtime) would remain invisible until the operator restarts. Or am I overlooking something?

I noticed #507 was landed these days so I remove the touch to capiinstaller entirely

@lunarwhite lunarwhite force-pushed the proxy branch 4 times, most recently from 7974ca8 to 84794ac Compare April 7, 2026 08:50
@lunarwhite lunarwhite changed the title OCPCLOUD-2208: Add cluster-wide proxy support for CAPI controllers [WIP] OCPCLOUD-2208: Add cluster-wide proxy support for CAPI controllers Apr 7, 2026
@lunarwhite lunarwhite marked this pull request as ready for review April 7, 2026 09:59
@openshift-ci openshift-ci bot requested review from chrischdi and mdbooth April 7, 2026 09:59
@lunarwhite
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 7, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (3)
pkg/util/proxy.go (2)

47-75: Verify uppercase-only proxy vars are sufficient.

This helper emits only HTTP_PROXY, HTTPS_PROXY, and NO_PROXY. If any controller image, wrapper script, or diagnostic tooling relies on the conventional lowercase aliases, proxy support will still be partial.

Possible change
 	if proxy.Status.HTTPProxy != "" {
-		envVars = append(envVars, corev1.EnvVar{
-			Name:  "HTTP_PROXY",
-			Value: proxy.Status.HTTPProxy,
-		})
+		envVars = append(envVars,
+			corev1.EnvVar{Name: "HTTP_PROXY", Value: proxy.Status.HTTPProxy},
+			corev1.EnvVar{Name: "http_proxy", Value: proxy.Status.HTTPProxy},
+		)
 	}
 
 	if proxy.Status.HTTPSProxy != "" {
-		envVars = append(envVars, corev1.EnvVar{
-			Name:  "HTTPS_PROXY",
-			Value: proxy.Status.HTTPSProxy,
-		})
+		envVars = append(envVars,
+			corev1.EnvVar{Name: "HTTPS_PROXY", Value: proxy.Status.HTTPSProxy},
+			corev1.EnvVar{Name: "https_proxy", Value: proxy.Status.HTTPSProxy},
+		)
 	}
 
 	if proxy.Status.NoProxy != "" {
-		envVars = append(envVars, corev1.EnvVar{
-			Name:  "NO_PROXY",
-			Value: proxy.Status.NoProxy,
-		})
+		envVars = append(envVars,
+			corev1.EnvVar{Name: "NO_PROXY", Value: proxy.Status.NoProxy},
+			corev1.EnvVar{Name: "no_proxy", Value: proxy.Status.NoProxy},
+		)
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/util/proxy.go` around lines 47 - 75, The ProxyEnvVars function currently
emits only uppercase HTTP_PROXY/HTTPS_PROXY/NO_PROXY which can break tools
expecting lowercase variants; update ProxyEnvVars to also append the lowercase
aliases "http_proxy", "https_proxy", and "no_proxy" alongside their uppercase
counterparts (ensuring you don't create duplicates when values are empty) so
both variants are present for any consumer that expects lowercase; locate
ProxyEnvVars in pkg/util/proxy.go and add the additional corev1.EnvVar entries
for each proxy field (Status.HTTPProxy, Status.HTTPSProxy, Status.NoProxy).

82-160: Keep one proxy-env merge implementation.

InjectProxyEnvVarsIntoUnstructured and InjectProxyEnvVarsIntoDeployment each reimplement the same de-dupe/append rules. Because one path feeds revision ContentID generation and the other mutates typed Deployments, future drift here can turn into false content-ID mismatches or unnecessary rollouts. Consider extracting a shared merge routine and adapting both representations to it.

Also applies to: 165-189

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

In `@pkg/util/proxy.go` around lines 82 - 160, The two implementations
(InjectProxyEnvVarsIntoUnstructured and InjectProxyEnvVarsIntoDeployment)
duplicate the same de-duplication and append rules which can cause drift;
extract a single shared merge routine (e.g., MergeEnvVars or mergeProxyEnvVars)
that takes an existing env list and desired []corev1.EnvVar and returns a
deterministic merged []map[string]interface{} or []corev1.EnvVar (preserving
order and skipping existing names). Replace the logic inside
injectEnvVarsIntoContainer (and the Deployment mutator) to call this shared
function, and have injectEnvVarsAtPath and InjectProxyEnvVarsIntoDeployment
adapt typed vs unstructured representations to the same merge routine so both
paths use identical merging behavior.
pkg/controllers/installer/installer_controller_test.go (1)

601-658: Add a proxy-change reconciliation spec.

These cases only cover the proxy state at revision creation time. A spec that installs successfully first, then flips configv1.Proxy/status from empty→set (and ideally set→empty) would exercise the new Proxy watch path and catch regressions where existing Deployments do not roll to the updated env set.

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

In `@pkg/controllers/installer/installer_controller_test.go` around lines 601 -
658, Add a new test It in installer_controller_test.go that verifies
proxy-change reconciliation by (1) creating an initial revision without proxy
(use addRevision, makeDeploymentAvailable, waitForRevision), (2) updating the
cluster Proxy status to a non-empty value (fetch configv1.Proxy via cl.Get, set
Proxy.Status fields, cl.Status().Update), then wait for the controller to roll
the Deployment and assert the pod template now contains
HTTP_PROXY/HTTPS_PROXY/NO_PROXY env vars (read Deployment via cl.Get and check
deploy.Spec.Template.Spec.Containers[0].Env similar to the existing test); also
include the reverse case by clearing Proxy.Status (set empty/no-proxy and
cl.Status().Update) and asserting the env vars are removed after the rollout.
Use the same helper functions (addRevision, makeDeploymentAvailable,
waitForRevision) and util.ProxyEnvVars/revisiongenerator.WithProxyConfig where
needed to construct expected values.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/controllers/capiinstaller/capi_installer_controller.go`:
- Around line 130-133: The Info log in capi_installer_controller.go that calls
log.Info("Injecting proxy configuration into provider deployments", "httpProxy",
proxy.Status.HTTPProxy, ...) must not log raw proxy URLs as they may contain
credentials; update the code that logs proxy.Status.HTTPProxy,
proxy.Status.HTTPSProxy and proxy.Status.NoProxy (and the identical logging
sites in pkg/controllers/revision/revision_controller.go and
pkg/controllers/installer/installer_controller.go) to sanitize/redact any URL
userinfo before logging (e.g., parse with net/url, clear u.User or replace with
"<redacted>" and log only host/path or a presence indicator), handle empty/nil
values safely, and keep the same log keys so callers can find the logging call
(look for the log.Info invocation and the proxy.Status.* references to change).

In `@pkg/revisiongenerator/revision_test.go`:
- Around line 435-436: Remove the trailing whitespace/newline noise at the end
of the test file so the file ends with a single newline and no extra blank lines
or spaces; open pkg/revisiongenerator/revision_test.go, delete the extra
whitespace on the last lines (around the final closing brace) and ensure the
file terminates with exactly one newline (run gofmt/gofmt -w or trim trailing
whitespace in your editor before committing).

In `@pkg/util/proxy_test.go`:
- Around line 97-107: The file contains unformatted Go code around the test
table declaration (the for _, tc := range []struct { ... } block with fields
like wantEnvCount, wantContainers, wantInitEnvCount, wantInitContainers,
wantSkipInspect, wantEnvValues), causing golangci-lint to fail; fix by running
gofmt (or gofmt -w) / goimports on pkg/util/proxy_test.go to reformat the file
and commit the changes so the test table and surrounding code comply with gofmt
formatting rules.

---

Nitpick comments:
In `@pkg/controllers/installer/installer_controller_test.go`:
- Around line 601-658: Add a new test It in installer_controller_test.go that
verifies proxy-change reconciliation by (1) creating an initial revision without
proxy (use addRevision, makeDeploymentAvailable, waitForRevision), (2) updating
the cluster Proxy status to a non-empty value (fetch configv1.Proxy via cl.Get,
set Proxy.Status fields, cl.Status().Update), then wait for the controller to
roll the Deployment and assert the pod template now contains
HTTP_PROXY/HTTPS_PROXY/NO_PROXY env vars (read Deployment via cl.Get and check
deploy.Spec.Template.Spec.Containers[0].Env similar to the existing test); also
include the reverse case by clearing Proxy.Status (set empty/no-proxy and
cl.Status().Update) and asserting the env vars are removed after the rollout.
Use the same helper functions (addRevision, makeDeploymentAvailable,
waitForRevision) and util.ProxyEnvVars/revisiongenerator.WithProxyConfig where
needed to construct expected values.

In `@pkg/util/proxy.go`:
- Around line 47-75: The ProxyEnvVars function currently emits only uppercase
HTTP_PROXY/HTTPS_PROXY/NO_PROXY which can break tools expecting lowercase
variants; update ProxyEnvVars to also append the lowercase aliases "http_proxy",
"https_proxy", and "no_proxy" alongside their uppercase counterparts (ensuring
you don't create duplicates when values are empty) so both variants are present
for any consumer that expects lowercase; locate ProxyEnvVars in
pkg/util/proxy.go and add the additional corev1.EnvVar entries for each proxy
field (Status.HTTPProxy, Status.HTTPSProxy, Status.NoProxy).
- Around line 82-160: The two implementations
(InjectProxyEnvVarsIntoUnstructured and InjectProxyEnvVarsIntoDeployment)
duplicate the same de-duplication and append rules which can cause drift;
extract a single shared merge routine (e.g., MergeEnvVars or mergeProxyEnvVars)
that takes an existing env list and desired []corev1.EnvVar and returns a
deterministic merged []map[string]interface{} or []corev1.EnvVar (preserving
order and skipping existing names). Replace the logic inside
injectEnvVarsIntoContainer (and the Deployment mutator) to call this shared
function, and have injectEnvVarsAtPath and InjectProxyEnvVarsIntoDeployment
adapt typed vs unstructured representations to the same merge routine so both
paths use identical merging behavior.
🪄 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: 497d8be5-5c36-4bf9-9e54-ad77897accdf

📥 Commits

Reviewing files that changed from the base of the PR and between eb44334 and 84794ac.

📒 Files selected for processing (13)
  • pkg/controllers/capiinstaller/capi_installer_controller.go
  • pkg/controllers/installer/helpers_test.go
  • pkg/controllers/installer/installer_controller.go
  • pkg/controllers/installer/installer_controller_test.go
  • pkg/controllers/installer/revision_reconciler.go
  • pkg/controllers/revision/helpers_test.go
  • pkg/controllers/revision/revision_controller.go
  • pkg/controllers/revision/revision_controller_test.go
  • pkg/controllers/revision/suite_test.go
  • pkg/revisiongenerator/revision.go
  • pkg/revisiongenerator/revision_test.go
  • pkg/util/proxy.go
  • pkg/util/proxy_test.go

CAPI provider workloads need HTTP_PROXY/HTTPS_PROXY/NO_PROXY env vars
when the cluster is behind a proxy, otherwise they cannot reach external
endpoints.

Add pkg/util/proxy.go that reads the cluster-wide Proxy CR status and
injects proxy env vars into Deployment containers.
Proxy env vars must be part of the rendered revision so that content ID
reflects proxy changes and triggers a new rollout.

Add a RevisionRenderOption that injects proxy env vars into Deployment containers during rendering.
Controllers need to read the Proxy CR and pass it to the revision
generator so provider workloads get proxy env vars at deploy time.

Both controllers now fetch the Proxy CR and forward env vars via
WithProxyConfig. The revision controller watches Proxy to re-reconcile
when proxy config changes.
@openshift-ci-robot
Copy link
Copy Markdown

openshift-ci-robot commented Apr 10, 2026

@lunarwhite: This pull request references OCPCLOUD-2208 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:

Summary

When an OpenShift cluster is configured with a cluster-wide proxy (oc get proxy cluster), CAPI provider Deployments need the proxy environment variables to reach external endpoints.

This PR reads the proxy configuration from proxy.Status and injects env vars during manifest rendering:

  • Add pkg/util/proxy.go to read the Proxy CR status and inject env vars into Deployment containers.
  • Add WithProxyConfig render option to the revision generator for proxy injection during manifest rendering.
  • RevisionController watches configv1.Proxy and triggers new revisions on proxy changes.
  • InstallerController reads Proxy to keep content IDs consistent when re-rendering revisions.
  • Env vars with the same name as a proxy var are not overwritten. Only non-empty status fields produce env vars.

What have been tested

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.

@lunarwhite lunarwhite changed the title [WIP] OCPCLOUD-2208: Add cluster-wide proxy support for CAPI controllers OCPCLOUD-2208: Add cluster-wide proxy support for CAPI controllers Apr 10, 2026
@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 Apr 10, 2026
@damdo
Copy link
Copy Markdown
Member

damdo commented Apr 10, 2026

/ok-to-test

@openshift-ci openshift-ci bot added the ok-to-test Indicates a non-member PR verified by an org member that is safe to test. label Apr 10, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci bot commented Apr 10, 2026

@lunarwhite: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@damdo
Copy link
Copy Markdown
Member

damdo commented Apr 13, 2026

/assign @mdbooth

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

Labels

jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. ok-to-test Indicates a non-member PR verified by an org member that is safe to test.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants