Skip to content

OCPCLOUD-3384, OCPCLOUD-3365: Implement admission action Warn and ensure validations not active when not configured#492

Merged
openshift-merge-bot[bot] merged 9 commits intoopenshift:mainfrom
openshift-cloud-team:compatibility-admit-warn
Mar 28, 2026
Merged

OCPCLOUD-3384, OCPCLOUD-3365: Implement admission action Warn and ensure validations not active when not configured#492
openshift-merge-bot[bot] merged 9 commits intoopenshift:mainfrom
openshift-cloud-team:compatibility-admit-warn

Conversation

@JoelSpeed
Copy link
Copy Markdown
Contributor

@JoelSpeed JoelSpeed commented Mar 9, 2026

This ensures that users configuring admission to warn do not have pruning or rejected writes for object admission

Also ensures that VWC/MWCs are removed when object admission is not configured

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 9, 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: 4e16a121-c2f8-4292-8bf7-c22ddf85aba3

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

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Refactors validators to accept CompatibilityRequirement objects, adds owner-reference checks and enablement guards for webhooks, implements action-driven Warn/Deny behavior for validation and pruning, expands warning-mode tests, and adds CRD/test helpers plus a REST WarningHandler utility.

Changes

Cohort / File(s) Summary
Signature & call-site refactors
pkg/controllers/crdcompatibility/objectpruning/webhook.go, pkg/controllers/crdcompatibility/objectvalidation/webhook.go, pkg/controllers/crdcompatibility/objectpruning/validator_unit_test.go, pkg/controllers/crdcompatibility/objectvalidation/validator_unit_test.go
Changed getStructuralSchema / getValidationStrategy to accept a *CompatibilityRequirement and version; removed internal client fetch/context usage and updated all callers/tests to pass pre-fetched requirement objects.
Webhook behavior & enablement checks
pkg/controllers/crdcompatibility/objectpruning/webhook.go, pkg/controllers/crdcompatibility/objectvalidation/webhook.go, pkg/controllers/crdcompatibility/reconcile.go
Added isObjectValidationWebhookEnabled and labelSelectorIsEmpty; handlers now early-return when validation is disabled or in Warn action; validation/pruning honor Spec.ObjectSchemaValidation.Action (Warn/Deny) and produce warnings instead of always denying.
Ownership enforcement for webhook configs
pkg/controllers/crdcompatibility/reconcile.go, pkg/controllers/crdcompatibility/reconcile_test.go
Reconciler now checks ownership (OwnerReferences / metav1.IsControlledBy) before applying or deleting Mutating/ValidatingWebhookConfigurations and errors if configs exist but are not controlled by the CompatibilityRequirement.
Test suite CRD helpers & timing utilities
pkg/controllers/crdcompatibility/objectpruning/suite_test.go, pkg/controllers/crdcompatibility/objectvalidation/suite_test.go
Added createSuiteCRDs, createCRD, timeSince, and package-level closure accessors (permissiveSuiteCRD, emptySuiteCRD, suiteCompatibilityCRD) to build/install CRDs once for suites and return deep-copy accessors; tests use these helpers.
Object pruning tests
pkg/controllers/crdcompatibility/objectpruning/handle_test.go, pkg/controllers/crdcompatibility/objectpruning/suite_test.go
Reworked tests to use suite CRD helpers, construct input objects via DeepCopy, add eventual Get+IgnoreFields comparisons, add update-triggered prune checks and a WARN-mode path (ensure no pruning), and minor test-data/type adjustments.
Object validation tests & warning-mode suite
pkg/controllers/crdcompatibility/objectvalidation/handle_test.go, pkg/controllers/crdcompatibility/objectvalidation/suite_test.go
Large additions: createWarningCompatibilityRequirement, new "Warning Mode Validation" suite exercising object/status/scale warnings, wiring a test WarningHandler, adjustments to CRD/webhook setup to use suite CRDs, and metrics/webhook manager options enabled for tests.
WarningHandler test utility
pkg/test/warninghandler.go
New exported test.WarningHandler and NewTestWarningHandler() to capture REST warning headers into an in-memory buffer and expose Messages() for assertions.
Test builder update
pkg/test/crdbuilder.go
GenerateTestCompatibilityRequirement now populates Spec.ObjectSchemaValidation with Action: CRDAdmitActionDeny by default.
Validator logic, caching & error handling
pkg/controllers/crdcompatibility/objectvalidation/webhook.go, pkg/controllers/crdcompatibility/objectpruning/...
Moved schema/strategy cache keying to use provided CompatibilityRequirement identity/generation, refactored functions to accept requirement objects, added helpers for converting validation errors to warning strings, and set OwnerReferences on generated webhook configurations.
Test ergonomics & timeouts
pkg/controllers/crdcompatibility/reconcile_test.go, various tests
Refactored test setup to use deep-copied CRDs per-context, tightened async assertions with .WithContext(ctx) and consistent timeouts, and added a test verifying webhook lifecycle is tied to presence/absence of ObjectSchemaValidation.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 2 warnings)

Check name Status Explanation Resolution
Stable And Deterministic Test Names ❌ Error Test step descriptions in pkg/controllers/crdcompatibility/reconcile_test.go contain dynamic values (requirement.Name, testCRDClean.Name, obj.GetName()) via string concatenation and fmt.Sprintf, violating stable test naming requirements. Replace dynamic values in By() statements with static descriptive text and move object name assertions into test body logic instead of test descriptions.
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Test Structure And Quality ⚠️ Warning New Ginkgo tests bundle multiple behaviors into single entries, violating single-responsibility, and lack descriptive failure messages on assertions. Refactor scenarios into separate It blocks, add contextual messages to Expect calls, and specify explicit timeouts on all Eventually/Consistently calls.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main changes: implementing Warn admission action and ensuring validations are inactive when not configured, directly aligned with the substantial refactoring and feature additions throughout the codebase.
✨ 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-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-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Mar 9, 2026
@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 Mar 9, 2026
@openshift-ci-robot
Copy link
Copy Markdown

openshift-ci-robot commented Mar 9, 2026

@JoelSpeed: This pull request references OCPCLOUD-3384 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 task to target the "4.22.0" version, but no target version was set.

This pull request references OCPCLOUD-3365 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 task to target the "4.22.0" version, but no target version was set.

Details

In response to this:

Currently stacked on #464

This ensures that users configuring admission to warn do not have pruning or rejected writes for object admission

Also ensures that VWC/MWCs are removed when object admission is not configured

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Mar 9, 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

@JoelSpeed JoelSpeed force-pushed the compatibility-admit-warn branch from 18f2100 to 4478e45 Compare March 13, 2026 11:20
@JoelSpeed JoelSpeed marked this pull request as ready for review March 13, 2026 11:21
@openshift-ci-robot
Copy link
Copy Markdown

openshift-ci-robot commented Mar 13, 2026

@JoelSpeed: This pull request references OCPCLOUD-3384 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 task to target the "4.22.0" version, but no target version was set.

This pull request references OCPCLOUD-3365 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 task to target the "4.22.0" version, but no target version was set.

Details

In response to this:

This ensures that users configuring admission to warn do not have pruning or rejected writes for object admission

