Skip to content

OLS-3546 Dynamically reconcile metrics-reader ClusterRoleBinding namespace - #1852

Open
thoraxe wants to merge 2 commits into
openshift:mainfrom
thoraxe:fix/OLS-3546-metrics-crb-namespace
Open

OLS-3546 Dynamically reconcile metrics-reader ClusterRoleBinding namespace#1852
thoraxe wants to merge 2 commits into
openshift:mainfrom
thoraxe:fix/OLS-3546-metrics-crb-namespace

Conversation

@thoraxe

@thoraxe thoraxe commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add dynamic reconciliation of the metrics-reader ClusterRoleBinding to the operator's Phase 1 loop, using r.GetNamespace() so the subject namespace always matches the actual install namespace
  • Fix the kustomize source to use the standard system placeholder instead of the hardcoded openshift-lightspeed namespace
  • Handle three cases: CRB missing (create), wrong namespace (patch), subject missing entirely (replace with correct entry)

Fixes metrics scraping (403 Forbidden / up == 0) when the operator is installed outside openshift-lightspeed (e.g. AppSRE's lightspeed-operator namespace).

Test plan

  • Unit test: generator produces correct ClusterRoleBinding structure with dynamic namespace
  • Unit test: reconciler creates CRB with correct namespace when missing
  • Unit test: reconciler corrects CRB subject namespace when wrong
  • All existing tests pass (make test — 11 suites, 0 failures)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added automatic management of the metrics reader access binding.
    • Creates the required ClusterRoleBinding when missing and updates it when subject configuration drifts.
    • Automatically skips this management in local development mode.
  • Bug Fixes

    • Fixed the metrics reader subject namespace to system.
    • Improved MCP server TLS trust when introspection is enabled, and now triggers redeploys based on MCP CA content changes rather than config versions.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

The change updates the OpenShift MCP service URL and CA configuration, adds metrics reader ClusterRoleBinding generation and reconciliation, changes the Prometheus binding namespace, and adds related tests and RBAC error constants.

Changes

Appserver resource configuration and reconciliation

Layer / File(s) Summary
MCP service URL and CA wiring
internal/controller/appserver/assets.go
Uses a namespace-aware MCP service URL and adds the MCP service CA certificate path when introspection is enabled.
Metrics reader binding definition and generation
internal/controller/utils/constants.go, internal/controller/appserver/assets.go, internal/controller/appserver/assets_test.go, config/prometheus/clusterrole_binding.yaml
Defines metrics reader RBAC names, generates and validates the ClusterRoleBinding, and changes the Prometheus subject namespace to system.
Metrics reader binding reconciliation
internal/controller/utils/errors.go, internal/controller/appserver/reconciler.go, internal/controller/appserver/reconciler_test.go
Creates missing bindings and updates differing subjects, including correction of service-account namespace drift.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ReconcileAppServerResources
  participant reconcileMetricsReaderClusterRoleBinding
  participant KubernetesAPI
  ReconcileAppServerResources->>reconcileMetricsReaderClusterRoleBinding: reconcile metrics reader ClusterRoleBinding
  reconcileMetricsReaderClusterRoleBinding->>KubernetesAPI: get ClusterRoleBinding
  KubernetesAPI-->>reconcileMetricsReaderClusterRoleBinding: existing or not found
  reconcileMetricsReaderClusterRoleBinding->>KubernetesAPI: create or update desired subjects
  KubernetesAPI-->>reconcileMetricsReaderClusterRoleBinding: reconciliation result
Loading

Suggested reviewers: raptorsun, blublinsky

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly states the main change: dynamically reconciling the metrics-reader ClusterRoleBinding namespace.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@openshift-ci
openshift-ci Bot requested review from blublinsky and raptorsun July 21, 2026 13:35
@openshift-ci

openshift-ci Bot commented Jul 21, 2026

Copy link
Copy Markdown

[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 joshuawilson 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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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 `@internal/controller/appserver/assets.go`:
- Around line 998-1028: Update generateMetricsReaderClusterRoleBinding to
initialize its ObjectMeta.Labels with utils.DefaultLabels() instead of hardcoded
label values, preserving the existing resource name and all other
ClusterRoleBinding fields.

In `@internal/controller/appserver/reconciler.go`:
- Around line 444-460: Update the subject reconciliation logic around the
MetricsReaderServiceAccountName check to compare found.Subjects with
desired.Subjects using the repository’s standard semantic equality helper. When
they differ, replace found.Subjects with desired.Subjects and mark needsUpdate;
remove the separate subjectFound and namespace-only handling so the controller
consistently enforces the exact desired subject list.
- Around line 420-474: Add a kubebuilder RBAC marker in the reconciler’s
controller RBAC declarations granting get, create, and update permissions for
clusterrolebindings, covering the operations performed by
reconcileMetricsReaderClusterRoleBinding. Use the existing RBAC marker style and
preserve the current reconciliation logic.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 046f709e-8431-4d4e-9546-fc6937efe838

📥 Commits

Reviewing files that changed from the base of the PR and between 65d1f01 and 1c4373d.

📒 Files selected for processing (7)
  • config/prometheus/clusterrole_binding.yaml
  • internal/controller/appserver/assets.go
  • internal/controller/appserver/assets_test.go
  • internal/controller/appserver/reconciler.go
  • internal/controller/appserver/reconciler_test.go
  • internal/controller/utils/constants.go
  • internal/controller/utils/errors.go

Comment on lines +998 to +1028
func generateMetricsReaderClusterRoleBinding(r reconciler.Reconciler, cr *olsv1alpha1.OLSConfig) (*rbacv1.ClusterRoleBinding, error) {
rb := rbacv1.ClusterRoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: utils.MetricsReaderClusterRoleBindingName,
Labels: map[string]string{
"app.kubernetes.io/name": "clusterrolebinding",
"app.kubernetes.io/component": "metrics",
"app.kubernetes.io/part-of": "lightspeed-operator",
},
},
Subjects: []rbacv1.Subject{
{
Kind: "ServiceAccount",
Name: utils.MetricsReaderServiceAccountName,
Namespace: r.GetNamespace(),
},
},
RoleRef: rbacv1.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "ClusterRole",
Name: utils.MetricsReaderClusterRoleName,
},
}

