Skip to content

OCPEDGE-2705: Add TNF Pacemaker metrics controller#1634

Open
fonta-rh wants to merge 3 commits into
openshift:mainfrom
fonta-rh:ocpedge-2705-metrics-controller
Open

OCPEDGE-2705: Add TNF Pacemaker metrics controller#1634
fonta-rh wants to merge 3 commits into
openshift:mainfrom
fonta-rh:ocpedge-2705-metrics-controller

Conversation

@fonta-rh

@fonta-rh fonta-rh commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds a metrics controller that projects PacemakerCluster CR conditions into Prometheus gauges (20 metric families, ~53 series on a 2-node cluster)
  • Shares the existing pacemakerInformer with HealthCheck — zero additional API server load
  • Uses table-driven sync logic with GaugeVec.Reset() to prevent stale data from removed nodes

Details

New package pkg/tnf/pkg/metriccontroller/ with three files:

File Purpose
metrics.go 20 metric definitions (3 cluster, 9 node, 8 resource), mapping tables, conditionToFloat64 helper
controller.go Controller struct, constructor with metrics.KubeRegistry injection, sync logic
controller_test.go 11 test cases covering healthy cluster, node offline, resource stopped, missing CR, nil nodes, missing condition, node removal, multi-resource, label correctness, idempotency, and edge cases

Wiring in pkg/tnf/operator/starter.go — controller created after HealthCheck, sharing pacemakerInformer.

Key design decisions

  • Registry injection for test isolation (matches EtcdCertSignerController pattern)
  • Missing CR → gauges reset to 0 — makes "unhealthy" the safe default for alerting rules (== 0 vs absent())
  • No operator condition — failure modes overlap with HealthCheck; self-health metric deferred to OCPEDGE-2707
  • StabilityLevel: metrics.ALPHA — explicit on all metrics

Metrics exposed

Level Count Type Labels
Cluster 3 Gauge none
Node 9 GaugeVec node
Resource 8 GaugeVec node, resource

Test plan

  • go build ./... — all binaries compile
  • go test ./pkg/tnf/pkg/metriccontroller/ -v -count=5 — 55/55 pass, no registration pollution
  • go test ./pkg/tnf/... -count=1 — 454 existing TNF tests pass (no regressions)
  • make build — clean
  • make test-unit — all tests pass with -race
  • E2E: Deployed on fencing-IPI cluster, 53 series confirmed on :8443/metrics and in Prometheus

E2E validation (11 scenarios on live cluster)

17/20 metrics dynamically validated via reversible pcs operations (maintenance mode, unmanage, disable, standby, fence disable, cluster stop, force-stop, double-ban, virsh destroy, kubelet kill). 3 remaining are not dynamically testable: node_ready (too-transient, 1-3s vs 60s poll), node_clean (API blind spot — quorum loss blocks CR writes), cluster_node_count_as_expected (structurally unreachable — configured membership fixed at 2). All code paths covered by unit tests.

Related

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added Prometheus metrics for PacemakerCluster, including cluster condition gauges, per-node online status, and per-resource state.
    • Metrics are maintained by a dedicated controller and reset appropriately when cluster or node details are unavailable.
  • Tests

    • Added unit tests validating metric outputs across healthy, unhealthy/offline, stopped/started, missing data, label correctness, node removal, and Sync idempotency.
    • Updated health check tests to use shared fake informer utilities.

Implement a metrics controller that projects PacemakerCluster CR
conditions into Prometheus gauges for the TNF monitoring pipeline.

The controller shares the existing pacemakerInformer with HealthCheck,
registers 20 metric families (~53 series on a 2-node cluster), and
uses table-driven sync logic with GaugeVec.Reset() to prevent stale
data from removed nodes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jun 18, 2026
@openshift-ci-robot

openshift-ci-robot commented Jun 18, 2026

Copy link
Copy Markdown