Also ensures that VWC/MWCs are removed when object admission is not configured

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci openshift-ci Bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Mar 13, 2026
@openshift-ci openshift-ci Bot requested review from mdbooth and nrb March 13, 2026 11:23
@openshift-ci-robot
Copy link
Copy Markdown

openshift-ci-robot commented Mar 13, 2026

@JoelSpeed: This pull request references OCPCLOUD-3384 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 task to target the "4.22.0" version, but no target version was set.

This pull request references OCPCLOUD-3365 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 task to target the "4.22.0" version, but no target version was set.

Details

In response to this:

This ensures that users configuring admission to warn do not have pruning or rejected writes for object admission

Also ensures that VWC/MWCs are removed when object admission is not configured

Summary by CodeRabbit

  • New Features

  • Added warning mode for object schema validation, allowing validation enforcement via warnings instead of denial.

  • Bug Fixes

  • Webhook configurations now properly owned by CompatibilityRequirements to prevent accidental overwrites.

  • Enhanced object pruning and validation to respect webhook ownership constraints.

  • Chores

  • Updated Go toolchain to 1.25.0.

  • Upgraded Kubernetes API dependencies to v0.35.2.

  • Updated OpenShift API and etcd dependencies.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

Copy link
Copy Markdown

@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

Caution

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

⚠️ Outside diff range comments (1)
pkg/controllers/crdcompatibility/reconcile.go (1)

232-249: ⚠️ Potential issue | 🔴 Critical

Prevent deletion of non-owned ValidatingWebhookConfiguration objects.

At Line 247, deletion is unconditional once the object is found. Combined with Line 202-205 (disable path), this can remove a same-named webhook not controlled by this CompatibilityRequirement.

