Add migration/pkg/migration core library (Phases 1–5) - #14
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
b4fda3c to
27f0887
Compare
27f0887 to
68208c2
Compare
68208c2 to
832b418
Compare
Implements the OLMv0→OLMv1 migration library as specified in
specs/20260821-migration-v0-to-v1/requirements.md, porting and adapting
the perdasilva/operator-controller prototype onto current OLMv1 APIs.
Package layout:
migration/pkg/migration/
labels.go — annotation and label constants (R2.5)
types.go — OperatorStatus (4-state), Options, MigrationInfo,
Backup.SaveToDisk (R1.3, R2.6)
checks.go — CheckResult, PreMigrationReport
readiness.go — C8 (Subscription + CSV state), C9 (olm.generated-by)
compatibility.go — C1–C6 checks; C1/C4/C5/C6/C8 soft with acknowledge
flags; C2/C9 hard blocks; C3 removed (OPRUN-4723)
scan.go — ScanAll, Check, Gather, Rollback, Cleanup (R1.1);
4-state classification; C7 catalog check; dependent-
operator warning (R9)
catalog.go — ResolveClusterCatalog; defaultChannel from FBC (R4);
PackageNotFoundError
collector.go — 5-source resource collection (R5): Operator CR refs,
CRD labels, olm.owner label, ownerRefs, InstallPlan
steps; dedup by Group/Kind/namespace/name
phase.go — PhaseSort: groups objects into ordered phases
secretpacker.go — Secret-backed COS objects (R2.4): gzip, 900 KiB
batching, content-addressed keys
migration.go — Migrate (full flow), Rollback, CleanupOLMv0Resources
Key design points:
- ClusterObjectSet (not ClusterExtensionRevision) throughout (R2.2)
- CollisionProtection: IfNoController on all COS objects (R2.4)
- CE spec.serviceAccount never set — deprecated in OLMv1 (R2.5/R7)
- All migration annotations on COS and CE (R2.5)
- Default channel resolved from ClusterCatalog FBC when Subscription
has no spec.channel (R4)
- spec.config mapped to CE.spec.config.inline.deploymentConfig (R4/R7)
- kubeconfig via standard clientcmd chain — HCP-compatible (R10)
Also adds/replaces:
go.mod / go.sum — real module dependencies
Makefile — real targets wired to bingo-managed golangci-lint
and go-apidiff
.bingo/ — bingo tool pins (golangci-lint v2.8.0, go-apidiff v0.8.3)
.golangci.yaml — lint config
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Todd Short <tshort@redhat.com>
832b418 to
78c03ae
Compare
| } | ||
|
|
||
| switch meta.Schema { | ||
| case "olm.package": |
There was a problem hiding this comment.
should we care about moving these strings to constants?
|
|
||
| // possibleResourceGVKs lists all resource GVKs that may be part of an OLMv0 operator installation. | ||
| var possibleResourceGVKs = []schema.GroupVersionKind{ | ||
| {Group: "", Version: "v1", Kind: "Namespace"}, |
There was a problem hiding this comment.
Namespace might not be needed here as v0 doesn't manage namespaces
|
|
||
| // clusterScopedKinds is the set of kinds that are cluster-scoped (no namespace in lookups). | ||
| var clusterScopedKinds = map[string]bool{ | ||
| "Namespace": true, |
| } | ||
|
|
||
| // olmv0OnlyKinds are OLMv0 management resources that should not be included in the COS. | ||
| var olmv0OnlyKinds = map[string]bool{ |
There was a problem hiding this comment.
Dunno if we want to include ClusterServiceVersion, InstallPlan, and Subscription here?
| } | ||
| } else if sub.Status.Install != nil { | ||
| // Fallback to the deprecated status.install field (R4). | ||
| ipName = sub.Status.Install.Name |
There was a problem hiding this comment.
probably being overzealous here but maybe we don't want to rely on a deprecated status field?
| // Fallback to the deprecated status.install field (R4). | ||
| ipName = sub.Status.Install.Name | ||
| } | ||
| if ipName != "" { |
There was a problem hiding this comment.
Should we bail if the install plan is not set on the subscription status?
| seen := make(map[string]bool) | ||
| var collected []unstructured.Unstructured | ||
|
|
||
| addIfNew := func(obj unstructured.Unstructured) { |
There was a problem hiding this comment.
is it worth just making collected a map then?
| return crdList.Items, nil | ||
| } | ||
|
|
||
| func (m *Migrator) gatherResourcesByOwnerLabel(ctx context.Context, csvName string) []unstructured.Unstructured { |
There was a problem hiding this comment.
| func (m *Migrator) gatherResourcesByOwnerLabel(ctx context.Context, csvName string) []unstructured.Unstructured { | |
| func (m *Migrator) gatherResourcesByOwnerLabel(ctx context.Context, ownerName string) []unstructured.Unstructured { |
| return result | ||
| } | ||
|
|
||
| func (m *Migrator) gatherResourcesByOwnerRef(ctx context.Context, namespace string, csv *operatorsv1alpha1.ClusterServiceVersion) []unstructured.Unstructured { |
There was a problem hiding this comment.
| func (m *Migrator) gatherResourcesByOwnerRef(ctx context.Context, namespace string, csv *operatorsv1alpha1.ClusterServiceVersion) []unstructured.Unstructured { | |
| func (m *Migrator) gatherResourcesByOwnerRef(ctx context.Context, namespace string, ownerName string) []unstructured.Unstructured { |
|
|
||
| for _, obj := range list.Items { | ||
| for _, ref := range obj.GetOwnerReferences() { | ||
| if ref.Kind == "ClusterServiceVersion" && ref.Name == csv.Name { |
There was a problem hiding this comment.
| if ref.Kind == "ClusterServiceVersion" && ref.Name == csv.Name { | |
| if ref.Kind == "ClusterServiceVersion" && ref.Name == ownerName { |
| return nil, nil | ||
| } | ||
|
|
||
| skipKinds := map[string]bool{ |
There was a problem hiding this comment.
should this be a map? should we move this list as top level unexported var and use it also in gatherResourcesFromInstallPlan - or move the skip check to a function or something?
| // Dependency checks (C2 — hard block) | ||
| report.Checks = append(report.Checks, checkNoDependencies(bundleProperties)...) | ||
|
|
||
| // C3 (APIService definitions) was removed: OLMv1 now manages APIService objects |
There was a problem hiding this comment.
this probably needs to be updated now =/
| // spec.serviceAccountName (C6 — soft) | ||
| if og.Spec.ServiceAccountName != "" { | ||
| if opts.AcknowledgeScopedServiceAccount { | ||
| checks = append(checks, CheckResult{ |
There was a problem hiding this comment.
it could we worth creating builder functions for these CheckResults - but I'm fine either way
| OwnerName: opts.ClusterExtensionName, | ||
| SystemNamespace: systemNS, | ||
| } | ||
| packed, err := packer.pack(phases) |
There was a problem hiding this comment.
it would be cool to make this an exported function in some package somewhere in library-olm - and also to be able to configure it to only pack resources in Secrets if necessary, otherwise use the inline option...
|
|
||
| // WaitForClusterExtensionInstalled waits for the CE to reach Installed=True. | ||
| func (m *Migrator) WaitForClusterExtensionInstalled(ctx context.Context, ceName string) error { | ||
| return wait.PollUntilContextTimeout(ctx, 5*time.Second, 5*time.Minute, true, func(ctx context.Context) (bool, error) { |
There was a problem hiding this comment.
should we move the timeout and poll period to constants somewhere?
|
|
||
| deleted := 0 | ||
| for i := range csvList.Items { | ||
| if err := m.Client.Delete(ctx, &csvList.Items[i], client.PropagationPolicy(metav1.DeletePropagationOrphan)); err != nil { |
There was a problem hiding this comment.
I wonder if the olmv0 controller cleans up the copied csvs on deletion - it might be worth a check
| } | ||
|
|
||
| // splitNamespacedName splits "namespace/name" into its components. | ||
| func splitNamespacedName(ref string) (string, string, error) { |
perdasilva
left a comment
There was a problem hiding this comment.
a few nits - nothing that I would block merging on if they are addressed in a follow up
|
/lgtm |
Summary
Part 4/6 in the OLMv0→OLMv1 migration library stack (OPRUN-4717).
Implements the core migration library, porting and adapting the
perdasilva/operator-controller prototype
onto current OLMv1 APIs with full R1–R9 requirements coverage per
specs/20260821-migration-v0-to-v1/requirements.md.Also replaces the stub
Makefileandgo.mod(from PR #13) with the real versions wired to the bingo tools from PR #12.Package:
migration/pkg/migration/types.goOperatorStatus(4-state enum),Options(all flags + acknowledge overrides),MigrationInfo,Backup.SaveToDiskchecks.goCheckResult,PreMigrationReportreadiness.goolm.generated-byhard block)compatibility.goAcknowledge*flags; C2/C9 hard; C3 removed (APIService renderer landed in operator-controller PR #2885)scan.goScanAll,Check,Gather,Rollback,Cleanup(canonical R1.1 API); 4-state classification; C7 catalog check; dependent-operator warning (R9)catalog.goResolveClusterCatalog;defaultChannelresolution from FBC (R4);PackageNotFoundErrorcollector.goolm.ownerlabel, ownerRefs, InstallPlan steps; dedup by Group/Kind/ns/namephase.goPhaseSort— groups objects into ordered phases (namespaces→crds→rbac→deploy→publish)secretpacker.gomigration.goMigrate(full flow),Rollback,CleanupOLMv0Resources; cert-pivot warning (R9)Key design decisions
ClusterObjectSet(notClusterExtensionRevision) throughout (R2.2)CollisionProtection: IfNoControlleron all COS objects — enables CRD adoption (R2.4)CE spec.serviceAccountnever set — deprecated in OLMv1 (R2.5/R7)spec.config→CE.spec.config.inline.deploymentConfig(R4/R7)clientcmdkubeconfig chain — HCP-compatible (R10)Reviewer Checklist