diff --git a/specs/20260821-migration-v0-to-v1/e2e.md b/specs/20260821-migration-v0-to-v1/e2e.md index 8d5f80c..6dbcdca 100644 --- a/specs/20260821-migration-v0-to-v1/e2e.md +++ b/specs/20260821-migration-v0-to-v1/e2e.md @@ -72,6 +72,9 @@ public mutable catalog. | Validation IDs | Scenario | Required assertions | |---|---|---| | V1.1, V1.2, V1.3, V3.1–V3.7 | Baseline fixture migration | `check`, dry-run, COS `Succeeded=True` before CE creation, CE `Installed=True`, field mappings, CE backups/audit, Sub/CSV cleanup. | +| V4.7 | Cross-namespace fixture migration | Target namespace is created with copied PSA/SCC labels; source Deployments are scaled to zero before target creation; CE and rendered Deployment use the target; collected source Deployment is removed while the source namespace remains. | +| V4.7 | Acknowledged live namespace deletion | A real OLMv0 installation is converted with `--acknowledge-namespace-delete`; after CE installation in the target namespace, OLMv0 finalizes the CSV and the source namespace is deleted. | +| V4.8 | System-managed namespace (requirement gap) | Deferred until a supported controller can accept an omitted CE namespace. Verify the explicit opt-in omits `spec.namespace` and uses the bundle-metadata namespace; verify unsupported controllers reject it before mutation. | | V1.4, V3.18 | Rollback | Refusal without acknowledgment for installed CE; CE/COS deletion and Subscription restoration with acknowledgment; on-disk backup files exist before deletion. | | V1.5, V4.1 | Conflict cleanup | CE stays; Subscription and OLMv0 artifacts are removed; shared OperatorGroup is retained. | | V1.6–V1.8, V2.10 | Batch and argument behavior | Four-section ordering; only Eligible converts; stop/continue behavior; a Subscription named `check` works. | @@ -79,7 +82,6 @@ public mutable catalog. | V3.8–V3.11, V3.13–V3.17, V3.19 | Catalog migration | image, poll interval, priority, unsupported source, dedup/adoption, overflow, and deletion-reference behavior. | | V3.12, V4.2, V4.6 | Collection and adoption | Deployment config survives an OLMv1 upgrade, shared CRD adoption succeeds, and large payload uses Secrets. | | V5.1–V5.9 | Real-operator smoke | Bootstrap, install a pinned AllNamespaces operator, catalog migration, conversion, upgrade, rollback, and four-state batch scan. | -| V4.7 | Namespace change | Deferred: Phase 6 is blocked. Add only when its upstream prerequisite lands. | ## Test implementation and coverage @@ -152,6 +154,7 @@ controllers. It replays the committed OLMv0 snapshots. ```bash make migration/e2e-fixture-setup make migration/test-e2e-fixture-matrix +make migration/test-e2e-cross-namespace E2E_CLUSTER_NAME=library-olm-fixture-e2e make migration/e2e-teardown ``` diff --git a/specs/20260821-migration-v0-to-v1/plan.md b/specs/20260821-migration-v0-to-v1/plan.md index 54a1e2a..deb4baa 100644 --- a/specs/20260821-migration-v0-to-v1/plan.md +++ b/specs/20260821-migration-v0-to-v1/plan.md @@ -123,18 +123,25 @@ flag is set; CE carries the matching annotation. **Depends on:** Phase 1. **Exit:** N CatalogSources → N serving ClusterCatalogs; operator scan then reports catalog-available. -## Phase 6 — Install-namespace change ⚠️ blocked — [OPRUN-4721](https://redhat.atlassian.net/browse/OPRUN-4721) -**Goal:** Support `--install-namespace` differing from the Subscription namespace (R6, R9). -- **Blocked on** [OCPSTRAT-2690](https://redhat.atlassian.net/browse/OCPSTRAT-2690) / - [OPRUN-4505](https://redhat.atlassian.net/browse/OPRUN-4505) / - [PR #2825](https://github.com/operator-framework/operator-controller/pull/2825) (making - `spec.namespace` optional / COS-managed). Once it lands, the tool may omit `spec.namespace`. -- Move namespace-scoped resources to the new namespace; copy PSA (`pod-security.kubernetes.io/*`) - and `security.openshift.io/scc.podSecurityLabelSync` labels; delete the old namespace only with - `--acknowledge-namespace-delete`. - -**Depends on:** Phases 1, 3 + PR #2825. **Exit:** resources land in the new namespace with PSA/SCC -labels copied; old namespace deleted only when acknowledged. +## Phase 6 — Install-namespace change 🚧 in progress — [OPRUN-4721](https://redhat.atlassian.net/browse/OPRUN-4721) +**Goal:** Support `--install-namespace` differing from the Subscription namespace (R6, R9), then +an explicitly selected OLMv1 system-managed namespace mode when its controller API is released. +- Create or update the target namespace before removing OLMv0 management, copying PSA + (`pod-security.kubernetes.io/*`) and `security.openshift.io/scc.podSecurityLabelSync` labels. +- Move collected namespace-scoped resources to the target namespace in the migration COS and, + after the target CE is installed, remove their source copies. +- Delete the source namespace only with `--acknowledge-namespace-delete`; retain it by default. +- **Remaining requirement gap:** introduce an explicit + `--system-managed-install-namespace` mode after operator-controller ships a supported API for + an omitted `spec.namespace`. It must capability-gate the mode, omit the field, and let OLMv1 + resolve the namespace from bundle metadata. It must reject unsupported controllers (including + released versions that require the field), not silently fall back to another namespace. Add a + dedicated E2E scenario before declaring this mode complete. + +**Depends on:** Phases 1 and 3. **Exit:** resources land in the new namespace with PSA/SCC +labels copied; old namespace deleted only when acknowledged. The system-managed mode is complete +only when its supported controller prerequisite, capability rejection, and dedicated E2E scenario +are in place. ## Phase 7 — OLMv1 APIService renderer support *(cross-repo, operator-controller)* — [OPRUN-4723](https://redhat.atlassian.net/browse/OPRUN-4723) **Goal:** Add `apiregistration.k8s.io` support to the OLMv1 registry+v1 bundle renderer as @@ -173,7 +180,7 @@ E2E scenarios in VALIDATION pass in CI. Prerequisite (OPRUN-4716, operator-controller) ──┐ (parallel; needed before Phase 8) ▼ Phase 1 (4717) ──► Phase 2 (4718) ──► Phase 3 (4719) ──► Phase 4 (4720) ──► Phase 8 - │ └─────────────────────────────────► Phase 6 (4721) BLOCKED + │ └─────────────────────────────────► Phase 6 (4721) └──► Phase 5 (4722, parallel) ──────────────────────────────────────────► Phase 8 Phase 7 (4723, operator-controller, parallel) ──► removes C3 from Phase 3 (operators with APIService definitions become Eligible) diff --git a/specs/20260821-migration-v0-to-v1/requirements.md b/specs/20260821-migration-v0-to-v1/requirements.md index 982c983..058231b 100644 --- a/specs/20260821-migration-v0-to-v1/requirements.md +++ b/specs/20260821-migration-v0-to-v1/requirements.md @@ -38,13 +38,24 @@ is never ambiguous. Flags: `-n/--namespace`, `--all`, `--dry-run` (on `convert`), `--backup ` (on `convert`; writes OLM-related objects to disk before deletions — see R2.6), `--delete-operatorgroup` (on `convert`; deletes the OperatorGroup when no Subscriptions -remain — both conditions required), `--continue-on-error` (on `convert --all`), +remain — both conditions required), `--install-namespace` (on single-operator `convert`; +defaults to the Subscription namespace), `--acknowledge-namespace-delete` (on a +cross-namespace conversion; permits deletion of the source namespace only after a successful +migration), `--continue-on-error` (on `convert --all`), `--acknowledge-installed` (on `rollback`), and the eligibility-override flags (R3): `--acknowledge-watch-scope-change`, `--acknowledge-operator-condition`, `--acknowledge-olmv0-api-access`, `--acknowledge-scoped-serviceaccount`, `--acknowledge-not-steady-state`. `check`/`convert` target a `Subscription` (name + `-n` namespace); `rollback`/`cleanup` target the resulting `ClusterExtension`. +**Requirement gap — OLMv1 system-managed namespace:** add an explicit +`--system-managed-install-namespace` conversion mode once a released, supported +operator-controller API permits omitting `ClusterExtension.spec.namespace`. That mode must omit +the field and let OLMv1 resolve the namespace from bundle metadata. It must be capability-gated +and rejected with an actionable error on controllers that require `spec.namespace`; omitting +`--install-namespace` must continue to mean the Subscription namespace and must never silently +select the system-managed mode. + For `migrate-catalogs-v0-to-v1`: `--delete-catalogsource` deletes the source `CatalogSource` after creating the `ClusterCatalog`, but only when no `Subscription` references it — both conditions required. Default: leave the `CatalogSource` in place. @@ -218,7 +229,7 @@ Subscription + OperatorGroup inputs above. |---|---|---| | `metadata.name` | Subscription name (default; `--ce-name` override) | | | `metadata.annotations` | migration metadata | See R2.5 (`migrated-from-subscription`, `migration-subscription-backup`, `acknowledged-*`). | -| `spec.namespace` | Subscription namespace (default) or `--install-namespace` | Required, immutable today. **Phase 6 / [PR #2825](https://github.com/operator-framework/operator-controller/pull/2825):** may become optional/omitted → OLMv1 resolves it from bundle metadata. | +| `spec.namespace` | Subscription namespace (default) or `--install-namespace` | Required and immutable in released operator-controller versions. For a different `--install-namespace`, migration creates or updates the target namespace, copies PSA and SCC-sync labels, and rewrites collected namespaced resources to the target. An existing target must explicitly declare an equal or less restrictive PSA `enforce` level when the source declares one; migration fails closed rather than infer an unknown cluster PSA default. **Gap:** a future, explicit `--system-managed-install-namespace` mode must omit this field only when the installed controller supports its experimental optional-namespace API; it must use bundle metadata rather than fall back on an unsupported controller. | | `spec.serviceAccount` | **do not set** | Deprecated and **ignored** in current OLMv1 (operator-controller uses its own cluster-admin SA). The RFC/prototype `-installer` SA concept is obsolete — do not create or set it. | | `spec.source.sourceType` | constant `Catalog` | Only implemented source type. | | `spec.source.catalog.packageName` | Subscription `spec.name` | Required, immutable. | @@ -278,7 +289,12 @@ Both conditions must be met. - **OperatorCondition detection** → OLMv0 stamps OperatorCondition RBAC onto **every** operator's service account, so RBAC is **not** a usage signal. Usage is detected **only** via `OperatorCondition.status.conditions` (C4); C5 explicitly excludes `operatorconditions` from the OLMv0-API RBAC check. - **Certificate handling** → OLMv0 manages TLS certs directly; OLMv1 delegates to cert-manager (upstream) / service-ca (downstream). Expect pod restarts across the pivot; document as known behavior. - **Large bundles** → SecretPacker (R2.4) avoids Kubernetes object-size limits. -- **Namespace change** → copy PSA labels (`pod-security.kubernetes.io/*`) and the OpenShift SCC sync label (`security.openshift.io/scc.podSecurityLabelSync`) from the old namespace to the new one. Delete the old namespace **only** with `--acknowledge-namespace-delete` (it may contain non-operator resources). +- **Namespace change** → copy PSA labels (`pod-security.kubernetes.io/*`) and the OpenShift SCC sync label (`security.openshift.io/scc.podSecurityLabelSync`) from the old namespace to the new one. An existing target with an unknown PSA default is rejected when the source declares `enforce`; do not weaken an unobservable cluster default. Before creating the target CE, scale collected source Deployments to zero so controllers cannot overlap with independent leader-election Leases. Restore their original replica counts only when target COS creation failed before it could reconcile; if the target may be active, retain the source at zero, do not automatically restore OLMv0 management, and report the state for recovery. After the target CE is installed, delete the collected source-namespace operator resources. Delete the old namespace **only** with `--acknowledge-namespace-delete` (it may contain non-operator resources). +- **OLMv1 system-managed namespace (gap)** → support only through an explicit opt-in and a + controller capability check. The CE must omit `spec.namespace`, and OLMv1 must choose the + bundle-metadata namespace; migration must not infer one or change the default source-namespace + behavior. Define its resource and source-cleanup semantics with its implementation and validate + them against a controller release that supports the optional field. - **Disconnected / mirrored** → catalogs must be migrated first; the operator tool never auto-creates catalogs. --- diff --git a/specs/20260821-migration-v0-to-v1/validation.md b/specs/20260821-migration-v0-to-v1/validation.md index ea80bbd..31a36a2 100644 --- a/specs/20260821-migration-v0-to-v1/validation.md +++ b/specs/20260821-migration-v0-to-v1/validation.md @@ -65,7 +65,12 @@ flag flips it to `Eligible`: - **V4.4** Dependency operator (`olm.generated-by` present / declares requirements) → flagged; an operator others depend on migrates but emits a dependents warning. - **V4.5** OperatorCondition disambiguation: an operator with OLMv0-stamped OperatorCondition RBAC but **empty** `status.conditions` is **Eligible** (RBAC is not treated as usage). - **V4.6** Large bundle exceeding inline size limits migrates successfully via SecretPacker. -- **V4.7** Namespace change copies `pod-security.kubernetes.io/*` and `security.openshift.io/scc.podSecurityLabelSync` to the new namespace; old namespace deleted only with `--acknowledge-namespace-delete`. +- **V4.7** Namespace change copies `pod-security.kubernetes.io/*` and `security.openshift.io/scc.podSecurityLabelSync` to the new namespace. An existing target with no explicit PSA `enforce` label is rejected when the source sets one, because its cluster default is not observable. Collected source Deployments scale to zero before target creation so two controllers do not overlap. They return to their original replica count only when target COS creation failed before it may have reconciled; otherwise migration reports that the target may be active, leaves the source scaled down, and refuses automatic OLMv0 recovery. The target operator resources are present and their collected source copies are removed. The fixture scenario retains the old namespace by default; the live scenario passes `--acknowledge-namespace-delete` and verifies the source namespace is deleted after OLMv0 finalizes its CSV. +- **V4.8** System-managed namespace (requirement gap): against a controller release that supports + an omitted `ClusterExtension.spec.namespace`, explicit system-managed conversion omits the + field and OLMv1 installs into the namespace resolved from bundle metadata. The same invocation + against a controller that requires the field is rejected before mutation with an actionable + error. A conversion with neither namespace flag continues to use the Subscription namespace. ## V5. End-to-end scenario (kind) @@ -118,8 +123,8 @@ flag flips it to `Eligible`: | R3 C1–C9 | V2.1–V2.10 | | R4 Subscription fields | V3.1–V3.3, V3.12, V4.4 | | R5 Resource collection strategy | V1.3, V4.2, V4.6 | -| R6 OperatorGroup fields | V2.1, V2.7, V3.5, V3.7 | -| R7 ClusterExtension mapping | V3.1–V3.6, V3.12 | +| R6 OperatorGroup fields | V2.1, V2.7, V3.5, V3.7, V4.7 | +| R7 ClusterExtension mapping | V3.1–V3.6, V3.12, V4.8 | | R8 CatalogSource→ClusterCatalog | V3.8–V3.11, V3.13–V3.17, V3.19 | -| R9 Edge cases | V4.1–V4.7 | +| R9 Edge cases | V4.1–V4.8 | | R10 Non-goals | V6.4, V6.5 |