🔒 Proposed fix
 func (r *reconcileState) removeObjectValidationWebhook(ctx context.Context, obj *apiextensionsv1alpha1.CompatibilityRequirement) error {
 	webhookConfig := &admissionregistrationv1.ValidatingWebhookConfiguration{
 		ObjectMeta: metav1.ObjectMeta{
 			Name: obj.Name,
 		},
 	}
@@
 	if err := r.client.Get(ctx, types.NamespacedName{Name: webhookConfig.Name}, webhookConfig); err != nil {
 		if apierrors.IsNotFound(err) {
 			return nil
 		}

 		return fmt.Errorf("failed to get ValidatingWebhookConfiguration %s: %w", webhookConfig.Name, err)
 	}
+
+	// If we don't own the webhook config, we should not be deleting it.
+	if !metav1.IsControlledBy(webhookConfig, obj) {
+		return nil
+	}

 	if err := r.client.Delete(ctx, webhookConfig); err != nil {
 		return fmt.Errorf("failed to delete ValidatingWebhookConfiguration %s: %w", webhookConfig.Name, err)
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/controllers/crdcompatibility/reconcile.go` around lines 232 - 249, The
deletion is unconditional in removeObjectValidationWebhook which can remove a
same-named ValidatingWebhookConfiguration not owned by this
CompatibilityRequirement; before calling r.client.Delete check ownership (use
metav1.IsControlledBy or controllerutil.ContainsReference/IsOwned helper) to
ensure webhookConfig is owned/controlled by the obj (CompatibilityRequirement)
and only delete if true—if not owned, skip deletion and return nil (or a clear
no-op) to avoid deleting resources owned by others.
🧹 Nitpick comments (2)
go.mod (1)

19-29: Align require versions with replace pins to reduce dependency drift.

The replace directives pin Kubernetes modules to v0.35.2/v1.35.2, but several require entries lag behind:

  • Line 55: k8s.io/apiextensions-apiserver v0.34.1 → should be v0.35.2
  • Line 61: k8s.io/kubernetes v1.34.1 → should be v1.35.2
  • Line 351: k8s.io/controller-manager v0.32.1 (indirect) → should be v0.35.2
  • Line 354: k8s.io/kubelet v0.34.1 (indirect) → should be v0.35.2

This drift may cause future go mod tidy churn and makes the intended dependency versions less clear.

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

In `@go.mod` around lines 19 - 29, Update the go.mod require entries so they match
the pinned versions in the replace directives: change
k8s.io/apiextensions-apiserver to v0.35.2, k8s.io/kubernetes to v1.35.2, and
ensure indirect requires for k8s.io/controller-manager and k8s.io/kubelet are
v0.35.2; run go get <module>@<version> or edit the require block to the listed
versions and then run go mod tidy to verify there is no drift between require
and replace pins.
pkg/controllers/crdcompatibility/reconcile_test.go (1)

381-382: Use the typed NotFound matcher here.

Matching "not found" couples the test to error text and can pass for the wrong failure. test.BeK8SNotFound() is already used in the deletion specs above and keeps these assertions tied to the actual API status.

♻️ Suggested cleanup
-			Expect(kWithCtx(ctx).Get(noObjectSchemaValidatingWebhook)()).To(MatchError(ContainSubstring("not found")))
-			Expect(kWithCtx(ctx).Get(noObjectSchemaMutatingWebhook)()).To(MatchError(ContainSubstring("not found")))
+			Expect(kWithCtx(ctx).Get(noObjectSchemaValidatingWebhook)()).To(test.BeK8SNotFound())
+			Expect(kWithCtx(ctx).Get(noObjectSchemaMutatingWebhook)()).To(test.BeK8SNotFound())-			Eventually(kWithCtx(ctx).Get(noObjectSchemaValidatingWebhook)).WithContext(ctx).Should(MatchError(ContainSubstring("not found")))
-			Eventually(kWithCtx(ctx).Get(noObjectSchemaMutatingWebhook)).WithContext(ctx).Should(MatchError(ContainSubstring("not found")))
+			Eventually(kWithCtx(ctx).Get(noObjectSchemaValidatingWebhook)).WithContext(ctx).Should(test.BeK8SNotFound())
+			Eventually(kWithCtx(ctx).Get(noObjectSchemaMutatingWebhook)).WithContext(ctx).Should(test.BeK8SNotFound())

Also applies to: 399-400

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

In `@pkg/controllers/crdcompatibility/reconcile_test.go` around lines 381 - 382,
Replace the fragile string-based error assertions with the typed NotFound
matcher: change the two expectations using MatchError(ContainSubstring("not
found")) for kWithCtx(ctx).Get(noObjectSchemaValidatingWebhook)() and
kWithCtx(ctx).Get(noObjectSchemaMutatingWebhook)() to use test.BeK8SNotFound()
instead; also make the same replacement for the identical assertions noted
elsewhere in the file (the other occurrence around the deletion specs) so the
tests assert Kubernetes NotFound status rather than matching error text.
🤖 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/crdcompatibility/objectpruning/webhook.go`:
- Around line 119-125: The handler currently only returns early when
ObjectSchemaValidation.Action == CRDAdmitActionWarn, but when
ObjectSchemaValidation is nil the zero-value falls through and causes pruning;
update the early-exit logic in the webhook handler (around
compatibilityRequirement.Spec.ObjectSchemaValidation.Action and the call to
v.getStructuralSchema) to treat unset/cleared validation as disabled by
returning nil unless the action is explicitly
apiextensionsv1alpha1.CRDAdmitActionDeny — i.e., check if
Spec.ObjectSchemaValidation is nil or its Action != CRDAdmitActionDeny and
return nil to keep the admission inert during reconciliation windows.

In `@pkg/controllers/crdcompatibility/objectvalidation/handle_test.go`:
- Around line 853-860: The BeforeEach mutates the package-global cl and relies
on the implicit global scheme; instead create an explicit scheme and avoid
changing global state: build a fresh scheme (e.g. runtime.NewScheme()) and
explicitly register the needed API types (the same apiextensionsv1alpha1 types
registered in pkg/test/envtest.go) and pass that scheme into client.New via a
copied rest.Config (warningConfig), then create a local client variable (e.g.
testCl) from client.New rather than assigning to the package-global cl; if other
helpers require the global, save the oldCl before creating testCl and restore
oldCl in AfterEach (and ensure any client cleanup runs even on panic) so tests
remain isolated.

In `@pkg/controllers/crdcompatibility/reconcile.go`:
- Around line 314-317: The isObjectValidationWebhookEnabled function currently
treats a non-nil MatchConditions slice as enabled even if it's empty; change the
check from osl.MatchConditions != nil to len(osv.MatchConditions) > 0 so an
explicitly empty list is considered not configured, i.e., update the return
expression in isObjectValidationWebhookEnabled to use len(osv.MatchConditions) >
0 (keeping the existing checks for osv.Action and the namespace/object selector
helpers).

---

Outside diff comments:
In `@pkg/controllers/crdcompatibility/reconcile.go`:
- Around line 232-249: The deletion is unconditional in
removeObjectValidationWebhook which can remove a same-named
ValidatingWebhookConfiguration not owned by this CompatibilityRequirement;
before calling r.client.Delete check ownership (use metav1.IsControlledBy or
controllerutil.ContainsReference/IsOwned helper) to ensure webhookConfig is
owned/controlled by the obj (CompatibilityRequirement) and only delete if
true—if not owned, skip deletion and return nil (or a clear no-op) to avoid
deleting resources owned by others.

---

Nitpick comments:
In `@go.mod`:
- Around line 19-29: Update the go.mod require entries so they match the pinned
versions in the replace directives: change k8s.io/apiextensions-apiserver to
v0.35.2, k8s.io/kubernetes to v1.35.2, and ensure indirect requires for
k8s.io/controller-manager and k8s.io/kubelet are v0.35.2; run go get
<module>@<version> or edit the require block to the listed versions and then run
go mod tidy to verify there is no drift between require and replace pins.

In `@pkg/controllers/crdcompatibility/reconcile_test.go`:
- Around line 381-382: Replace the fragile string-based error assertions with
the typed NotFound matcher: change the two expectations using
MatchError(ContainSubstring("not found")) for
kWithCtx(ctx).Get(noObjectSchemaValidatingWebhook)() and
kWithCtx(ctx).Get(noObjectSchemaMutatingWebhook)() to use test.BeK8SNotFound()
instead; also make the same replacement for the identical assertions noted
elsewhere in the file (the other occurrence around the deletion specs) so the
tests assert Kubernetes NotFound status rather than matching error text.

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Pro

Run ID: 01a51f56-b065-4956-b2f5-83eb8e268ea7

📥 Commits

Reviewing files that changed from the base of the PR and between 98025f0 and 4478e45.

⛔ Files ignored due to path filters (285)
  • e2e/go.sum is excluded by !**/*.sum
  • go.sum is excluded by !**/*.sum
  • go.work is excluded by !**/*.work
  • manifests-gen/go.sum is excluded by !**/*.sum
  • vendor/github.com/gogo/protobuf/sortkeys/sortkeys.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/.ci-operator.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/AGENTS.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/Dockerfile.ocp is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/apiextensions/v1alpha1/types_compatibilityrequirement.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/apps/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/apps/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/authorization/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/authorization/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/build/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/build/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/cloudnetwork/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/cloudnetwork/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_config-operator_01_networks.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/config/v1/zz_generated.crd-manifests/0000_10_openshift-controller-manager_01_builds.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/config/v1alpha1/register.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/config/v1alpha1/types_pki.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/config/v1alpha1/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/config/v1alpha1/zz_generated.featuregated-crd-manifests.yaml is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/config/v1alpha1/zz_generated.swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/features.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/features/features.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/image/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/image/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/network/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/network/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/networkoperator/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/networkoperator/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/oauth/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/oauth/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/openapi/generated_openapi/zz_generated.openapi.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_50_ingress_00_ingresscontrollers.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/operator/v1/zz_generated.crd-manifests/0000_70_dns_00_dnses.crd.yaml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/project/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/project/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/quota/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/quota/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/route/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/route/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/samples/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/samples/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/security/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/security/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/template/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/template/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/user/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/api/user/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/robfig/cron/v3/.gitignore is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/robfig/cron/v3/.travis.yml is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/robfig/cron/v3/LICENSE is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/robfig/cron/v3/README.md is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/robfig/cron/v3/chain.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/robfig/cron/v3/constantdelay.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/robfig/cron/v3/cron.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/robfig/cron/v3/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/robfig/cron/v3/logger.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/robfig/cron/v3/option.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/robfig/cron/v3/parser.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/robfig/cron/v3/spec.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.etcd.io/etcd/api/v3/version/version.go is excluded by !**/vendor/**, !vendor/**
  • vendor/go.etcd.io/etcd/client/v3/retry_interceptor.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/admission/v1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/admission/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/admission/v1/generated.proto is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/admission/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/admission/v1/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/admission/v1/types_swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/admission/v1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/admission/v1beta1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/admission/v1beta1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/admission/v1beta1/generated.proto is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/admission/v1beta1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/admission/v1beta1/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/admission/v1beta1/types_swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/admission/v1beta1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/admissionregistration/v1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/admissionregistration/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/admissionregistration/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/admissionregistration/v1/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/admissionregistration/v1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/admissionregistration/v1alpha1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/admissionregistration/v1alpha1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/admissionregistration/v1alpha1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/admissionregistration/v1alpha1/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/admissionregistration/v1alpha1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/admissionregistration/v1beta1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/admissionregistration/v1beta1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/admissionregistration/v1beta1/generated.proto is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/admissionregistration/v1beta1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/admissionregistration/v1beta1/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/admissionregistration/v1beta1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/apidiscovery/v2/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/apidiscovery/v2/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/apidiscovery/v2/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/apidiscovery/v2/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/apidiscovery/v2beta1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/apidiscovery/v2beta1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/apidiscovery/v2beta1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/apidiscovery/v2beta1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/apiserverinternal/v1alpha1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/apiserverinternal/v1alpha1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/apiserverinternal/v1alpha1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/apiserverinternal/v1alpha1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/apps/v1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/apps/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/apps/v1/generated.proto is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/apps/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/apps/v1/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/apps/v1/types_swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/apps/v1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/apps/v1beta1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/apps/v1beta1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/apps/v1beta1/generated.proto is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/apps/v1beta1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/apps/v1beta1/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/apps/v1beta1/types_swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/apps/v1beta1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/apps/v1beta2/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/apps/v1beta2/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/apps/v1beta2/generated.proto is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/apps/v1beta2/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/apps/v1beta2/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/apps/v1beta2/types_swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/apps/v1beta2/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/authentication/v1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/authentication/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/authentication/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/authentication/v1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/authentication/v1alpha1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/authentication/v1alpha1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/authentication/v1alpha1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/authentication/v1alpha1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/authentication/v1beta1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/authentication/v1beta1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/authentication/v1beta1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/authentication/v1beta1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/authorization/v1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/authorization/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/authorization/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/authorization/v1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/authorization/v1beta1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/authorization/v1beta1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/authorization/v1beta1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/authorization/v1beta1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/autoscaling/v1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/autoscaling/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/autoscaling/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/autoscaling/v1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/autoscaling/v2/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/autoscaling/v2/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/autoscaling/v2/generated.proto is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/autoscaling/v2/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/autoscaling/v2/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/autoscaling/v2/types_swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/autoscaling/v2/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/autoscaling/v2beta1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/autoscaling/v2beta1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/autoscaling/v2beta1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/autoscaling/v2beta1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/autoscaling/v2beta2/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/autoscaling/v2beta2/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/autoscaling/v2beta2/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/autoscaling/v2beta2/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/batch/v1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/batch/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/batch/v1/generated.proto is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/batch/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/batch/v1/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/batch/v1/types_swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/batch/v1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/batch/v1beta1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/batch/v1beta1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/batch/v1beta1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/batch/v1beta1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/certificates/v1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/certificates/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/certificates/v1/generated.proto is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/certificates/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/certificates/v1/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/certificates/v1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/certificates/v1alpha1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/certificates/v1alpha1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/certificates/v1alpha1/generated.proto is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/certificates/v1alpha1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/certificates/v1alpha1/register.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/certificates/v1alpha1/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/certificates/v1alpha1/types_swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/certificates/v1alpha1/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/certificates/v1alpha1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/certificates/v1alpha1/zz_generated.prerelease-lifecycle.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/certificates/v1beta1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/certificates/v1beta1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/certificates/v1beta1/generated.proto is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/certificates/v1beta1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/certificates/v1beta1/register.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/certificates/v1beta1/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/certificates/v1beta1/types_swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/certificates/v1beta1/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/certificates/v1beta1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/certificates/v1beta1/zz_generated.prerelease-lifecycle.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/coordination/v1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/coordination/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/coordination/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/coordination/v1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/coordination/v1alpha2/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/coordination/v1alpha2/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/coordination/v1alpha2/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/coordination/v1alpha2/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/coordination/v1beta1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/coordination/v1beta1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/coordination/v1beta1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/coordination/v1beta1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/core/v1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/core/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/core/v1/generated.proto is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/core/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/core/v1/toleration.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/core/v1/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/core/v1/types_swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/core/v1/zz_generated.deepcopy.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/core/v1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/discovery/v1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/discovery/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/discovery/v1/generated.proto is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/discovery/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/discovery/v1/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/discovery/v1/types_swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/discovery/v1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/discovery/v1beta1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/discovery/v1beta1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/discovery/v1beta1/generated.proto is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/discovery/v1beta1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/discovery/v1beta1/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/discovery/v1beta1/types_swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/discovery/v1beta1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/events/v1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/events/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/events/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/events/v1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/events/v1beta1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/events/v1beta1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/events/v1beta1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/events/v1beta1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/extensions/v1beta1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/extensions/v1beta1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/extensions/v1beta1/generated.proto is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/extensions/v1beta1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/extensions/v1beta1/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/extensions/v1beta1/types_swagger_doc_generated.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/extensions/v1beta1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/extensions/v1beta1/zz_generated.validations.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/flowcontrol/v1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/flowcontrol/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/flowcontrol/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/flowcontrol/v1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/flowcontrol/v1beta1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/flowcontrol/v1beta1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/flowcontrol/v1beta1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/flowcontrol/v1beta1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/flowcontrol/v1beta2/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/flowcontrol/v1beta2/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/flowcontrol/v1beta2/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/flowcontrol/v1beta2/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/flowcontrol/v1beta3/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/flowcontrol/v1beta3/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/flowcontrol/v1beta3/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/flowcontrol/v1beta3/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/imagepolicy/v1alpha1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/imagepolicy/v1alpha1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/imagepolicy/v1alpha1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/imagepolicy/v1alpha1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/networking/v1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/networking/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/networking/v1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/networking/v1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/networking/v1beta1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/networking/v1beta1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/networking/v1beta1/generated.protomessage.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/networking/v1beta1/zz_generated.model_name.go is excluded by !**/vendor/**, !vendor/**, !**/zz_generated*
  • vendor/k8s.io/api/node/v1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/k8s.io/api/node/v1/generated.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
📒 Files selected for processing (15)
  • e2e/go.mod
  • go.mod
  • hack/tools/go.mod
  • manifests-gen/go.mod
  • pkg/controllers/crdcompatibility/objectpruning/handle_test.go
  • pkg/controllers/crdcompatibility/objectpruning/validator_unit_test.go
  • pkg/controllers/crdcompatibility/objectpruning/webhook.go
  • pkg/controllers/crdcompatibility/objectvalidation/handle_test.go
  • pkg/controllers/crdcompatibility/objectvalidation/suite_test.go
  • pkg/controllers/crdcompatibility/objectvalidation/validator_unit_test.go
  • pkg/controllers/crdcompatibility/objectvalidation/webhook.go
  • pkg/controllers/crdcompatibility/reconcile.go
  • pkg/controllers/crdcompatibility/reconcile_test.go
  • pkg/test/crdbuilder.go
  • pkg/test/warninghandler.go

Comment thread pkg/controllers/crdcompatibility/objectpruning/webhook.go Outdated
Comment thread pkg/controllers/crdcompatibility/objectvalidation/handle_test.go
Comment thread pkg/controllers/crdcompatibility/reconcile.go
@openshift-ci-robot
Copy link
Copy Markdown

openshift-ci-robot commented Mar 13, 2026

@JoelSpeed: This pull request references OCPCLOUD-3384 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 task to target the "4.22.0" version, but no target version was set.

This pull request references OCPCLOUD-3365 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 task to target the "4.22.0" version, but no target version was set.

Details

In response to this:

This ensures that users configuring admission to warn do not have pruning or rejected writes for object admission

Also ensures that VWC/MWCs are removed when object admission is not configured

Summary by CodeRabbit

  • New Features

  • Warning mode for object schema validation: validations can emit warnings instead of denying requests.

  • Bug Fixes

  • Webhook ownership and lifecycle tightened to avoid overwriting or deleting webhooks not owned by the requirement.

  • Pruning/validation behavior adjusted to respect warning mode and ownership checks.

  • Chores

  • Bumped Go toolchain to 1.25.0 and updated Kubernetes, OpenShift, and etcd dependencies.

  • CI/Docker builder images updated.

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.

Comment thread pkg/controllers/crdcompatibility/reconcile.go
if err := r.client.Get(ctx, types.NamespacedName{Name: webhookConfig.Name}, existingWebhookConfig); err != nil && !apierrors.IsNotFound(err) {
return fmt.Errorf("failed to get ValidatingWebhookConfiguration %s: %w", webhookConfig.Name, err)
} else if err == nil && !metav1.IsControlledBy(existingWebhookConfig, obj) {
return fmt.Errorf("%w: %s", errWebhookConfigNotControlledByCompatibilityRequirement, webhookConfig.Name)
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.

Terminal error?

Comment thread pkg/controllers/crdcompatibility/objectpruning/webhook.go Outdated
retrievedObj.SetName(inputObject.GetName())
retrievedObj.SetNamespace(inputObject.GetNamespace())

Eventually(kWithCtx(ctx).Get(retrievedObj)).WithContext(ctx).Should(Succeed())
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 thought we were doing timeouts too, now?

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.

I haven't swept through to make that update yet, this is fine when the tests pass, but messy when the tests fail, planning to do a sweep that's mechanical afterwards once I work out a good pattern

scenario.CompatibilityRequirement.Spec.ObjectSchemaValidation.Action = apiextensionsv1alpha1.CRDAdmitActionWarn
})).WithContext(ctx).Should(Succeed())