@fonta-rh: This pull request references OCPEDGE-2705 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:

Summary

  • Adds a metrics controller that projects PacemakerCluster CR conditions into Prometheus gauges (20 metric families, ~53 series on a 2-node cluster)
  • Shares the existing pacemakerInformer with HealthCheck — zero additional API server load
  • Uses table-driven sync logic with GaugeVec.Reset() to prevent stale data from removed nodes

Details

New package pkg/tnf/pkg/metriccontroller/ with three files:

File Purpose
metrics.go 20 metric definitions (3 cluster, 9 node, 8 resource), mapping tables, conditionToFloat64 helper
controller.go Controller struct, constructor with metrics.KubeRegistry injection, sync logic
controller_test.go 11 test cases covering healthy cluster, node offline, resource stopped, missing CR, nil nodes, missing condition, node removal, multi-resource, label correctness, idempotency, and edge cases

Wiring in pkg/tnf/operator/starter.go — controller created after HealthCheck, sharing pacemakerInformer.

Key design decisions

  • Registry injection for test isolation (matches EtcdCertSignerController pattern)
  • Missing CR → gauges reset to 0 — makes "unhealthy" the safe default for alerting rules (== 0 vs absent())
  • No operator condition — failure modes overlap with HealthCheck; self-health metric deferred to OCPEDGE-2707
  • StabilityLevel: metrics.ALPHA — explicit on all metrics

Metrics exposed

Level Count Type Labels
Cluster 3 Gauge none
Node 9 GaugeVec node
Resource 8 GaugeVec node, resource

Test plan

  • go build ./... — all binaries compile
  • go test ./pkg/tnf/pkg/metriccontroller/ -v -count=5 — 55/55 pass, no registration pollution
  • go test ./pkg/tnf/... -count=1 — 454 existing TNF tests pass (no regressions)
  • make build — clean
  • make test-unit — all tests pass with -race
  • E2E: Deploy on TNF cluster, verify metrics appear on :8443/metrics

Related

🤖 Generated with Claude Code

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

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: c9580664-f044-454e-85a2-58098d34de97

📥 Commits

Reviewing files that changed from the base of the PR and between 17f75ce and b75d472.

📒 Files selected for processing (1)
  • pkg/tnf/pkg/metriccontroller/metrics.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/tnf/pkg/metriccontroller/metrics.go

Walkthrough

A Pacemaker metrics controller is added to collect cluster, node, and resource Prometheus metrics from PacemakerCluster status. Startup wiring now launches it alongside the existing controller, and tests add shared informer support plus coverage for metric updates and resets.

Changes

Pacemaker Metrics Reporting

Layer / File(s) Summary
Metric definitions
pkg/tnf/pkg/metriccontroller/metrics.go
Declares cluster, node, and resource gauges; groups them for registration; maps Pacemaker condition types to metric instances; and adds conditionToFloat64.
Controller sync
pkg/tnf/pkg/metriccontroller/controller.go
Adds NewPacemakerMetricsController, registers metrics, and syncs from the informer store to reset or update gauges from PacemakerCluster status.
Operator startup wiring
pkg/tnf/operator/starter.go
Imports the metrics controller and starts it during Pacemaker controller initialization with the existing informer, recorder, and legacy registry.
Fake informer reuse
pkg/tnf/internal/testutil/fakeinformer.go, pkg/tnf/pkg/pacemaker/healthcheck_test.go
Adds a shared fake informer helper and switches healthcheck tests to use it.
Metrics controller tests
pkg/tnf/pkg/metriccontroller/controller_test.go
Adds builders, sync setup, and unit tests for healthy, missing, partial, multi-resource, label, and idempotency cases.

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

🚥 Pre-merge checks | ✅ 14 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (14 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding the TNF Pacemaker metrics controller.
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 PASS: The changed tests use fixed literal names (e.g. healthy_status, fencing_degraded_node_unhealthy); no dynamic It/Describe/Context titles were found.
Test Structure And Quality ✅ Passed The new tests are plain unit tests using fake informers/in-memory recorders; no Ginkgo, cluster waits, or cleanup-heavy resources are present.
Microshift Test Compatibility ✅ Passed The PR adds only Go unit tests and controller code; no new Ginkgo e2e tests or MicroShift-unsupported APIs/features were introduced.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No new Ginkgo e2e tests were added; the new metriccontroller tests are plain Go unit tests, so the SNO multi-node check is not applicable.
Topology-Aware Scheduling Compatibility ✅ Passed The PR only adds a metrics controller and test scaffolding; no pod specs, replicas, affinities, nodeSelectors, PDBs, or topology-spread constraints were introduced or modified.
Ote Binary Stdout Contract ✅ Passed No added main/init/TestMain/suite stdout writes; changed files only add metrics/controller logic and tests, and klog defaults to stderr.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed No new Ginkgo/e2e tests were added; the new tests are stdlib unit tests with no external connectivity or IPv4-only assumptions.
No-Weak-Crypto ✅ Passed New metriccontroller/starter code adds no weak crypto primitives or custom crypto; searches found no MD5/SHA1/DES/RC4/ECB use or new secret/token comparisons.
Container-Privileges ✅ Passed PR changes only Go metrics/controller code and test helpers; no touched manifests or pod specs contain privileged, hostPID, hostNetwork, hostIPC, SYS_ADMIN, or allowPrivilegeEscalation=true.
No-Sensitive-Data-In-Logs ✅ Passed The added metric-controller logs are generic status/count messages only; no new logging prints secrets, tokens, PII, or hostnames.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions
The command is terminated due to an error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions


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

@openshift-ci openshift-ci Bot requested review from eggfoobar and mshitrit June 18, 2026 14:31
@fonta-rh fonta-rh marked this pull request as draft June 18, 2026 14:31
@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 Jun 18, 2026

@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)
pkg/tnf/pkg/metriccontroller/controller_test.go (1)

21-68: 💤 Low value

Consider extracting fakeInformer to a shared test utility.

The comment on line 22 notes this is copied from pacemaker/healthcheck_test.go. To reduce duplication, consider extracting this to a shared test helper package (e.g., pkg/tnf/pkg/testutil) so both test files can reuse the same implementation.

🤖 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 `@pkg/tnf/pkg/metriccontroller/controller_test.go` around lines 21 - 68, The
fakeInformer struct and createFakeInformer function are duplicated between
controller_test.go and pacemaker/healthcheck_test.go as noted in the comment.
Extract both the createFakeInformer function and the fakeInformer type
definition (along with all its method implementations) to a shared test utility
package such as pkg/tnf/pkg/testutil. Update both test files to import and use
the shared implementation instead of maintaining duplicate code.
🤖 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 `@pkg/tnf/operator/starter.go`:
- Around line 320-328: The type assertion on legacyregistry.DefaultGatherer to
metrics.KubeRegistry is unsafe and will cause a panic if the assertion fails at
runtime. Replace the bare type assertion with the comma-ok idiom by capturing
both the converted value and a boolean success indicator, then check the boolean
before proceeding. If the assertion fails, handle the error appropriately (e.g.,
log an error and return or exit) before creating the metricsController with
NewPacemakerMetricsController.

---

Nitpick comments:
In `@pkg/tnf/pkg/metriccontroller/controller_test.go`:
- Around line 21-68: The fakeInformer struct and createFakeInformer function are
duplicated between controller_test.go and pacemaker/healthcheck_test.go as noted
in the comment. Extract both the createFakeInformer function and the
fakeInformer type definition (along with all its method implementations) to a
shared test utility package such as pkg/tnf/pkg/testutil. Update both test files
to import and use the shared implementation instead of maintaining duplicate
code.
🪄 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: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 6cfb780f-0e07-4d69-909e-d7f8d653442a

📥 Commits

Reviewing files that changed from the base of the PR and between f38807a and 383e514.

📒 Files selected for processing (4)
  • pkg/tnf/operator/starter.go
  • pkg/tnf/pkg/metriccontroller/controller.go
  • pkg/tnf/pkg/metriccontroller/controller_test.go
  • pkg/tnf/pkg/metriccontroller/metrics.go

Comment thread pkg/tnf/operator/starter.go
Both metriccontroller and pacemaker tests had identical 47-line
fakeInformer implementations. Move to pkg/tnf/internal/testutil/
so future interface changes only need one update.

Co-Authored-By: Claude Opus 4.6 <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: 2

🤖 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 `@pkg/tnf/internal/testutil/fakeinformer.go`:
- Around line 19-21: The `store.Add(obj)` call in the function containing the if
statement is suppressing the error with the blank identifier (_), which can hide
test setup failures. Modify the function signature to return an error type, and
instead of discarding the error, return it if `store.Add(obj)` fails. Then
update all five call sites of this function across controller_test.go and
healthcheck_test.go to handle the returned error appropriately by checking for
nil and failing the test if an error is returned.

In `@pkg/tnf/pkg/pacemaker/healthcheck_test.go`:
- Around line 53-59: The test setup in createTestHealthCheckWithMockStatus has
an implicit coupling between how the fake informer indexes objects (by
PacemakerCluster.Name) and how getPacemakerStatus fetches them (by
PacemakerClusterResourceName constant). Make this contract explicit by setting
mockStatus.Name to match the expected lookup key before passing it to
testutil.CreateFakeInformer(mockStatus), ensuring the mock object can be found
when getPacemakerStatus attempts to retrieve it by its fixed resource name.
🪄 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: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 9c1e7295-27cc-4c14-9264-76fe10a05aa9

📥 Commits

Reviewing files that changed from the base of the PR and between 383e514 and 17f75ce.

📒 Files selected for processing (3)
  • pkg/tnf/internal/testutil/fakeinformer.go
  • pkg/tnf/pkg/metriccontroller/controller_test.go
  • pkg/tnf/pkg/pacemaker/healthcheck_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/tnf/pkg/metriccontroller/controller_test.go

Comment thread pkg/tnf/internal/testutil/fakeinformer.go
Comment thread pkg/tnf/pkg/pacemaker/healthcheck_test.go
@fonta-rh fonta-rh marked this pull request as ready for review June 24, 2026 07:51
@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 Jun 24, 2026
@openshift-ci openshift-ci Bot requested review from clobrano and jaypoulz June 24, 2026 07:52
{pacmkrv1.ResourceSchedulableConditionType, resourceSchedulableGauge},
}

func conditionToFloat64(cond *metav1.Condition) float64 {

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.

One thing to note is that this choice eliminates the distinction between status unknown (nil) and status unhealthy (0).

That said, I'm pretty sure this choice was made at the API level as well. The only time I'm not sure this should apply is during initial setup, before the pacemakercluster CR is populated.

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.

The CR is always created with conditions populated — StatusCollector writes Status: *status in the initial create (statuscollector.go:825), then immediately PUTs the status subresource. There's no window where the CR exists without conditions.

Before the CR exists, the informer store is empty, so sync() hits the "not found" path and resets all gauges to 0. That's the intended behavior — during initial setup, nothing is healthy yet, and 0 is the safe default for alerting (== 0 fires without needing absent()).

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.

Excellent. Glad we've thought this through.

klog.V(4).Infof("syncing Pacemaker metrics")

item, exists, err := c.pacemakerInformer.GetStore().GetByKey(pacemaker.PacemakerClusterResourceName)
if err != nil {

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.

should we log this error?

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.

The factory controller framework (library-go) already logs returned errors and retries with exponential backoff — adding a log here would duplicate the message on each retry attempt.

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.

Awesome - good that the error is logged. :)

metricsController := metriccontroller.NewPacemakerMetricsController(
pacemakerInformer,
controllerContext.EventRecorder,
legacyregistry.DefaultGatherer.(metrics.KubeRegistry),

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.

Is default gatherer guaranteed to be a KubeRegistry? if not, it might be worth check if it is first, so that we can catch the error and log it.

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.

This matches the existing pattern at pkg/operator/starter.go:440 (non-TNF starter). DefaultGatherer is initialized by legacyregistry as a KubeRegistry — it can't be a different type at runtime.

Happy to add a guard, but this is the only file we touch outside of our owned scope (pkg/tnf/), so it's the one I want to be most consistent with the existing codebase in.

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.

Agreed. I'd follow the existing pattern and minimize the diff, like you said.

Comment thread pkg/tnf/pkg/metriccontroller/metrics.go Outdated

var (
clusterHealthyGauge = metrics.NewGauge(&metrics.GaugeOpts{
Name: "tnf_cluster_healthy",

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.

This is chai-bot, but it claims:
Using Namespace: "tnf" + Subsystem: "cluster" in GaugeOpts is the k8s convention and would produce the same wire name while making the code more structured

I'm not one way or another but I feel like this would be low effort for slightly cleaner structure.

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.

Didn't know about this convention — good point. I was going with the existing CEO pattern from their metric (signerExpirationGauge). All the fields in GaugeOpts are concatenated, so the final wire name is still tnf_cluster_healthy, etc. — no breaking change.

Adopted it: Namespace: "tnf" with Subsystem per tier (cluster, node, resource).

# TYPE tnf_resource_started gauge
tnf_resource_started{node="master-0",resource="Etcd"} 0
tnf_resource_started{node="master-0",resource="Kubelet"} 1
tnf_resource_started{node="master-1",resource="Etcd"} 1

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.

etcd cannot be active while kubelet is dead :) probably not relevant but something I noticed

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.

Yeah, not a realistic combination — but the test is just exercising the per-resource mapping logic, not simulating a real failure. The fixture sets one resource unhealthy per node to verify conditions don't bleed across resources.

@jaypoulz jaypoulz left a comment

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.

Overall this is a great extension to the pacemaker healthcheck family of controllers. :)

As a standalone patch that gathers up these stats, I think this is quite reasonable. My only concern is - what happens if a node was populating information and then suddenly stops. PacemakerCluster would drop it entirely. Maybe an improvement here would be to initiate the node list from the k8s node list, and then populate what's available from the CR. This way my lifecycle manager work plays nicely as it adds and removes nodes.

registry := setupAndSync(t, buildCluster(withNodes("node-alpha", "node-beta")))

require.NoError(t, testutil.GatherAndCompare(registry, strings.NewReader(`
# HELP tnf_node_online [ALPHA] Whether a TNF node is online (1=online, 0=offline)

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.

I'm not crazy about the string fixture approach. Feels like there's maybe a more programmatic way of synthesizing these, or we throw them in a fixtures file to make this more readable.

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.

These are the standard k8s testutil.GatherAndCompare assertions — they require Prometheus text exposition format, so there's no programmatic builder to use here. Each string is only 3-6 lines and is tightly coupled to the buildCluster() options in the same test, so I think keeping them inline makes each test easier to read as a self-contained unit. Moving them to fixture files would separate the "what we set up" from the "what we expect" without reducing the overall line count.

Review feedback: structure metric definitions with Namespace: "tnf"
and Subsystem per tier (cluster, node, resource). Wire names unchanged.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@openshift-ci

openshift-ci Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

@fonta-rh: 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.

@jaypoulz jaypoulz left a comment

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.

/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label Jul 2, 2026
@openshift-ci

openshift-ci Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: jaypoulz

The full list of commands accepted by this bot can be found here.

The pull request process is described 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 openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jul 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lgtm Indicates that a PR is ready to be merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants