diff --git a/test/integration/etcd/data.go b/test/integration/etcd/data.go index 9287620176e..9b1813bd660 100644 --- a/test/integration/etcd/data.go +++ b/test/integration/etcd/data.go @@ -767,3 +767,7 @@ func gvr(g, v, r string) schema.GroupVersionResource { func gvkP(g, v, k string) *schema.GroupVersionKind { return &schema.GroupVersionKind{Group: g, Version: v, Kind: k} } + +func gvk(g, v, k string) schema.GroupVersionKind { + return schema.GroupVersionKind{Group: g, Version: v, Kind: k} +} diff --git a/test/integration/etcd/etcd_storage_path_test.go b/test/integration/etcd/etcd_storage_path_test.go index 7abbc229339..5b007224eba 100644 --- a/test/integration/etcd/etcd_storage_path_test.go +++ b/test/integration/etcd/etcd_storage_path_test.go @@ -20,6 +20,7 @@ import ( "context" "encoding/json" "fmt" + "path/filepath" "reflect" "strings" "testing" @@ -45,6 +46,25 @@ var kindWhiteList = sets.NewString() // namespace used for all tests, do not change this const testNamespace = "etcdstoragepathtestnamespace" +// allowMissingTestdataFixtures contains the kinds expected to be missing serialization fixtures API testdata directory. +// this should only contain custom resources and built-in types with open issues tracking adding serialization fixtures. +// Do not add new built-in types to this list, add them to k8s.io/api/roundtrip_test.go instead. +var allowMissingTestdataFixtures = map[schema.GroupVersionKind]bool{ + // TODO(https://github.com/kubernetes/kubernetes/issues/79027) + gvk("apiregistration.k8s.io", "v1", "APIService"): true, + gvk("apiregistration.k8s.io", "v1beta", "APIService"): true, + + // TODO(https://github.com/kubernetes/kubernetes/issues/79026) + gvk("apiextensions.k8s.io", "v1beta1", "CustomResourceDefinition"): true, + gvk("apiextensions.k8s.io", "v1", "CustomResourceDefinition"): true, + + // Custom resources are not expected to have serialization fixtures in k8s.io/api + gvk("awesome.bears.com", "v1", "Panda"): true, + gvk("cr.bar.com", "v1", "Foo"): true, + gvk("random.numbers.com", "v1", "Integer"): true, + gvk("custom.fancy.com", "v2", "Pant"): true, +} + // TestEtcdStoragePath tests to make sure that all objects are stored in an expected location in etcd. // It will start failing when a new type is added to ensure that all future types are added to this test. // It will also fail when a type gets moved to a different location. Be very careful in this situation because @@ -139,6 +159,40 @@ func TestEtcdStoragePath(t *testing.T) { expectedGVK = *testData.ExpectedGVK } + // if previous releases had a non-alpha version of this group/kind, make sure the storage version is understood by a previous release + fixtureFilenameGroup := expectedGVK.Group + if fixtureFilenameGroup == "" { + fixtureFilenameGroup = "core" + } + // find all versions of this group/kind in all versions of the serialization fixture testdata + previousReleaseGroupKindFiles, err := filepath.Glob("../../../staging/src/k8s.io/api/testdata/*/" + fixtureFilenameGroup + ".*." + expectedGVK.Kind + ".yaml") + if err != nil { + t.Error(err) + } + if len(previousReleaseGroupKindFiles) == 0 && !allowMissingTestdataFixtures[expectedGVK] { + // We should at least find the HEAD fixtures + t.Errorf("No testdata serialization files found for %#v, cannot determine if previous releases could read this group/kind. Add this group-version to k8s.io/api/roundtrip_test.go", expectedGVK) + } + // find non-alpha versions of this group/kind understood by previous releases + previousNonAlphaVersions := sets.NewString() + for _, previousReleaseGroupKindFile := range previousReleaseGroupKindFiles { + if serverVersion := filepath.Base(filepath.Dir(previousReleaseGroupKindFile)); serverVersion == "HEAD" { + continue + } + parts := strings.Split(filepath.Base(previousReleaseGroupKindFile), ".") + version := parts[len(parts)-3] + if !strings.Contains(version, "alpha") { + previousNonAlphaVersions.Insert(version) + } + } + if len(previousNonAlphaVersions) > 0 && !previousNonAlphaVersions.Has(expectedGVK.Version) { + t.Errorf("Previous releases understand non-alpha versions %q, but do not understand the expected current storage version %q. "+ + "This means a current server will store data in etcd that is not understood by a previous version.", + previousNonAlphaVersions.List(), + expectedGVK.Version, + ) + } + actualGVK := output.getGVK() if actualGVK != expectedGVK { t.Errorf("GVK for %s does not match, expected %s got %s", kind, expectedGVK, actualGVK) @@ -181,8 +235,10 @@ func TestEtcdStoragePath(t *testing.T) { } } +var debug = false + func dumpEtcdKVOnFailure(t *testing.T, kvClient clientv3.KV) { - if t.Failed() { + if t.Failed() && debug { response, err := kvClient.Get(context.Background(), "/", clientv3.WithPrefix()) if err != nil { t.Fatal(err) diff --git a/test/integration/etcd/server.go b/test/integration/etcd/server.go index 64c9f0f0b3f..cd9b544f8ee 100644 --- a/test/integration/etcd/server.go +++ b/test/integration/etcd/server.go @@ -122,6 +122,9 @@ func StartRealMasterOrDie(t *testing.T, configFuncs ...func(*options.ServerRunOp kubeClientConfig.QPS = 99999 kubeClientConfig.Burst = 9999 + // we make requests to all resources, don't log warnings about deprecated ones + restclient.SetDefaultWarningHandler(restclient.NoWarnings{}) + kubeClient := clientset.NewForConfigOrDie(kubeClientConfig) go func() {