By("Updating the object again, should not be pruned")
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 feel like you need to wait here until the CR has a success condition with observedGeneration >= the return from your Update?

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.

I don't think there's a need to. The webhook loads the CR from the cache on every request and checks whether the action is set to warn or deny. We aren't reliant on the controller to make any changes to reflect that change

@openshift-merge-robot openshift-merge-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Mar 15, 2026
@JoelSpeed JoelSpeed force-pushed the compatibility-admit-warn branch from fa03d1b to c54005f Compare March 16, 2026 12:32
@openshift-merge-robot openshift-merge-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Mar 16, 2026
@openshift-ci-robot
Copy link
Copy Markdown

@JoelSpeed: This pull request references OCPCLOUD-3384 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 task to target the "4.22.0" version, but no target version was set.

This pull request references OCPCLOUD-3365 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 task to target the "4.22.0" version, but no target version was set.

Details

In response to this:

This ensures that users configuring admission to warn do not have pruning or rejected writes for object admission

Also ensures that VWC/MWCs are removed when object admission is not configured

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

Copy link
Copy Markdown

@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

🤖 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/crdcompatibility/objectvalidation/webhook.go`:
- Around line 162-189: In ValidateUpdate (webhook.go) add the same short-circuit
that ValidateCreate uses when object admission is no longer enabled: after
loading the CompatibilityRequirement and before calling
getValidationStrategy/ValidateUpdate, detect the removed/empty admit action
(compatibilityRequirement.Spec.ObjectSchemaValidation.Action == "" or equivalent
"admission disabled" condition) and return nil, nil (or return empty warnings,
nil) to ignore stale webhook calls instead of falling through to the default
branch that errors; update any references to
strategy.ValidateUpdate/WarningsOnUpdate to only run when admission is enabled.

In `@pkg/controllers/crdcompatibility/reconcile.go`:
- Around line 209-214: The check that returns an error when an existing
ValidatingWebhookConfiguration/MutatingWebhookConfiguration
(existingWebhookConfig) is not owned by the CompatibilityRequirement (obj)
should instead attempt a migration/adoption: after r.client.Get finds an
existing resource and metav1.IsControlledBy(existingWebhookConfig, obj) is
false, try to adopt it by setting the CompatibilityRequirement as controller
(use controllerutil.SetControllerReference or construct an OwnerReference) and
patch/update the existingWebhookConfig via r.client.Patch or r.client.Update,
handling conflicts/retries; only return
errWebhookConfigNotControlledByCompatibilityRequirement if the patch/update
fails or owner adoption is rejected. Apply the same adoption logic to the
analogous check for MutatingWebhookConfiguration around the other block
referenced (lines 263-268).
- Around line 202-204: The current disabled/unconfigured path calls
removeObjectValidationWebhook which can delete cluster-scoped
ValidatingWebhookConfigurations that this controller does not own; update the
logic so we only remove webhooks that this controller created/owns: modify
removeObjectValidationWebhook to fetch the ValidatingWebhookConfiguration and
verify ownership (e.g., ownerReference matching the compatibility CR's UID or a
controller-specific label/annotation set when creating the webhook) before
deleting, and adjust the reconcile branch around
isObjectValidationWebhookEnabled/compatibilityCRD to skip deletion when there is
no compatibility CR present; use the symbols isObjectValidationWebhookEnabled,
removeObjectValidationWebhook, and compatibilityCRD to locate and change the
code.

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Pro

Run ID: 0067868a-73bb-491f-98b3-a31f570b610c

📥 Commits

Reviewing files that changed from the base of the PR and between fa03d1b and c54005f.

📒 Files selected for processing (12)
  • pkg/controllers/crdcompatibility/objectpruning/handle_test.go
  • pkg/controllers/crdcompatibility/objectpruning/suite_test.go
  • pkg/controllers/crdcompatibility/objectpruning/validator_unit_test.go
  • pkg/controllers/crdcompatibility/objectpruning/webhook.go
  • pkg/controllers/crdcompatibility/objectvalidation/handle_test.go
  • pkg/controllers/crdcompatibility/objectvalidation/suite_test.go
  • pkg/controllers/crdcompatibility/objectvalidation/validator_unit_test.go
  • pkg/controllers/crdcompatibility/objectvalidation/webhook.go
  • pkg/controllers/crdcompatibility/reconcile.go
  • pkg/controllers/crdcompatibility/reconcile_test.go
  • pkg/test/crdbuilder.go
  • pkg/test/warninghandler.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/test/crdbuilder.go

Comment thread pkg/controllers/crdcompatibility/objectvalidation/webhook.go
Comment thread pkg/controllers/crdcompatibility/reconcile.go
Comment on lines +209 to +214
existingWebhookConfig := &admissionregistrationv1.ValidatingWebhookConfiguration{}
if err := r.client.Get(ctx, types.NamespacedName{Name: webhookConfig.Name}, existingWebhookConfig); err != nil && !apierrors.IsNotFound(err) {
return fmt.Errorf("failed to get ValidatingWebhookConfiguration %s: %w", webhookConfig.Name, err)
} else if err == nil && !metav1.IsControlledBy(existingWebhookConfig, obj) {
return fmt.Errorf("%w: %s", errWebhookConfigNotControlledByCompatibilityRequirement, webhookConfig.Name)
}
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Mar 16, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add a migration path for existing webhook configs before enforcing ownership.

These checks only accept configs that already have a controller ref to the CompatibilityRequirement. Because this PR also starts adding that owner ref to generated configs, any same-name VWC/MWC already present during upgrade will terminal-error here instead of being adopted or patched, which can wedge reconciliation until manual cleanup.

Also applies to: 263-268

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

In `@pkg/controllers/crdcompatibility/reconcile.go` around lines 209 - 214, The
check that returns an error when an existing
ValidatingWebhookConfiguration/MutatingWebhookConfiguration
(existingWebhookConfig) is not owned by the CompatibilityRequirement (obj)
should instead attempt a migration/adoption: after r.client.Get finds an
existing resource and metav1.IsControlledBy(existingWebhookConfig, obj) is
false, try to adopt it by setting the CompatibilityRequirement as controller
(use controllerutil.SetControllerReference or construct an OwnerReference) and
patch/update the existingWebhookConfig via r.client.Patch or r.client.Update,
handling conflicts/retries; only return
errWebhookConfigNotControlledByCompatibilityRequirement if the patch/update
fails or owner adoption is rejected. Apply the same adoption logic to the
analogous check for MutatingWebhookConfiguration around the other block
referenced (lines 263-268).

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 isn't required, as the feature has not been released.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@mdbooth, understood — since this feature hasn't shipped yet, there are no pre-existing webhook configurations without owner refs that could be encountered during upgrade. The concern doesn't apply here.

@JoelSpeed JoelSpeed force-pushed the compatibility-admit-warn branch from c54005f to 0a75757 Compare March 16, 2026 13:30
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.

♻️ Duplicate comments (1)
pkg/controllers/crdcompatibility/reconcile.go (1)

209-214: ⚠️ Potential issue | 🟠 Major

Add upgrade adoption path before hard-failing on webhook ownership.

Line 212 and Line 271 still terminal-error on same-name webhook configs lacking owner refs. That can block reconciliation after upgrade from legacy configs until manual intervention.

Suggested direction
@@
-	} else if err == nil && !metav1.IsControlledBy(existingWebhookConfig, obj) {
-		return fmt.Errorf("%w: %s", errWebhookConfigNotControlledByCompatibilityRequirement, webhookConfig.Name)
+	} else if err == nil && !metav1.IsControlledBy(existingWebhookConfig, obj) {
+		// Legacy migration path: adopt only unowned configs; keep failing for foreign-owned configs.
+		if len(existingWebhookConfig.OwnerReferences) > 0 {
+			return fmt.Errorf("%w: %s", errWebhookConfigNotControlledByCompatibilityRequirement, webhookConfig.Name)
+		}
+		existingWebhookConfig.OwnerReferences = []metav1.OwnerReference{
+			*metav1.NewControllerRef(obj, apiextensionsv1alpha1.GroupVersion.WithKind("CompatibilityRequirement")),
+		}
+		if err := r.client.Update(ctx, existingWebhookConfig); err != nil {
+			return fmt.Errorf("failed to adopt ValidatingWebhookConfiguration %s: %w", webhookConfig.Name, err)
+		}
 	}
@@
-	} else if err == nil && !metav1.IsControlledBy(existingWebhookConfig, obj) {
-		return fmt.Errorf("%w: %s", errWebhookConfigNotControlledByCompatibilityRequirement, webhookConfig.Name)
+	} else if err == nil && !metav1.IsControlledBy(existingWebhookConfig, obj) {
+		if len(existingWebhookConfig.OwnerReferences) > 0 {
+			return fmt.Errorf("%w: %s", errWebhookConfigNotControlledByCompatibilityRequirement, webhookConfig.Name)
+		}
+		existingWebhookConfig.OwnerReferences = []metav1.OwnerReference{
+			*metav1.NewControllerRef(obj, apiextensionsv1alpha1.GroupVersion.WithKind("CompatibilityRequirement")),
+		}
+		if err := r.client.Update(ctx, existingWebhookConfig); err != nil {
+			return fmt.Errorf("failed to adopt MutatingWebhookConfiguration %s: %w", webhookConfig.Name, err)
+		}
 	}

Also applies to: 268-273

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

In `@pkg/controllers/crdcompatibility/reconcile.go` around lines 209 - 214, The
current logic in reconcile.go returns a hard error when an existing
ValidatingWebhookConfiguration with the same name is found but not controlled by
the CompatibilityRequirement (check uses metav1.IsControlledBy on
existingWebhookConfig and returns
errWebhookConfigNotControlledByCompatibilityRequirement); instead implement an
upgrade/adoption path: if r.client.Get finds an existing webhook and
metav1.IsControlledBy(...) is false, attempt to adopt it by adding the
CompatibilityRequirement as an owner reference to existingWebhookConfig and
updating it via r.client.Update (or Patch) while handling conflicts/retries, and
only return the ownership error if the adopt/update fails; apply the same change
to the equivalent block around lines 268-273 that checks
MutatingWebhookConfiguration ownership.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@pkg/controllers/crdcompatibility/reconcile.go`:
- Around line 209-214: The current logic in reconcile.go returns a hard error
when an existing ValidatingWebhookConfiguration with the same name is found but
not controlled by the CompatibilityRequirement (check uses metav1.IsControlledBy
on existingWebhookConfig and returns
errWebhookConfigNotControlledByCompatibilityRequirement); instead implement an
upgrade/adoption path: if r.client.Get finds an existing webhook and
metav1.IsControlledBy(...) is false, attempt to adopt it by adding the
CompatibilityRequirement as an owner reference to existingWebhookConfig and
updating it via r.client.Update (or Patch) while handling conflicts/retries, and
only return the ownership error if the adopt/update fails; apply the same change
to the equivalent block around lines 268-273 that checks
MutatingWebhookConfiguration ownership.

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Pro

