diff --git a/apiextensions/storageversion/migrator.go b/apiextensions/storageversion/migrator.go index 7ac1cc9326..469031251e 100644 --- a/apiextensions/storageversion/migrator.go +++ b/apiextensions/storageversion/migrator.go @@ -68,6 +68,11 @@ func (m *Migrator) Migrate(ctx context.Context, gr schema.GroupResource) error { return fmt.Errorf("unable to determine storage version for %s", gr) } + // don't migrate storage version if CRD has a single valid storage in its status + if len(crd.Status.StoredVersions) == 1 && crd.Status.StoredVersions[0] == version { + return nil + } + if err := m.migrateResources(ctx, gr.WithVersion(version)); err != nil { return err } diff --git a/apiextensions/storageversion/migrator_test.go b/apiextensions/storageversion/migrator_test.go index 8129d456c4..a72c079d0f 100644 --- a/apiextensions/storageversion/migrator_test.go +++ b/apiextensions/storageversion/migrator_test.go @@ -63,6 +63,21 @@ var ( }, }, } + + singleVersionFakeCRD = &apix.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: fakeGR.String(), + }, + Spec: apix.CustomResourceDefinitionSpec{ + Group: fakeGK.Group, + Versions: []apix.CustomResourceDefinitionVersion{ + {Name: "v1", Served: true, Storage: true}, + }, + }, + Status: apix.CustomResourceDefinitionStatus{ + StoredVersions: []string{"v1"}, + }, + } ) func TestMigrate(t *testing.T) { @@ -88,6 +103,22 @@ func TestMigrate(t *testing.T) { ) } +func TestMigrate_SingleStoredVersion(t *testing.T) { + // setup + dclient := dynamicFake.NewSimpleDynamicClient(runtime.NewScheme()) + cclient := apixFake.NewSimpleClientset(singleVersionFakeCRD) + m := NewMigrator(dclient, cclient) + + if err := m.Migrate(context.Background(), fakeGR); err != nil { + t.Fatal("Migrate() =", err) + } + + assertPatches(t, cclient.Actions(), + // patch resource definition dropping non-storage version + crdStorageVersionPatch(singleVersionFakeCRD.Name, "v1"), + ) +} + // func TestMigrate_Paging(t *testing.T) { // t.Skip("client-go lacks testing pagination " + // "since list options aren't captured in actions")