Skip to content

feat: OLMv1 lifecycle — fresh install tests + OLMv0→OLMv1 migration target#2160

Open
weshayutin wants to merge 16 commits into
openshift:oadp-devfrom
weshayutin:olmv1tests
Open

feat: OLMv1 lifecycle — fresh install tests + OLMv0→OLMv1 migration target#2160
weshayutin wants to merge 16 commits into
openshift:oadp-devfrom
weshayutin:olmv1tests

Conversation

@weshayutin
Copy link
Copy Markdown
Contributor

@weshayutin weshayutin commented Apr 10, 2026

Overview

Enable OADP users to install and migrate to OLMv1 (ClusterExtension-based) management. This PR covers:

  1. Fresh OLMv1 install/upgrade Ginkgo test suite (tests/olmv1/)
  2. make test-olmv1 / make test-olmv1-cleanup Makefile targets
  3. make generate-olmv1-manifest — generates OLMv1 install manifest per OCPSTRAT-2268 adoption template
  4. make upgrade-v0-to-olmv1 Makefile target for migrating existing OLMv0 installs
  5. make test-upgrade-v0-to-olmv1 — Ginkgo migration test with version verification
  6. CSV installModes: enable SingleNamespace=true (OADP-4051)
  7. CI/Prow compatibility — auto-detects CatalogSource from any namespace, appends migration test to test-e2e

Fixes #2194
Fixes #2193


Related Issues & Epics

Ticket Summary Status
OADP-7235 OADP OLMv1 phase 2 install test In Progress
OADP-4051 OADP installModes / cluster-scoped install New
#2194 Add upgrade-v0-to-olmv1 Makefile target Open
#2193 Test coverage for OLMv0→OLMv1 migration Open
OPRUN-4131 [Dependency] GA Single/OwnNamespace support in OLMv1 Release Pending ✅
OCPSTRAT-1982 [Dependency] OLMv1 manage OwnNamespace/SingleNamespace operators Release Pending ✅
OCPSTRAT-2268 OLMv1 operator adoption — manifest template & naming conventions Reference

Progress

Fresh Install — test-olmv1 (OADP-7235)

  • OLMV1_* Makefile variables (OLMV1_PACKAGE, OLMV1_NAMESPACE, OLMV1_CHANNEL, OLMV1_VERSION, OLMV1_UPGRADE_VERSION, OLMV1_CATALOG, OLMV1_CATALOG_IMAGE, OLMV1_SERVICE_ACCOUNT, OLMV1_INSTALLER_BINDING)
  • make test-olmv1 target — runs Ginkgo suite against cluster
  • make test-olmv1-cleanup target — deletes ClusterExtension, ClusterCatalog, SA, CRB
  • Test: install OADP via ClusterExtension (waits for Installed=True, fail-fast on InvalidConfiguration/Failed)
  • Test: controller-manager pod reaches Running
  • Test: 6 OADP/Velero CRDs present
  • Test: no deprecation conditions (Deprecated, PackageDeprecated, ChannelDeprecated, BundleDeprecated all False)
  • Test: upgrade via upgradeConstraintPolicy: SelfCertified (skipped when OLMV1_UPGRADE_VERSION unset)
  • Helper: cleanupOrphanedCRDs — removes *.oadp.openshift.io / *.velero.io CRDs left by OLMv0 (OLMv1 cannot adopt CRDs it didn't create)
  • Helper: ensureClusterCatalog / waitForClusterCatalogServing for custom catalog images
  • Tested against productized catalog (OLMV1_PACKAGE=redhat-oadp-operator) — PASSED using redhat-operator-index:v4.21 as ClusterCatalog (v4.22 index does not include OADP yet). Installed redhat-oadp-operator v1.5.5 from registry.redhat.io/oadp/oadp-operator-bundle, controller-manager Running, 6 CRDs created, no deprecation warnings
  • CI job wired up

OLMv1 Manifest — generate-olmv1-manifest (OCPSTRAT-2268)

  • make generate-olmv1-manifest — generates oadp-olmv1-manifest.yaml per official adoption template
  • Naming follows OCPSTRAT-2268 convention: SA=<pkg>-installer, CRB=<pkg>-installer-binding
  • Optional OLMV1_CHANNEL / OLMV1_VERSION appended when set
  • Optional OLMV1_PIN_CATALOG — adds selector.matchLabels to pin ClusterExtension to a specific ClusterCatalog
  • Generated file added to .gitignore

OLMv0 → OLMv1 Migration — upgrade-v0-to-olmv1 (#2194)

  • make upgrade-v0-to-olmv1 target:
    • Phase 1: Build fresh operator/bundle/catalog images (avoids expired ttl.sh). Skip with OLMV1_CATALOG_IMAGE=<image>
    • Phase 2: Remove OLMv0 Subscription, OperatorGroup, CSV, CatalogSource (scans both openshift-marketplace and operator namespace for CI compatibility)
    • Phase 3: Delete orphaned *.oadp.openshift.io and *.velero.io CRDs
    • Phase 3b: Delete olm.managed=true labeled remnants (SA, Roles, RoleBindings, Deployments, ClusterRoles, ClusterRoleBindings)
    • Phase 4: Create ClusterCatalog with verbose error diagnostics (image ref, catalogd logs, ttl.sh expiry hint)
    • Phase 5: Apply ClusterExtension pinned to specific ClusterCatalog via selector.matchLabels
    • Phase 6: Wait for condition=Installed=True

Migration Test — test-upgrade-v0-to-olmv1 (#2193)

  • Ginkgo test suite (olmv1_migrate_test.go) with structured assertions
  • Auto-detects CatalogSource image from OLMv0 Subscription (spec.source + spec.sourceNamespace)
  • CatalogSource cleanup scans both openshift-marketplace and operator namespace (CI creates CatalogSource in operator namespace via optional-operators-subscribe)
  • Captures OLMv0 CSV version before migration
  • Verifies OLMv1 installed bundle version matches OLMv0 CSV version
  • Verifies installed bundle came from expected catalog (not community default)
  • Removes olm.managed=true remnant resources (ServiceAccounts, Roles, Deployments, ClusterRoles, etc.)
  • Appended to make test-e2e — runs after e2e tests complete, migration failure does not mask e2e exit code
  • JUnit XML output at $(ARTIFACT_DIR)/junit_olmv1_report.xml

CSV / Bundle (OADP-4051)

  • Enable SingleNamespace: true in installModes — Velero already supports single-namespace via WATCH_NAMESPACE; OwnNamespace vs SingleNamespace only differs in whether watched namespace equals install namespace

Design Notes

Why spec.config.inline.watchNamespace (not an annotation)

OADP's CSV declares OwnNamespace install mode. OLMv1 requires spec.config.inline.watchNamespace set to the install namespace — without it the install fails with InvalidConfiguration. The metadata annotation olm.operatorframework.io/watch-namespace is not read by operator-controller; only the spec field matters.

Why delete CRDs before migrating from OLMv0

OLMv1 takes ownership of CRDs it creates. CRDs already present on the cluster (owned by OLMv0 or manually created) cannot be adopted — the install will proceed but CRD lifecycle management is broken. cleanupOrphanedCRDs handles this by deleting *.oadp.openshift.io and *.velero.io CRDs before install.

Why pin ClusterExtension to a specific ClusterCatalog

Without catalog.selector.matchLabels, OLMv1 resolves from all available ClusterCatalogs. On clusters with default catalogs (e.g., openshift-community-operators), the community OADP package (v0.5.6) may be selected instead of the custom build. Pinning via olm.operatorframework.io/metadata.name: <catalog> ensures resolution from the correct catalog.

CI/Prow compatibility

Prow's optional-operators-subscribe step creates CatalogSource in OO_INSTALL_NAMESPACE (typically openshift-adp), not openshift-marketplace. The migration test reads spec.sourceNamespace from the Subscription to find CatalogSources in any namespace. Both Makefile and Go test clean up CatalogSources from both locations.

Why enable SingleNamespace installMode (falsetrue)

OLMv1 does not distinguish between OwnNamespace and SingleNamespace — both mean the operator watches a single namespace. OLMv1's spec.config.inline.watchNamespace field controls which namespace, regardless of installMode type. With SingleNamespace: false, OLMv1 rejects installs where the watched namespace differs from the install namespace, even though the OADP controller handles this identically (it reads WATCH_NAMESPACE either way). Enabling SingleNamespace gives OLMv1 users the flexibility to watch a namespace other than the install namespace without any operator code changes. The operator's WATCH_NAMESPACE env var works the same in both modes.

No operator Go code changes needed

WATCH_NAMESPACE in config/manager/manager.yaml is set from fieldRef: metadata.namespace. OLMv1 propagates spec.config.inline.watchNamespace as the WATCH_NAMESPACE env var into the deployed manager, overriding the fieldRef. The controller reads WATCH_NAMESPACE identically regardless of who set it.

Platform requirement

OCP 4.20+ with OLMv1 enabled (operator-controller and catalogd running). OPRUN-4131 (GA Single/OwnNamespace support — removes the TechPreviewNoUpgrade feature gate requirement) is Release Pending, so no feature gate needed on 4.20+.


Usage

# Generate OLMv1 manifest only (review before applying)
make generate-olmv1-manifest
cat oadp-olmv1-manifest.yaml

# Fresh OLMv1 install against a custom catalog
make test-olmv1 OLMV1_CATALOG_IMAGE=ttl.sh/oadp-operator-catalog-<rev>:1h

# Fresh OLMv1 install against productized catalog
make test-olmv1 OLMV1_PACKAGE=redhat-oadp-operator

# Migrate an existing OLMv0 install to OLMv1 (shell-based, builds fresh images)
make deploy-olm
make upgrade-v0-to-olmv1

# Test migration path with Ginkgo assertions and version verification
make deploy-olm
make test-upgrade-v0-to-olmv1 OLMV1_CATALOG_IMAGE=<image>

# In CI: test-upgrade-v0-to-olmv1 runs automatically after test-e2e.
# It auto-detects the CatalogSource image from the Subscription created by
# optional-operators-subscribe (no OLMV1_CATALOG_IMAGE needed).

# Cleanup
make test-olmv1-cleanup

How to Test (Reviewer Guide)

Prerequisites: OCP 4.20+ cluster with OLMv1 enabled (operator-controller + catalogd running). Logged in via oc login.

1. Fresh OLMv1 install (no prior OADP)

# Build and push a catalog image with current branch code
make docker-build docker-push bundle bundle-build bundle-push catalog-build catalog-push

# Run the fresh install test
make test-olmv1 OLMV1_CATALOG_IMAGE=$CATALOG_IMG

# Verify: all Ginkgo specs pass, controller-manager pod Running, CRDs created
make test-olmv1-cleanup

2. OLMv0 → OLMv1 migration (shell-based)

# Install OADP via OLMv0 first
make deploy-olm

# Verify OLMv0 install is running
oc get csv -n openshift-adp
oc get pods -n openshift-adp

# Run migration (builds fresh images automatically)
make upgrade-v0-to-olmv1

# Verify: ClusterExtension shows Installed=True, controller-manager Running
oc get clusterextension oadp-operator
oc get pods -n openshift-adp

3. OLMv0 → OLMv1 migration test (Ginkgo with assertions)

# Install OADP via OLMv0 first
make deploy-olm

# Run migration test — auto-detects CatalogSource from the Subscription
make test-upgrade-v0-to-olmv1 OLMV1_CATALOG_IMAGE=$CATALOG_IMG

# Verify: all specs pass, JUnit report at /tmp/junit_olmv1_report.xml
# The test checks:
#   - All OLMv0 resources removed (Subscription, CSV, CRDs, olm.managed=true remnants)
#   - ClusterExtension Installed=True
#   - Installed version matches pre-migration CSV version
#   - Bundle came from expected catalog (not community default)
#   - controller-manager pod Running

4. Manifest generation

make generate-olmv1-manifest
cat oadp-olmv1-manifest.yaml
# Verify: contains Namespace, ServiceAccount, ClusterRoleBinding, ClusterExtension
# with watchNamespace set and correct naming convention

5. SingleNamespace installMode

# Check the CSV change
grep -A4 installModes bundle/manifests/oadp-operator.clusterserviceversion.yaml
# Verify: SingleNamespace is now supported: true

Common issues:

  • ttl.sh images expire after TTL_DURATION (default 1h) — rebuild if tests fail with image pull errors
  • OCP < 4.20 does not have OLMv1 APIs — ClusterExtension CRD will not exist
  • If migration test picks wrong version (e.g., community 0.5.6), check that OLMV1_CATALOG_IMAGE is set or CatalogSource auto-detection found the right one

Files Changed

File Purpose
Makefile OLMv1 targets, migration phases, CI-compatible cleanup, appended to test-e2e
tests/olmv1/olmv1_suite_test.go Test suite setup, helpers, ClusterCatalog diagnostics
tests/olmv1/olmv1_install_test.go Fresh install/upgrade test specs
tests/olmv1/olmv1_migrate_test.go Migration test with version verification and catalog validation
tests/olmv1/.gitignore Ignore test binaries
.gitignore Ignore generated oadp-olmv1-manifest.yaml
.golangci.yaml Exclude tests/olmv1/ from linting
bundle/manifests/oadp-operator.clusterserviceversion.yaml Enable SingleNamespace installMode
config/manifests/bases/oadp-operator.clusterserviceversion.yaml Enable SingleNamespace installMode

Note

Responses generated with Claude

Summary by CodeRabbit

  • New Features

    • Enabled operator installation in its own namespace via OwnNamespace install mode support.
  • Tests

    • Added comprehensive OLMv1 lifecycle testing including installation and upgrade scenarios.
    • Added automated testing for OLMv0 to OLMv1 migration with resource cleanup and validation.

Signed-off-by: Wesley Hayutin <weshayutin@gmail.com>
@weshayutin weshayutin self-assigned this Apr 10, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 10, 2026

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

Adds OLMv1 end-to-end and migration tests under tests/olmv1, new Makefile variables/targets to run/manage OLMv1 workflows (including upgrade-v0-to-olmv1 and manifest generation), excludes the new tests from unit runs and linters, and updates CSV installModes (OwnNamespace supported). Also adds generated manifest ignore and test tmp ignores.

Changes

OLMv1 tests, Makefile targets, and manifest tweaks

Layer / File(s) Summary
Makefile: configuration variables
Makefile
Introduces OLMv1 variables: OLMV1_PACKAGE, OLMV1_NAMESPACE, OLMV1_CHANNEL, OLMV1_VERSION, OLMV1_UPGRADE_VERSION, OLMV1_CATALOG, OLMV1_CATALOG_IMAGE, OLMV1_SERVICE_ACCOUNT, OLMV1_INSTALLER_BINDING, OLMV1_FAIL_FAST, and OLMV1_MANIFEST.
Makefile: ginkgo flags & targets
Makefile
Adds OLMV1_GINKGO_FLAGS and new targets: test-olmv1, test-olmv1-cleanup, generate-olmv1-manifest, upgrade-v0-to-olmv1, test-upgrade-v0-to-olmv1; updates test to exclude tests/e2e and tests/olmv1; test-e2e now runs migration test flow post-E2E and preserves E2E exit code.
Makefile: manifest generation & upgrade flow
Makefile
generate-olmv1-manifest builds a ClusterExtension manifest with optional catalog pinning via OLMV1_PIN_CATALOG; upgrade-v0-to-olmv1 implements shell-based migration flow (optional build of operator/bundle/catalog, remove OLMv0 remnants, create ClusterCatalog, generate/apply OLMv1 manifest, wait for install).
Test harness / initialization
tests/olmv1/olmv1_suite_test.go
New Ginkgo suite: CLI flags, kube/dynamic client setup, global test state, and helpers for namespace/ServiceAccount/ClusterRoleBinding, ClusterExtension/ClusterCatalog build/get/delete, status/condition extraction, CRD checks/cleanup, and polling utilities.
OLMv1 lifecycle tests
tests/olmv1/olmv1_install_test.go
New ordered lifecycle tests: orphaned CRD cleanup, ensure namespace/SA/RBAC, optional ClusterCatalog creation and Serving wait, create ClusterExtension and wait for Installed=True (rejecting certain terminal Progressing reasons), controller-manager pod checks, CRD existence and deprecation checks, optional in-place OLMv1 upgrade flow, and teardown; adds unstructured nested-map helpers.
OLMv0→OLMv1 migration tests
tests/olmv1/olmv1_migrate_test.go
New migration suite (gated by migrate flag): detect/remove OLMv0 Subscriptions/CSVs/OperatorGroups/CatalogSources, clean orphaned CRDs and olm.managed=true remnant resources, optionally create ClusterCatalog from detected catalog image, install via ClusterExtension, wait for Installed=True and bundle/version validation, verify controller-manager pods, and teardown.
Test artifacts & linters
tests/olmv1/.gitignore, .gitignore, .golangci.yaml
Adds tests/olmv1/tmp/ to tests/olmv1/.gitignore, adds oadp-olmv1-manifest.yaml to top-level .gitignore, and excludes tests/olmv1 from golangci-lint exclusions.
CSV manifest formatting & installMode change
bundle/manifests/.../oadp-operator.clusterserviceversion.yaml, config/manifests/bases/.../oadp-operator.clusterserviceversion.yaml
Reflowed installModes formatting in bundle CSV; base CSV now marks OwnNamespace install mode as supported: true (other modes unchanged).

Sequence Diagram(s)

sequenceDiagram
    participant Test as Test Suite
    participant API as Kubernetes API
    participant CC as ClusterCatalog
    participant CE as ClusterExtension Controller
    participant OLM as OLM Resolver

    Test->>API: Create Namespace & ServiceAccount
    Test->>API: Create ClusterRoleBinding (cluster-admin)
    Test->>API: Create ClusterCatalog (from image)
    Test->>CC: Poll until Serving=True
    Test->>API: Create ClusterExtension (reference catalog)
    CE->>OLM: Resolve bundle from catalog
    OLM-->>CE: Return bundle manifest
    CE->>API: Create operator deployment
    Test->>API: Poll ClusterExtension.status (wait Installed=True)
    API-->>Test: Installed condition reached
    Test->>API: Verify controller-manager pods Running
    Test->>API: Verify OADP/Velero CRDs exist
    Test->>API: Check no Deprecated conditions

    alt Upgrade scenario (if upgradeVersion set)
        Test->>API: Patch ClusterExtension to new version
        CE->>OLM: Resolve upgraded bundle
        OLM-->>CE: Return new bundle manifest
        CE->>API: Update operator deployment
        Test->>API: Poll for new bundle version & Installed=True
        Test->>API: Verify controller-manager Running again
    end

    Test->>API: Delete ClusterExtension
    Test->>API: Wait for deletion
    Test->>API: Delete ClusterCatalog
    Test->>API: Delete ClusterRoleBinding & ServiceAccount
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

🚥 Pre-merge checks | ✅ 9 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 19.05% 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 Multiple Expect assertions lack meaningful failure messages in both test files. Fails requirement #4: Assertion messages should include helpful context for diagnosis. Add descriptive messages to Expect statements without them (install_test.go lines 69, 99, 146; migrate_test.go lines 113, 118, 129, 251, 281, 330) like Expect(err).NotTo(HaveOccurred(), "failed to get resource").
Microshift Test Compatibility ⚠️ Warning New Ginkgo e2e tests use OLM APIs unavailable on MicroShift. Tests lack [Skipped:MicroShift], [apigroup:...] tags, or exutil.IsMicroShiftCluster() guards. Add [apigroup:operators.coreos.com] and [apigroup:olm.operatorframework.io] tags to test Describe blocks, or implement exutil.IsMicroShiftCluster() checks with Skip() to prevent failures on MicroShift.
✅ Passed checks (9 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly summarizes the main changes: adding OLMv1 lifecycle support with fresh install tests and OLMv0→OLMv1 migration automation.
Linked Issues check ✅ Passed All coding requirements from linked issues #2194 and #2193 are implemented: Makefile upgrade target, migration test suite, CRD cleanup, RBAC handling, version verification, and CI compatibility.
Out of Scope Changes check ✅ Passed All changes directly support OLMv1 lifecycle implementation. Only ancillary modifications (linting config, gitignore, CSV formatting) are included, all justified and minimal.
Stable And Deterministic Test Names ✅ Passed All Ginkgo test titles in the new olmv1 test files are stable and deterministic. No dynamic content (pod names, timestamps, UUIDs, IPs, variables, etc.) found in test names.
Single Node Openshift (Sno) Test Compatibility ✅ Passed New tests do not assume multi-node clusters. They test single-pod readiness, OLM resource operations, and CRD existence—all compatible with SNO.
Topology-Aware Scheduling Compatibility ✅ Passed PR adds OLMv1 test infrastructure without introducing topology-incompatible scheduling constraints. No required anti-affinity, topology spread constraints, or control-plane nodeSelectors are added.
Ote Binary Stdout Contract ✅ Passed OTE Stdout Contract fully compliant. Process-level code (init, TestOADPOLMv1) contains no stdout writes. All logging is within Ginkgo test blocks where output is intercepted by the framework.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed No IPv4 hardcodes, IPv4-only parsing, or external connectivity requirements. All operations are cluster-internal. Catalog image parameter is optional, allowing fallback to default catalogs.
Description check ✅ Passed The PR description is comprehensive and well-structured, covering the overview, related issues, progress tracking, design notes, usage examples, testing guidance, and files changed.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

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

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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

@weshayutin weshayutin added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Apr 10, 2026
@openshift-ci openshift-ci Bot requested review from mpryc and sseago April 10, 2026 23:51
@openshift-ci
Copy link
Copy Markdown

openshift-ci Bot commented Apr 10, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: weshayutin
Once this PR has been reviewed and has the lgtm label, please assign shubham-pampattiwar for approval. For more information see the Code Review Process.

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

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@config/manager/kustomization.yaml`:
- Around line 7-8: The checked-in kustomization currently pins newName/newTag to
the ephemeral ttl.sh image (ttl.sh/oadp-operator-7e53a850:1h); replace this with
a stable, non-expiring default (e.g., the official oadp-operator image and a
permanent tag or digest) or remove the ttl.sh newName/newTag entries so the
repository manifest does not reference an expiring image; ensure any temporary
ttl.sh usage is moved into CI/deploy workflows that inject the test image
dynamically rather than committing it to kustomization.yaml.

In `@Makefile`:
- Around line 1052-1057: The cleanup target test-olmv1-cleanup unconditionally
deletes ClusterCatalog $(OLMV1_CATALOG); guard that deletion so we only remove a
catalog the tests created by checking the same creation condition or a creation
marker. Modify test-olmv1-cleanup to only run the $(OC_CLI) delete
clustercatalog $(OLMV1_CATALOG) line when OLMV1_CATALOG_IMAGE is set (or when a
persisted marker like OLMV1_CATALOG_CREATED file/env var exists), and update the
Catalog creation step (the rule that creates the catalog) to set that marker
(e.g., touch a file or export a flag) so cleanup can safely detect it before
deleting.

In `@tests/olmv1/olmv1_install_test.go`:
- Around line 107-122: The current gomega.Eventually loop only checks
pod.Status.Phase == corev1.PodRunning which can false-pass; update the check in
the Eventually closure (the block using kubeClient.CoreV1().Pods(...).List and
iterating pods.Items) to verify readiness instead: for each pod, inspect
pod.Status.Conditions for condition.Type == corev1.PodReady with Status ==
corev1.ConditionTrue (or alternatively fetch the Deployment via
kubeClient.AppsV1().Deployments(namespace).Get and assert the Deployment status
has an Available condition == True / status.AvailableReplicas > 0); apply the
same change to the other occurrence mentioned (lines 213-226) so tests assert
PodReady or Deployment Available rather than just PodRunning.
- Around line 167-181: The current code reads the ClusterExtension via
getClusterExtension and then calls
dynamicClient.Resource(clusterExtensionGVR).Update after changing catalogSpec
(using unstructuredNestedMap/unstructuredSetNestedMap), which can race
controller status updates and yield 409s; instead patch only the
spec.source.catalog fields (or wrap the update in retry.RetryOnConflict) rather
than updating the whole object: construct a minimal merge patch containing
spec.source.catalog.version and spec.source.catalog.upgradeConstraintPolicy and
call dynamicClient.Resource(clusterExtensionGVR).Patch with types.MergePatchType
(add import "k8s.io/apimachinery/pkg/types"), or if you prefer keep Update, wrap
the read/modify/write in retry.RetryOnConflict to retry on conflicts. Ensure
references to getClusterExtension, unstructuredNestedMap,
unstructuredSetNestedMap, and dynamicClient.Resource(clusterExtensionGVR) are
updated accordingly.

In `@tests/olmv1/olmv1_suite_test.go`:
- Around line 110-126: The ClusterRoleBinding name in ensureClusterAdminBinding
only uses saName so it can collide across namespaces; change the naming or
reconcile existing bindings: either make bindingName include the namespace
(e.g., bindingName := saName + "-" + ns + "-cluster-admin") so it's unique per
namespace, or when Create returns AlreadyExists call
kubeClient.RbacV1().ClusterRoleBindings().Get to load the existing
ClusterRoleBinding and update its Subjects (add or replace the ServiceAccount
subject for {Name: saName, Namespace: ns}) and then call Update to persist the
corrected subjects; implement one of these approaches inside
ensureClusterAdminBinding.
- Around line 270-295: The cleanupOrphanedCRDs function is destructive on shared
clusters; change it to be gated behind an explicit opt-in (e.g., a test flag or
env var like TEST_DELETE_ORPHAN_CRDS) or a deterministic dedicated-cluster check
before calling dynamicClient.Resource(crdGVR).Delete, and after issuing Delete
for each CRD found by cleanupOrphanedCRDs poll/wait (using
dynamicClient.Resource(crdGVR).Get in a loop with backoff and timeout) until
apierrors.IsNotFound confirms the resource is fully removed before counting it
as deleted; ensure you still handle non-NotFound errors via logging and skip
deletion when the opt-in flag is not set.
- Around line 315-323: When Create on dynamicClient.Resource(clusterCatalogGVR)
returns apierrors.IsAlreadyExists(err), fetch the existing ClusterCatalog (using
dynamicClient.Resource(clusterCatalogGVR).Get with the same name and ctx) and
validate its image field against the requested image variable; if they differ,
fail the test (gomega.Expect/return error) or update/replace the catalog to
match the requested image instead of silently reusing it. Ensure the check
references the existing object's image path (e.g., status/spec field used for
image in ClusterCatalog) and only set createdCatalog = true and log "Created
ClusterCatalog" when you actually created or successfully reconciled the
resource to the desired image.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 77bf8ce7-890a-4973-98c9-d65314a9d12c

📥 Commits

Reviewing files that changed from the base of the PR and between 7e53a85 and 2b88073.

📒 Files selected for processing (5)
  • Makefile
  • config/manager/kustomization.yaml
  • tests/olmv1/.gitignore
  • tests/olmv1/olmv1_install_test.go
  • tests/olmv1/olmv1_suite_test.go

Comment thread config/manager/kustomization.yaml Outdated
Comment thread Makefile
Comment thread tests/olmv1/olmv1_install_test.go
Comment thread tests/olmv1/olmv1_install_test.go Outdated
Comment thread tests/olmv1/olmv1_suite_test.go
Comment thread tests/olmv1/olmv1_suite_test.go
Comment thread tests/olmv1/olmv1_suite_test.go
Signed-off-by: Wesley Hayutin <weshayutin@gmail.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
Makefile (1)

1053-1055: ⚠️ Potential issue | 🟠 Major

Make ClusterCatalog deletion opt-in.

Line 1055 still deletes $(OLMV1_CATALOG) unconditionally. The suite itself only deletes a catalog after it knows it created it (tests/olmv1/olmv1_suite_test.go sets createdCatalog only on successful create, and tests/olmv1/olmv1_install_test.go checks that flag in AfterAll). Pointing this cleanup target at an existing/shared catalog will remove a resource the tests did not own.

🧹 Safer cleanup sketch
+OLMV1_DELETE_CATALOG ?= false
+
 test-olmv1-cleanup: login-required ## Cleanup resources created by OLMv1 tests.
 	$(OC_CLI) delete clusterextension oadp-operator --ignore-not-found=true
-	$(OC_CLI) delete clustercatalog $(OLMV1_CATALOG) --ignore-not-found=true
+	`@if` [ "$(OLMV1_DELETE_CATALOG)" = "true" ]; then \
+		$(OC_CLI) delete clustercatalog $(OLMV1_CATALOG) --ignore-not-found=true; \
+	fi
 	$(OC_CLI) delete clusterrolebinding $(OLMV1_SERVICE_ACCOUNT)-cluster-admin --ignore-not-found=true
 	$(OC_CLI) delete sa $(OLMV1_SERVICE_ACCOUNT) -n $(OLMV1_NAMESPACE) --ignore-not-found=true

If you want parity with the suite’s ownership check, persist a creation marker and key catalog deletion off that instead of a plain name match.

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

In `@Makefile` around lines 1053 - 1055, The Makefile target test-olmv1-cleanup
currently unconditionally deletes the ClusterCatalog $(OLMV1_CATALOG); change it
to be opt-in by checking a persisted "created" marker (e.g., touch a file when
the suite successfully creates the catalog) before running the delete command in
the test-olmv1-cleanup target. Specifically, modify the test-olmv1-cleanup
target to only run `$(OC_CLI) delete clustercatalog $(OLMV1_CATALOG)` if the
marker file exists, and ensure tests that create the catalog
(tests/olmv1/olmv1_suite_test.go and olmv1_install_test.go flow) write/remove
that marker so ownership is respected instead of deleting a shared catalog by
name.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@Makefile`:
- Around line 1053-1055: The Makefile target test-olmv1-cleanup currently
unconditionally deletes the ClusterCatalog $(OLMV1_CATALOG); change it to be
opt-in by checking a persisted "created" marker (e.g., touch a file when the
suite successfully creates the catalog) before running the delete command in the
test-olmv1-cleanup target. Specifically, modify the test-olmv1-cleanup target to
only run `$(OC_CLI) delete clustercatalog $(OLMV1_CATALOG)` if the marker file
exists, and ensure tests that create the catalog
(tests/olmv1/olmv1_suite_test.go and olmv1_install_test.go flow) write/remove
that marker so ownership is respected instead of deleting a shared catalog by
name.

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Pro Plus

Run ID: b65495fa-dc13-49e1-a8c0-13056be93809

📥 Commits

Reviewing files that changed from the base of the PR and between 2b88073 and 76f9c16.

📒 Files selected for processing (1)
  • Makefile

Signed-off-by: Wesley Hayutin <weshayutin@gmail.com>
@kaovilai

This comment has been minimized.

@kaovilai

This comment has been minimized.

@kaovilai

This comment has been minimized.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 5, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
gh issue create \
  --repo openshift/oadp-operator \
  --title "Test OLMv0 to OLMv1 upgrade path/migration" \
  --body "## Overview

This issue tracks the work to add end-to-end tests covering the upgrade/migration path from OLMv0 (classic OLM via \`Subscription\`/\`ClusterServiceVersion\`) to OLMv1 (via \`ClusterExtension\` API) for the OADP operator.

## Background

PR `#2160` adds OLMv1 lifecycle tests (install, upgrade within OLMv1, CRD validation, deprecation checks). However, there is currently no test coverage for the scenario where an operator already installed via OLMv0 is migrated or upgraded to be managed by OLMv1.

## Goals

- Validate that an OADP operator instance installed via OLMv0 (\`Subscription\` + \`OperatorGroup\`) can be successfully migrated to OLMv1 (\`ClusterExtension\`).
- Ensure CRDs, existing \`DataProtectionApplication\` CRs, and Velero resources survive the migration without data loss or downtime.
- Verify that the controller-manager pod transitions cleanly under OLMv1 management post-migration.
- Cover any necessary RBAC, namespace, or \`installMode\` changes (e.g., \`inline.watchNamespace\` in OLMv1 vs. \`watchNamespace\` env var / \`OperatorGroup\` scope in OLMv0).

## References

- PR `#2160`: https://github.com/openshift/oadp-operator/pull/2160
- OLMv0 install mode in CSV: https://github.com/openshift/oadp-operator/blob/7e53a850ffc68b183e6fd7dd3cc134170b8b7f76/config/manifests/bases/oadp-operator.clusterserviceversion.yaml#L467-L475
- OLMv0 watchNamespace config: https://github.com/openshift/oadp-operator/blob/7e53a850ffc68b183e6fd7dd3cc134170b8b7f76/config/manager/manager.yaml#L63-L66

Requested by `@kaovilai`." \
  --assignee kaovilai

Length of output: 55


@kaovilai: Done! I've created the issue here: #2193

The issue — "Test OLMv0 to OLMv1 upgrade path/migration" — covers:

  • Migrating an OADP operator instance from OLMv0 (Subscription/OperatorGroup) to OLMv1 (ClusterExtension)
  • Ensuring CRDs, DataProtectionApplication CRs, and Velero resources survive the migration
  • Verifying controller-manager pod transitions cleanly post-migration
  • Covering RBAC, namespace, and installMode differences (e.g., inline.watchNamespace in OLMv1 vs. watchNamespace env var / OperatorGroup scope in OLMv0)

It's assigned to you and backlinked to PR #2160.

@kaovilai

This comment has been minimized.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 5, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
gh issue create \
  --repo openshift/oadp-operator \
  --title "Add Makefile target to upgrade OLMv0 install to OLMv1 install" \
  --body "## Overview

Add a \`make\` target (e.g., \`make upgrade-v0-to-olmv1\`) that automates upgrading an existing OADP operator installation managed by OLMv0 (\`Subscription\`/\`OperatorGroup\`) to be managed by OLMv1 (\`ClusterExtension\`).

## Background

PR `#2160` introduces OLMv1 lifecycle Makefile targets (\`test-olmv1\`, \`test-olmv1-cleanup\`) for fresh OLMv1 installs. However, there is no automation for the migration/upgrade scenario where an operator is already installed via OLMv0 and needs to be transitioned to OLMv1 management.

## Goals

- Add a parameterized Makefile target (e.g., \`make upgrade-v0-to-olmv1\`) that:
  1. Detects/removes the existing OLMv0 \`Subscription\` and \`OperatorGroup\` for OADP.
  2. Creates the necessary \`ServiceAccount\` and RBAC (\`ClusterRoleBinding\`) for the OLMv1 installer.
  3. Creates a \`ClusterExtension\` pointing to the desired package/channel/version.
  4. Waits for the \`ClusterExtension\` to reach \`Installed=True\`.
- Reuse existing \`OLMV1_*\` Makefile variables (package, namespace, channel, version, catalog, catalog-image, service-account) introduced in PR `#2160` for consistency.
- Handle \`inline.watchNamespace\` (OLMv1) vs. \`watchNamespace\` env var / \`OperatorGroup\` scope (OLMv0) differences.

## References

- PR `#2160`: https://github.com/openshift/oadp-operator/pull/2160
- Related issue `#2193` (test coverage for OLMv0→OLMv1 migration): https://github.com/openshift/oadp-operator/issues/2193
- OLMv0 install mode in CSV: https://github.com/openshift/oadp-operator/blob/7e53a850ffc68b183e6fd7dd3cc134170b8b7f76/config/manifests/bases/oadp-operator.clusterserviceversion.yaml#L467-L475
- OLMv0 watchNamespace config: https://github.com/openshift/oadp-operator/blob/7e53a850ffc68b183e6fd7dd3cc134170b8b7f76/config/manager/manager.yaml#L63-L66

Requested by \`@kaovilai\` on PR `#2160` comment: https://github.com/openshift/oadp-operator/pull/2160" \
  --assignee kaovilai

Length of output: 55


@kaovilai: Done! Issue created: #2194

"Add Makefile target to upgrade OLMv0 install to OLMv1 install" covers:

  • A new make upgrade-v0-to-olmv1 target that removes the existing OLMv0 Subscription/OperatorGroup, sets up the OLMv1 ServiceAccount/RBAC, creates a ClusterExtension, and waits for Installed=True
  • Reuse of the existing OLMV1_* Makefile variables from PR #2160 for consistency
  • Handling the inline.watchNamespace (OLMv1) vs. watchNamespace env var / OperatorGroup scope (OLMv0) differences

It's assigned to you and backlinked to PR #2160 and related issue #2193.

@weshayutin
Copy link
Copy Markdown
Contributor Author

@kaovilai taking this over :)

@kaovilai kaovilai changed the title dnm: test olmv1 deployment feat: OLMv1 lifecycle — fresh install tests + OLMv0→OLMv1 migration target May 5, 2026
…anifest generation, and implement migration tests

Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
@kaovilai kaovilai marked this pull request as draft May 5, 2026 21:41
@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 May 5, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
Makefile (1)

1131-1132: 💤 Low value

xargs -r is GNU-specific and may fail on macOS.

The -r flag (don't run if stdin is empty) is a GNU extension not available in BSD xargs. On macOS, this will error unless GNU coreutils is installed.

Possible fix using shell conditional
-	-$(OC_CLI) get crd -o name 2>/dev/null | grep -E '\.oadp\.openshift\.io|\.velero\.io' | \
-		xargs -r $(OC_CLI) delete --ignore-not-found=true || true
+	-CRDS=$$($(OC_CLI) get crd -o name 2>/dev/null | grep -E '\.oadp\.openshift\.io|\.velero\.io'); \
+	if [ -n "$$CRDS" ]; then echo "$$CRDS" | xargs $(OC_CLI) delete --ignore-not-found=true; fi || true
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Makefile` around lines 1131 - 1132, The Makefile line uses GNU-only xargs -r
which breaks on macOS; change the command to guard against empty stdin instead
of relying on -r: capture the output of "$(OC_CLI) get crd -o name 2>/dev/null |
grep -E '\.oadp\.openshift\.io|\.velero\.io'" into a variable or test it, and
only pipe to "xargs $(OC_CLI) delete --ignore-not-found=true" when non-empty;
update the invocation that currently contains "xargs -r" and the surrounding
"$(OC_CLI) get crd -o name" pipeline accordingly so the delete step is skipped
on empty input in a portable POSIX-compatible way.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@Makefile`:
- Around line 1131-1132: The Makefile line uses GNU-only xargs -r which breaks
on macOS; change the command to guard against empty stdin instead of relying on
-r: capture the output of "$(OC_CLI) get crd -o name 2>/dev/null | grep -E
'\.oadp\.openshift\.io|\.velero\.io'" into a variable or test it, and only pipe
to "xargs $(OC_CLI) delete --ignore-not-found=true" when non-empty; update the
invocation that currently contains "xargs -r" and the surrounding "$(OC_CLI) get
crd -o name" pipeline accordingly so the delete step is skipped on empty input
in a portable POSIX-compatible way.

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: 9043a314-cd22-4f4c-ab9c-d117aa57e4de

📥 Commits

Reviewing files that changed from the base of the PR and between ac16803 and 565e178.

📒 Files selected for processing (5)
  • Makefile
  • bundle/manifests/oadp-operator.clusterserviceversion.yaml
  • config/manifests/bases/oadp-operator.clusterserviceversion.yaml
  • tests/olmv1/olmv1_migrate_test.go
  • tests/olmv1/olmv1_suite_test.go

kaovilai and others added 2 commits May 7, 2026 10:19
OLMv1 cannot adopt resources created by OLMv0. Add cleanup step that
deletes all olm.managed=true labeled resources (ServiceAccounts, Roles,
RoleBindings, Deployments, ClusterRoles, ClusterRoleBindings) before
ClusterExtension install. Also add CatalogSource image detection to
migrate custom FBC catalogs to ClusterCatalog, and update Makefile
migration target with matching phases.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
The upgrade-v0-to-olmv1 Makefile target was missing the OLMv0 remnant
cleanup step. OLMv1 refuses to install when it finds pre-existing
resources labeled olm.managed=true (ServiceAccounts, Roles, ClusterRoles,
etc). Add Phase 3b to delete these before ClusterExtension creation.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

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

Inline comments:
In `@Makefile`:
- Around line 1141-1142: The Makefile currently runs $(OC_CLI) get crd ... |
xargs ... delete which removes OADP/Velero CRDs cluster-wide and thus destroys
all CR instances; change this to avoid deleting CRDs: either (A) remove the CRD
deletion entirely and only delete CR instances by listing and deleting
namespaced CRs (use $(OC_CLI) get <cr-kind> -n $(TARGET_NAMESPACE) ... and
delete those), or (B) gate the CRD deletion behind an explicit opt-in variable
(e.g. SKIP_CRD_DELETE or CONFIRM_DELETE_CRDS) and only run the existing
$(OC_CLI) delete command when that variable is set; target the unique symbols
$(OC_CLI), get crd, and the xargs ... delete pipeline to implement the safe
alternative.

In `@tests/olmv1/olmv1_migrate_test.go`:
- Around line 118-129: The cleanup currently swallows errors when listing or
deleting CatalogSources (calls using
dynamicClient.Resource(catalogSourceGVR).Namespace("openshift-marketplace").List/Delete
and the loop that uses isDefaultCatalogSource), causing flaky tests; change the
logic to assert on errors instead of ignoring them: check and fail the test
(using gomega/Expect or ginkgo.Fail) if the List returns an error and for each
Delete capture its error and assert it succeeded (or retry/collect and fail
after loop), and include the resource name in failure messages so failures are
deterministic and debuggable.
- Around line 82-85: The Eventually checks call
dynamicClient.Resource(subscriptionGVR).Namespace(namespace).List(...) and
ignore the returned error, which can cause nil derefs; update the lambda used in
gomega.Eventually (the anonymous func passed to gomega.Eventually at both
occurrences) to handle the error from List — if err != nil return a sentinel
value (e.g., -1) or otherwise surface the error so the Eventually assertion
won’t access list.Items on a nil list; replace the unconditional return
len(list.Items) in the lambda with logic that checks err and only returns
len(list.Items) when err == nil.
- Around line 170-183: The current deletion loops iterate all
ClusterRoles/ClusterRoleBindings matched by olmSelector and may remove non-OADP
resources; modify the logic in the blocks using
kubeClient.RbacV1().ClusterRoles().List / ClusterRoleBindings().List (variables
crs and crbs) to only delete items that are known OADP remnants by applying an
additional safety filter (e.g., check cr.Name or crb.Name for OADP-specific
prefixes like "oadp", "velero", or the OADP operator name, or check for a
specific label/annotation that identifies OADP resources such as "app=oadp" or
an OADP owner annotation) and skip/log all others instead of deleting them
unconditionally.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: ec3a3efd-e2fd-4ef1-9512-a5174ce744ab

📥 Commits

Reviewing files that changed from the base of the PR and between 565e178 and 8285756.

📒 Files selected for processing (2)
  • Makefile
  • tests/olmv1/olmv1_migrate_test.go

Comment thread Makefile Outdated
Comment thread tests/olmv1/olmv1_migrate_test.go Outdated
Comment thread tests/olmv1/olmv1_migrate_test.go Outdated
Comment thread tests/olmv1/olmv1_migrate_test.go Outdated
kaovilai and others added 2 commits May 7, 2026 11:16
…ion test

- Fix CatalogSource cleanup to scan both openshift-marketplace and operator
  namespace (CI places CatalogSource in operator namespace via
  optional-operators-subscribe)
- Add OLMv0 CSV version capture before migration and verify same version
  installed after OLMv1 ClusterExtension install
- Verify installed bundle came from expected catalog, not community default
- Pin ClusterExtension to specific ClusterCatalog via selector.matchLabels
- Build fresh operator/bundle/catalog images in upgrade-v0-to-olmv1 to avoid
  expired ttl.sh images
- Add verbose diagnostics for ClusterCatalog failures (image ref, catalogd logs)
- Append test-upgrade-v0-to-olmv1 to test-e2e target for Prow presubmit
- Add usage comments for local and CI/Prow workflows

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
@kaovilai

This comment has been minimized.

@kaovilai

This comment has been minimized.

@kaovilai
Copy link
Copy Markdown
Member

kaovilai commented May 7, 2026

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 7, 2026

✅ Actions performed

Full review triggered.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
tests/olmv1/olmv1_migrate_test.go (1)

187-214: 💤 Low value

List errors in cleanup are silently ignored.

All List calls for namespace-scoped cleanup (ServiceAccounts, Roles, RoleBindings, Deployments) ignore errors. If listing fails, cleanup silently skips those resources, potentially leaving orphaned OLMv0 remnants and causing flaky migration tests.

Consider at minimum logging the errors:

Suggested improvement
-		sas, _ := kubeClient.CoreV1().ServiceAccounts(namespace).List(ctx, olmSelector)
+		sas, err := kubeClient.CoreV1().ServiceAccounts(namespace).List(ctx, olmSelector)
+		if err != nil {
+			log.Printf("Warning: failed to list ServiceAccounts: %v", err)
+		}
 		if sas != nil {

Apply similar pattern to Roles, RoleBindings, and Deployments list calls.

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

In `@tests/olmv1/olmv1_migrate_test.go` around lines 187 - 214, The List calls for
namespace cleanup (kubeClient.CoreV1().ServiceAccounts(...).List,
kubeClient.RbacV1().Roles(...).List, kubeClient.RbacV1().RoleBindings(...).List,
kubeClient.AppsV1().Deployments(...).List) are ignoring returned errors; capture
each error (e.g., sasErr, rolesErr, rbsErr, deployErr) and if non-nil log it
(log.Printf or t.Errorf) so failures are visible during tests, and decide
whether to continue cleanup or fail the test based on the error; apply this
pattern to ServiceAccounts, Roles, RoleBindings and Deployments List calls.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Makefile`:
- Around line 1164-1166: The Makefile emits a scalar `channel:` but the
ClusterExtension API expects `spec.source.catalog.channels` to be an array;
update the generation logic that references OLMV1_CHANNEL and writes to
OLMV1_MANIFEST to output a YAML array field `channels:` with the channel value
inside (e.g., channels: [ '$(OLMV1_CHANNEL)' ]) instead of `channel:` so the
manifest matches the Go tests and schema.
- Around line 1002-1020: The recipe currently reads EXIT_CODE from
/tmp/oadp-e2e-exit-code in a new shell, causing a lost/zeroed exit when the
earlier ginkgo block sets EXIT_CODE; instead ensure the exit-code write/read
happen in the same recipe shell by moving the read/exit logic into the same
shell block that assigns EXIT_CODE (or by chaining commands with backslashes so
they run in one shell), or alternatively export and use the variable before Make
starts a new shell; specifically update the Makefile recipe so that the value
written to /tmp/oadp-e2e-exit-code (EXIT_CODE) and the final rm -f
/tmp/oadp-e2e-exit-code; exit $$E2E_EXIT logic execute in the same shell that
runs the ginkgo block and the call to test-upgrade-v0-to-olmv1, ensuring
EXIT_CODE is preserved for the final exit.

---

Nitpick comments:
In `@tests/olmv1/olmv1_migrate_test.go`:
- Around line 187-214: The List calls for namespace cleanup
(kubeClient.CoreV1().ServiceAccounts(...).List,
kubeClient.RbacV1().Roles(...).List, kubeClient.RbacV1().RoleBindings(...).List,
kubeClient.AppsV1().Deployments(...).List) are ignoring returned errors; capture
each error (e.g., sasErr, rolesErr, rbsErr, deployErr) and if non-nil log it
(log.Printf or t.Errorf) so failures are visible during tests, and decide
whether to continue cleanup or fail the test based on the error; apply this
pattern to ServiceAccounts, Roles, RoleBindings and Deployments List calls.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: 929f30dd-b0f5-4f8a-911d-248df73e1d7b

📥 Commits

Reviewing files that changed from the base of the PR and between 7e53a85 and 9de0e76.

📒 Files selected for processing (9)
  • .gitignore
  • .golangci.yaml
  • Makefile
  • bundle/manifests/oadp-operator.clusterserviceversion.yaml
  • config/manifests/bases/oadp-operator.clusterserviceversion.yaml
  • tests/olmv1/.gitignore
  • tests/olmv1/olmv1_install_test.go
  • tests/olmv1/olmv1_migrate_test.go
  • tests/olmv1/olmv1_suite_test.go

Comment thread Makefile
Comment thread Makefile
…or catalog target

- Fix generate-olmv1-manifest: channel (singular) → channels (array) per
  ClusterExtension API schema
- Scope olm.managed=true cluster-wide RBAC cleanup to OADP-related resources
  only, avoiding deletion of other operators' resources in shared clusters
- Replace Update with MergePatch for ClusterExtension upgrade to avoid 409
  Conflict races with the controller
- Validate existing ClusterCatalog image on AlreadyExists instead of silently
  returning
- Add deploy-olmv1-mirror-catalog target for testing with productized index
  images when current OCP version lacks redhat-oadp-operator (e.g., 4.22)

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
@kaovilai
Copy link
Copy Markdown
Member

kaovilai commented May 7, 2026

/test all

@kaovilai
Copy link
Copy Markdown
Member

kaovilai commented May 7, 2026

"flake" fix #2198

/retest

@openshift-ci
Copy link
Copy Markdown

openshift-ci Bot commented May 8, 2026

@weshayutin: all tests passed!

Full PR test history. Your PR dashboard.

Details

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

@kaovilai kaovilai marked this pull request as ready for review May 8, 2026 19:31
Copilot AI review requested due to automatic review settings May 8, 2026 19:31
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds OLMv1 (ClusterExtension/ClusterCatalog) lifecycle coverage and migration tooling so OADP can be installed fresh via OLMv1 and migrated from an existing OLMv0 (Subscription/CSV) install, with CI-friendly Makefile targets and Ginkgo suites.

Changes:

  • Introduces new Ginkgo suites under tests/olmv1/ for fresh OLMv1 install/upgrade and OLMv0→OLMv1 migration verification.
  • Extends Makefile with test-olmv1, test-upgrade-v0-to-olmv1, upgrade-v0-to-olmv1, and manifest-generation targets; appends migration test execution after test-e2e.
  • Enables SingleNamespace install mode in both generated and base CSV manifests.

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
Makefile Adds OLMv1 test/migration targets, manifest generation, and runs migration test after test-e2e.
tests/olmv1/olmv1_suite_test.go New shared helpers for OLMv1 tests (ClusterExtension/ClusterCatalog operations, CRD cleanup, condition logging).
tests/olmv1/olmv1_install_test.go New fresh-install/upgrade validation suite for OLMv1.
tests/olmv1/olmv1_migrate_test.go New OLMv0→OLMv1 migration suite with version/catal og validation and cleanup steps.
tests/olmv1/.gitignore Ignores test temp output directory.
config/manifests/bases/oadp-operator.clusterserviceversion.yaml Enables SingleNamespace install mode in base CSV.
bundle/manifests/oadp-operator.clusterserviceversion.yaml Enables SingleNamespace install mode in bundle CSV.
.golangci.yaml Excludes tests/olmv1 from golangci-lint.
.gitignore Ignores generated oadp-olmv1-manifest.yaml.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/olmv1/olmv1_suite_test.go
Comment thread tests/olmv1/olmv1_install_test.go
Comment thread tests/olmv1/olmv1_install_test.go
Comment thread tests/olmv1/olmv1_migrate_test.go
Comment thread tests/olmv1/olmv1_migrate_test.go
Comment thread tests/olmv1/olmv1_migrate_test.go
Comment thread tests/olmv1/olmv1_migrate_test.go
Comment thread Makefile
Comment thread Makefile
Comment thread Makefile Outdated
Comment thread tests/olmv1/olmv1_migrate_test.go Outdated
Comment thread tests/olmv1/olmv1_suite_test.go
Comment thread tests/olmv1/olmv1_suite_test.go
Comment thread tests/olmv1/olmv1_migrate_test.go Outdated
Comment thread tests/olmv1/olmv1_install_test.go
@kaovilai
Copy link
Copy Markdown
Member

Thank you for you reviews!

@kaovilai
Copy link
Copy Markdown
Member

/hold
need to migrate e2e in prow to use FBC to be compatible with OLMv1

kaovilai and others added 7 commits May 11, 2026 17:16
xargs -r (--no-run-if-empty) is a GNU coreutils extension not available
on macOS BSD xargs. Use shell variable + conditional instead.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
The Eventually closures for Subscription and CSV deletion verification
ignored List errors. If List fails (transient API error), the nil list
causes a panic on list.Items access. Use gomega.Gomega parameter to
properly assert both error and emptiness.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
Cleanup List calls for ServiceAccounts, Roles, RoleBindings, Deployments,
ClusterRoles, and ClusterRoleBindings were silently discarding errors.
Now log warnings on failure and skip iteration to prevent nil panics.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
When ensureClusterCatalog finds an AlreadyExists catalog with a matching
image, it returned without setting createdCatalog=true. This caused
AfterAll to skip cleanup, leaving the catalog on the cluster after
repeated test runs.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
CRD deletion in Kubernetes is asynchronous — finalizers run and existing
CRs get garbage collected. If the install test creates a ClusterExtension
before old CRDs are fully gone, OLMv1 may hit ownership conflicts.
Now polls until each deleted CRD is confirmed gone.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
Both install and migration tests failed with AlreadyExists when a
previous run left a ClusterExtension behind. Now delete any existing
CE before creating.

Also remove hardcoded clusterExtensionName const in favor of the
configurable packageName flag, aligning CE name with test-olmv1-cleanup
target which deletes $(OLMV1_PACKAGE).

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
…cted

buildClusterExtension only set the catalog selector when the global
catalogImage flag was non-empty. In migration, the catalog image is
auto-detected from the Subscription (migratedCatalogImage) while
catalogImage stays empty, so the selector was never set and OLMv1
could pick a wrong default/community catalog.

Add withCatalogSelector option function so the migration test can
explicitly pin to the created ClusterCatalog.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
@kaovilai
Copy link
Copy Markdown
Member

Please check/approve openshift/release#79152 to unblock testing here

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

Labels

do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Makefile target to upgrade OLMv0 install to OLMv1 install Test OLMv0 to OLMv1 upgrade path/migration

4 participants