if err := controllerutil.SetControllerReference(cr, &rb, r.GetScheme()); err != nil {
return nil, err
}

return &rb, nil
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use utils.DefaultLabels() for consistent labeling.

The labels in this ClusterRoleBinding are hardcoded. As per coding guidelines, use utils.DefaultLabels() for consistent labeling in asset generation functions.

🤖 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 `@internal/controller/appserver/assets.go` around lines 998 - 1028, Update
generateMetricsReaderClusterRoleBinding to initialize its ObjectMeta.Labels with
utils.DefaultLabels() instead of hardcoded label values, preserving the existing
resource name and all other ClusterRoleBinding fields.

Source: Coding guidelines

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

No DefaultLabels() function exists in this codebase. The closest analog (generateSARClusterRoleBinding) has no labels at all. The labels here match the kustomize source for consistency with the OLM-created resource. No change needed.

Comment thread internal/controller/appserver/reconciler.go
Comment thread internal/controller/appserver/reconciler.go
@openshift-ci openshift-ci Bot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jul 26, 2026
@thoraxe
thoraxe force-pushed the fix/OLS-3546-metrics-crb-namespace branch from a1df16f to 0d5def0 Compare July 27, 2026 13:16
@openshift-ci openshift-ci Bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jul 27, 2026
- Use utils.GenerateAppServerSelectorLabels() instead of hardcoded labels
  in generateMetricsReaderClusterRoleBinding (consistent labeling per
  coding guidelines)