Run ID: 1edcbf9a-908b-4ccf-91ea-1fabffeb280c

📥 Commits

Reviewing files that changed from the base of the PR and between c54005f and 0a75757.

📒 Files selected for processing (12)
  • pkg/controllers/crdcompatibility/objectpruning/handle_test.go
  • pkg/controllers/crdcompatibility/objectpruning/suite_test.go
  • pkg/controllers/crdcompatibility/objectpruning/validator_unit_test.go
  • pkg/controllers/crdcompatibility/objectpruning/webhook.go
  • pkg/controllers/crdcompatibility/objectvalidation/handle_test.go
  • pkg/controllers/crdcompatibility/objectvalidation/suite_test.go
  • pkg/controllers/crdcompatibility/objectvalidation/validator_unit_test.go
  • pkg/controllers/crdcompatibility/objectvalidation/webhook.go
  • pkg/controllers/crdcompatibility/reconcile.go
  • pkg/controllers/crdcompatibility/reconcile_test.go
  • pkg/test/crdbuilder.go
  • pkg/test/warninghandler.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • pkg/controllers/crdcompatibility/objectpruning/suite_test.go
  • pkg/controllers/crdcompatibility/objectpruning/webhook.go

@JoelSpeed
Copy link
Copy Markdown
Contributor Author

/verified by @sunzhaohua2

@openshift-ci-robot openshift-ci-robot added the verified Signifies that the PR passed pre-merge verification criteria label Mar 19, 2026
@openshift-ci-robot
Copy link
Copy Markdown

@JoelSpeed: This PR has been marked as verified by @sunzhaohua2.

Details

In response to this:

/verified by @sunzhaohua2

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.

@damdo damdo requested a review from mdbooth March 19, 2026 14:37
@JoelSpeed JoelSpeed force-pushed the compatibility-admit-warn branch from 0a75757 to f7ea34d Compare March 22, 2026 15:30
@openshift-ci-robot openshift-ci-robot removed the verified Signifies that the PR passed pre-merge verification criteria label Mar 22, 2026
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: 1

🧹 Nitpick comments (2)
pkg/controllers/crdcompatibility/reconcile.go (1)

275-275: Stale comment should be removed or relocated.

The comment "If we don't own the webhook config, we should not be overwriting it." appears after the ownership check (lines 271-273), making it misleading since the check already happened above.

🔧 Suggested fix
-	// If we don't own the webhook config, we should not be overwriting it.
 	if _, _, err := resourceapply.ApplyMutatingWebhookConfigurationImproved(
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/controllers/crdcompatibility/reconcile.go` at line 275, The comment "If
we don't own the webhook config, we should not be overwriting it." is stale
because the ownership check is already performed just above it; remove or
relocate that comment in pkg/controllers/crdcompatibility/reconcile.go (inside
the reconcile/Reconcile function) so it no longer appears after the ownership
check, or update it to reflect the actual behavior (e.g., "ownership was checked
above; skipping overwrite if not owned"). Ensure the comment string is either
deleted or moved/rewritten to precede the ownership check or accurately describe
the post-check path.
pkg/controllers/crdcompatibility/objectpruning/webhook.go (1)

303-310: Consider extracting duplicate helper functions to a shared package.

isObjectValidationWebhookEnabled and labelSelectorIsEmpty are duplicated in:

  • pkg/controllers/crdcompatibility/reconcile.go
  • pkg/controllers/crdcompatibility/objectpruning/webhook.go
  • pkg/controllers/crdcompatibility/objectvalidation/webhook.go

These could be consolidated into a shared utility package to reduce duplication.

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

In `@pkg/controllers/crdcompatibility/objectpruning/webhook.go` around lines 303 -
310, The isObjectValidationWebhookEnabled and labelSelectorIsEmpty helpers are
duplicated; extract them into a shared utility (e.g., a new package like
crdcompat/util or crdcompat/helpers), move the implementations for
labelSelectorIsEmpty and isObjectValidationWebhookEnabled there, update callers
in reconcile.go, objectpruning/webhook.go, and objectvalidation/webhook.go to
import that package and call util.LabelSelectorIsEmpty and
util.IsObjectValidationWebhookEnabled (or similar exported names), and remove
the local duplicate implementations so compilation imports/uses the single
shared functions.
🤖 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/crdcompatibility/objectvalidation/handle_test.go`:
- Around line 908-911: The Eventually call wrapping kWithCtx(ctx).Update(...)
for liveCRD lacks the .WithContext(ctx) invocation used elsewhere, which can
prevent proper timeout/cancellation; update that call to use
Eventually(...).WithContext(ctx).Should(Succeed()) so the test uses the provided
ctx for timeout control—specifically modify the Eventually invocation that wraps
kWithCtx(ctx).Update(liveCRD, func() { ... }) to append .WithContext(ctx) before
.Should(Succeed()).

---

Nitpick comments:
In `@pkg/controllers/crdcompatibility/objectpruning/webhook.go`:
- Around line 303-310: The isObjectValidationWebhookEnabled and
labelSelectorIsEmpty helpers are duplicated; extract them into a shared utility
(e.g., a new package like crdcompat/util or crdcompat/helpers), move the
implementations for labelSelectorIsEmpty and isObjectValidationWebhookEnabled
there, update callers in reconcile.go, objectpruning/webhook.go, and
objectvalidation/webhook.go to import that package and call
util.LabelSelectorIsEmpty and util.IsObjectValidationWebhookEnabled (or similar
exported names), and remove the local duplicate implementations so compilation
imports/uses the single shared functions.

In `@pkg/controllers/crdcompatibility/reconcile.go`:
- Line 275: The comment "If we don't own the webhook config, we should not be
overwriting it." is stale because the ownership check is already performed just
above it; remove or relocate that comment in
pkg/controllers/crdcompatibility/reconcile.go (inside the reconcile/Reconcile
function) so it no longer appears after the ownership check, or update it to
reflect the actual behavior (e.g., "ownership was checked above; skipping
overwrite if not owned"). Ensure the comment string is either deleted or
moved/rewritten to precede the ownership check or accurately describe the
post-check path.

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Pro

Run ID: b448f091-3ee1-4869-9304-188afc92371e

📥 Commits

Reviewing files that changed from the base of the PR and between 0a75757 and f7ea34d.

📒 Files selected for processing (12)
  • pkg/controllers/crdcompatibility/objectpruning/handle_test.go
  • pkg/controllers/crdcompatibility/objectpruning/suite_test.go
  • pkg/controllers/crdcompatibility/objectpruning/validator_unit_test.go
  • pkg/controllers/crdcompatibility/objectpruning/webhook.go
  • pkg/controllers/crdcompatibility/objectvalidation/handle_test.go
  • pkg/controllers/crdcompatibility/objectvalidation/suite_test.go
  • pkg/controllers/crdcompatibility/objectvalidation/validator_unit_test.go
  • pkg/controllers/crdcompatibility/objectvalidation/webhook.go
  • pkg/controllers/crdcompatibility/reconcile.go
  • pkg/controllers/crdcompatibility/reconcile_test.go
  • pkg/test/crdbuilder.go
  • pkg/test/warninghandler.go
✅ Files skipped from review due to trivial changes (2)
  • pkg/test/crdbuilder.go
  • pkg/test/warninghandler.go
🚧 Files skipped from review as they are similar to previous changes (5)
  • pkg/controllers/crdcompatibility/objectvalidation/validator_unit_test.go
  • pkg/controllers/crdcompatibility/objectvalidation/suite_test.go
  • pkg/controllers/crdcompatibility/objectpruning/suite_test.go
  • pkg/controllers/crdcompatibility/objectpruning/validator_unit_test.go
  • pkg/controllers/crdcompatibility/reconcile_test.go

Comment thread pkg/controllers/crdcompatibility/objectvalidation/handle_test.go
Copy link
Copy Markdown
Contributor

@mdbooth mdbooth left a comment

Choose a reason for hiding this comment

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

A few comments inline. Nothing I'd block on this week.

I would appreciate the requested change to re-use duplicate test code. I find this kind of highly duplicated test very difficult to 'see' when trying to read the test. You can't transfer context from test to test because you're scanning to see if any lines are different.

We're also missing test coverage for:

  • Setting owner references on webhooks
  • Ownership conflict on webhooks
  • Non-cleanup of non-owned webhooks

}

By("Checking that the webhook configurations are not present")
Expect(kWithCtx(ctx).Get(noObjectSchemaValidatingWebhook)()).To(MatchError(ContainSubstring("not found")))
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.

nit: Discovered this recently and like it.

Suggested change
Expect(kWithCtx(ctx).Get(noObjectSchemaValidatingWebhook)()).To(MatchError(ContainSubstring("not found")))
Expect(kWithCtx(ctx).Get(noObjectSchemaValidatingWebhook)()).To(Satisfy(apierrors.IsNotFound))

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.

What's the output when it does not satisfy?

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.

The error.

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.

Expect(kWithCtx(ctx).Get(noObjectSchemaValidatingWebhook)()).NotTo(Satisfy(apierrors.IsNotFound), "not found")

Gives:

  [FAILED] not found
  Expected
      <*errors.StatusError | 0x2676b5f6b9a0>:                                                                                                                                                                                                                                                                               validatingwebhookconfigurations.admissionregistration.k8s.io "test-requirement-bqhtq" not found
      {
          ErrStatus: {
              TypeMeta: {Kind: "", APIVersion: ""},
              ListMeta: {
                  SelfLink: "",
                  ResourceVersion: "",
                  Continue: "",
                  RemainingItemCount: nil,
              },
              Status: "Failure",
              Message: "validatingwebhookconfigurations.admissionregistration.k8s.io \"test-requirement-bqhtq\" not found",
              Reason: "NotFound",                                                                                                                                                                                                                                                                                                   Details: {                                                                                                                                                                                                                                                                                                                Name: "test-requirement-bqhtq",                                                                                                                                                                                                                                                                                       Group: "admissionregistration.k8s.io",                                                                                                                                                                                                                                                                                Kind: "validatingwebhookconfigurations",                                                                                                                                                                                                                                                                              UID: "",                                                                                                                                                                                                                                                                                                              Causes: nil,                                                                                                                                                                                                                                                                                                          RetryAfterSeconds: 0,                                                                                                                                                                                                                                                                                             },                                                                                                                                                                                                                                                                                                                    Code: 404,                                                                                                                                                                                                                                                                                                        },                                                                                                                                                                                                                                                                                                                }                                                                                                                                                                                                                                                                                                                 to not satisfy predicate                                                                                                                                                                                                                                                                                                  <func(error) bool>: 0xa62c00                                                                                                                                                                                                                                                                                      In [It] at: /home/mbooth/src/openshift/cluster-capi-operator/pkg/controllers/crdcompatibility/reconcile_test.go:402 @ 03/25/26 19:08:01.169                                                                                                                                                                         

So... you have to remember to include an error message because the address of the predicate isn't that revealing. I guess there's not much in it.

I won't make this change this in your PR.

requirementWithoutObjectSchemaValidation.Spec.ObjectSchemaValidation = requirement.Spec.ObjectSchemaValidation
})).WithContext(ctx).Should(Succeed())

By("Checking that the webhook configurations are now present")
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.

nit: My preference would be to wait on Admitted=true with the correct observedGeneration, then assert without Eventually that the webhooks are not present.

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.

Do we have an observed generation to observe for this test?

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.

We just updated the CR, so whatever we got back from that.

return fmt.Errorf("failed to delete ValidatingWebhookConfiguration %s: %w", webhookConfig.Name, err)
}

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

nit: I don't think we're adding Finalizers so this is probably ok in practice. However, in general I'd prefer to hold here until the object is gone.

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.

Does that not add unnecessary delay when you're reconciling multiple objects? If the object still exists it will come back through the queue and then be re-delete-attempted later?

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.

It does delay, but it's a correct delay: Admitted is not set until the managed object is gone first. In practice the delay will be extremely short, almost instantaneous. Also we'll be reconciled again anyway.

By("Attempting to update the object, should prune the object again", func() {
inputObject.Object["spec"] = scenario.InputObject["spec"]
Expect(cl.Update(ctx, inputObject)).To(Succeed())
})
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.

nit: deepcopy again?

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 probably a good idea to avoid mutation, good catch

Comment on lines +838 to +843
invalidObj := test.NewTestObject(gvk).
WithNamespace(namespace).
WithField("requiredField", "value").
WithNestedField("spec.replicas", int64(150)). // Above maximum of 100
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.

Test object doesn't match the test description.

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.

Test description is wrong, the test case needs to test numeric bounds because the required/not required distinction isn't testable here

}, defaultNodeTimeout)
})

Context("when ObjectSchemaValidation Action is Warn for status subresource", func() {
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.

nit: These tests are almost identical. I think they would be clearer as a table.

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.

I generally like tables, so sure, lets try

mdbooth added 2 commits March 27, 2026 08:43
Fixes 2 discovered issues:
* Ownership conflicts should be terminal
* Conflict detection was missing on validation webhook delete path
@mdbooth mdbooth force-pushed the compatibility-admit-warn branch from cc66378 to e93dc78 Compare March 27, 2026 08:44
@mdbooth
Copy link
Copy Markdown
Contributor

mdbooth commented Mar 27, 2026

/approve
/lgtm
/pipeline auto

@openshift-ci-robot
Copy link
Copy Markdown

Pipeline controller notification

The pipeline-auto label has been added to this PR. Second-stage tests will be triggered automatically when all first-stage tests pass.

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label Mar 27, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Mar 27, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: mdbooth

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 Mar 27, 2026
@mdbooth
Copy link
Copy Markdown
Contributor

mdbooth commented Mar 27, 2026

/verified by CI

@openshift-ci-robot openshift-ci-robot added the verified Signifies that the PR passed pre-merge verification criteria label Mar 27, 2026
@openshift-ci-robot
Copy link
Copy Markdown

@mdbooth: This PR has been marked as verified by CI.

Details

In response to this:

/verified by CI

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.

@mdbooth
Copy link
Copy Markdown
Contributor

mdbooth commented Mar 27, 2026

/pipeline required

@openshift-ci-robot
Copy link
Copy Markdown

Scheduling required tests:
/test e2e-openstack-ovn-techpreview

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-aws-capi-techpreview
/test e2e-aws-ovn
/test e2e-aws-ovn-serial-1of2
/test e2e-aws-ovn-serial-2of2
/test e2e-aws-ovn-techpreview
/test e2e-aws-ovn-techpreview-upgrade
/test e2e-azure-capi-techpreview
/test e2e-azure-ovn-techpreview
/test e2e-azure-ovn-techpreview-upgrade
/test e2e-gcp-capi-techpreview
/test e2e-gcp-ovn-techpreview
/test e2e-metal3-capi-techpreview
/test e2e-openstack-capi-techpreview
/test e2e-vsphere-capi-techpreview
/test regression-clusterinfra-aws-ipi-techpreview-capi

@openshift-ci-robot
Copy link
Copy Markdown

Tests from second stage were triggered manually. Pipeline can be controlled only manually, until HEAD changes. Use command to trigger second stage.

@mdbooth
Copy link
Copy Markdown
Contributor

mdbooth commented Mar 27, 2026

/override pull-ci-openshift-cluster-capi-operator-main-e2e-openstack-ovn-techpreview

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Mar 27, 2026

@mdbooth: Overrode contexts on behalf of mdbooth: ci/prow/e2e-openstack-ovn-techpreview

Details

In response to this:

/override pull-ci-openshift-cluster-capi-operator-main-e2e-openstack-ovn-techpreview

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.

@mdbooth
Copy link
Copy Markdown
Contributor

mdbooth commented Mar 27, 2026

/test e2e-aws-ovn

@mdbooth
Copy link
Copy Markdown
Contributor

mdbooth commented Mar 27, 2026

/override pull-ci-openshift-cluster-capi-operator-main-e2e-openstack-ovn-techpreview

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Mar 27, 2026

@mdbooth: Overrode contexts on behalf of mdbooth: ci/prow/e2e-openstack-ovn-techpreview

Details

In response to this:

/override pull-ci-openshift-cluster-capi-operator-main-e2e-openstack-ovn-techpreview

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.

@mdbooth
Copy link
Copy Markdown
Contributor

mdbooth commented Mar 27, 2026

Looks unrelated, but the same unrelated thing twice.

/test e2e-aws-ovn

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Mar 27, 2026

@JoelSpeed: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/e2e-azure-ovn-techpreview e93dc78 link false /test e2e-azure-ovn-techpreview

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.

@openshift-merge-bot openshift-merge-bot Bot merged commit 8f1b726 into openshift:main Mar 28, 2026
24 of 25 checks passed
@mdbooth mdbooth deleted the compatibility-admit-warn branch March 28, 2026 07:19
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. pipeline-auto verified Signifies that the PR passed pre-merge verification criteria

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants