Ensure storage version is understood by prior releases

This commit is contained in:
Jordan Liggitt 2021-03-05 17:52:22 -05:00
parent b458d97feb
commit 86a8271624
3 changed files with 64 additions and 1 deletions

View File

@ -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}
}

View File

@ -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)

View File

@ -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() {