- Add kubebuilder:rbac marker for clusterrolebindings get/create/update
  at the reconcileMetricsReaderClusterRoleBinding function
- Extend CRB generation test to assert on Labels field

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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)
internal/controller/appserver/reconciler_test.go (1)

455-484: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover a non-default operator namespace.

These assertions only exercise utils.OLSNamespaceDefault; a hardcoded namespace regression would pass. Reconcile with a shared TestReconciler configured for a custom namespace and assert the generated subject uses it.

As per coding guidelines, use shared controller test utilities and fixtures where appropriate, including TestReconciler and NewTestReconciler.

🤖 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 `@internal/controller/appserver/reconciler_test.go` around lines 455 - 484,
Update the metrics reader ClusterRoleBinding tests to use a shared
TestReconciler configured with a non-default operator namespace via
NewTestReconciler, rather than relying on utils.OLSNamespaceDefault. Reconcile
using that fixture and assert both creation and namespace correction in the
tests around the metrics reader ClusterRoleBinding cases, verifying the subject
namespace matches the configured custom namespace.

Source: Coding guidelines

🤖 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 `@internal/controller/appserver/assets.go`:
- Around line 1027-1028: In the owner-reference setup within the metrics reader
reconciliation flow, add the shared ErrSetMetricsReaderCRBOwnerReference
constant to internal/controller/utils/errors.go, then wrap the error returned by
controllerutil.SetControllerReference using the project’s fmt.Errorf("%s: %w",
ErrConstant, err) convention before returning it.

---

Nitpick comments:
In `@internal/controller/appserver/reconciler_test.go`:
- Around line 455-484: Update the metrics reader ClusterRoleBinding tests to use
a shared TestReconciler configured with a non-default operator namespace via
NewTestReconciler, rather than relying on utils.OLSNamespaceDefault. Reconcile
using that fixture and assert both creation and namespace correction in the
tests around the metrics reader ClusterRoleBinding cases, verifying the subject
namespace matches the configured custom namespace.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 386cf600-b24a-40f0-84f0-2e7e743b4f46

📥 Commits

Reviewing files that changed from the base of the PR and between 1c4373d and 675a061.

📒 Files selected for processing (7)
  • config/prometheus/clusterrole_binding.yaml
  • internal/controller/appserver/assets.go
  • internal/controller/appserver/assets_test.go
  • internal/controller/appserver/reconciler.go
  • internal/controller/appserver/reconciler_test.go
  • internal/controller/utils/constants.go
  • internal/controller/utils/errors.go

Comment on lines +1027 to +1028
if err := controllerutil.SetControllerReference(cr, &rb, r.GetScheme()); err != nil {
return nil, err

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Wrap the owner-reference error with a shared constant.

Add ErrSetMetricsReaderCRBOwnerReference in internal/controller/utils/errors.go and wrap this failure before returning it.

Proposed fix
- if err := controllerutil.SetControllerReference(cr, &rb, r.GetScheme()); err != nil {
-     return nil, err
+ if err := controllerutil.SetControllerReference(cr, &rb, r.GetScheme()); err != nil {
+     return nil, fmt.Errorf("%s: %w", utils.ErrSetMetricsReaderCRBOwnerReference, err)
  }

As per coding guidelines, “Wrap errors using fmt.Errorf("%s: %w", ErrConstant, err)”; as per path instructions, errors must use shared constants from internal/controller/utils/errors.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 `@internal/controller/appserver/assets.go` around lines 1027 - 1028, In the
owner-reference setup within the metrics reader reconciliation flow, add the
shared ErrSetMetricsReaderCRBOwnerReference constant to
internal/controller/utils/errors.go, then wrap the error returned by
controllerutil.SetControllerReference using the project’s fmt.Errorf("%s: %w",
ErrConstant, err) convention before returning it.

Sources: Coding guidelines, Path instructions

@openshift-ci

openshift-ci Bot commented Jul 30, 2026

Copy link
Copy Markdown

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

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