Commit fe5b3033 authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #45913 from enj/enj/t/etcd_cohabitating_resources

Automatic merge from submit-queue (batch tested with PRs 45913, 46065, 46352, 46363, 46373) Detect cohabitating resources in etcd storage test **What this PR does / why we need it**: This change updates the etcd storage path test to detect cohabitating resources by looking at their expected location in etcd. This was not detected in the past because the GVK check did not span across groups. To limit noise from failures caused by multiple objects at the same location in etcd, the test now fails when different GVRs share the same expected path. Thus every object is expected to have a unique path. @liggitt PTAL Signed-off-by: 's avatarMonis Khan <mkhan@redhat.com> **Release note**: ``` NONE ```
parents 80171e51 cbfe566e
...@@ -405,8 +405,10 @@ func TestEtcdStoragePath(t *testing.T) { ...@@ -405,8 +405,10 @@ func TestEtcdStoragePath(t *testing.T) {
}() }()
kindSeen := sets.NewString() kindSeen := sets.NewString()
pathSeen := map[string][]schema.GroupVersionResource{}
etcdSeen := map[schema.GroupVersionResource]empty{} etcdSeen := map[schema.GroupVersionResource]empty{}
ephemeralSeen := map[schema.GroupVersionResource]empty{} ephemeralSeen := map[schema.GroupVersionResource]empty{}
cohabitatingResources := map[string]map[schema.GroupVersionKind]empty{}
for gvk, apiType := range kapi.Scheme.AllKnownTypes() { for gvk, apiType := range kapi.Scheme.AllKnownTypes() {
// we do not care about internal objects or lists // TODO make sure this is always true // we do not care about internal objects or lists // TODO make sure this is always true
...@@ -510,6 +512,9 @@ func TestEtcdStoragePath(t *testing.T) { ...@@ -510,6 +512,9 @@ func TestEtcdStoragePath(t *testing.T) {
if !apiequality.Semantic.DeepDerivative(input, output) { if !apiequality.Semantic.DeepDerivative(input, output) {
t.Errorf("Test stub for %s from %s does not match: %s", kind, pkgPath, diff.ObjectGoPrintDiff(input, output)) t.Errorf("Test stub for %s from %s does not match: %s", kind, pkgPath, diff.ObjectGoPrintDiff(input, output))
} }
addGVKToEtcdBucket(cohabitatingResources, actualGVK, getEtcdBucket(testData.expectedEtcdPath))
pathSeen[testData.expectedEtcdPath] = append(pathSeen[testData.expectedEtcdPath], gvResource)
}() }()
} }
...@@ -524,6 +529,26 @@ func TestEtcdStoragePath(t *testing.T) { ...@@ -524,6 +529,26 @@ func TestEtcdStoragePath(t *testing.T) {
if inKindData, inKindSeen := diffMaps(kindWhiteList, kindSeen); len(inKindData) != 0 || len(inKindSeen) != 0 { if inKindData, inKindSeen := diffMaps(kindWhiteList, kindSeen); len(inKindData) != 0 || len(inKindSeen) != 0 {
t.Errorf("kind whitelist data does not match the types we saw:\nin kind whitelist but not seen:\n%s\nseen but not in kind whitelist:\n%s", inKindData, inKindSeen) t.Errorf("kind whitelist data does not match the types we saw:\nin kind whitelist but not seen:\n%s\nseen but not in kind whitelist:\n%s", inKindData, inKindSeen)
} }
for bucket, gvks := range cohabitatingResources {
if len(gvks) != 1 {
gvkStrings := []string{}
for key := range gvks {
gvkStrings = append(gvkStrings, keyStringer(key))
}
t.Errorf("cohabitating resources in etcd bucket %s have inconsistent GVKs\nyou may need to use DefaultStorageFactory.AddCohabitatingResources to sync the GVK of these resources:\n%s", bucket, gvkStrings)
}
}
for path, gvrs := range pathSeen {
if len(gvrs) != 1 {
gvrStrings := []string{}
for _, key := range gvrs {
gvrStrings = append(gvrStrings, keyStringer(key))
}
t.Errorf("invalid test data, please ensure all expectedEtcdPath are unique, path %s has duplicate GVRs:\n%s", path, gvrStrings)
}
}
} }
func startRealMasterOrDie(t *testing.T, certDir string) (*allClient, clientv3.KV, meta.RESTMapper) { func startRealMasterOrDie(t *testing.T, certDir string) (*allClient, clientv3.KV, meta.RESTMapper) {
...@@ -632,6 +657,28 @@ func dumpEtcdKVOnFailure(t *testing.T, kvClient clientv3.KV) { ...@@ -632,6 +657,28 @@ func dumpEtcdKVOnFailure(t *testing.T, kvClient clientv3.KV) {
} }
} }
func addGVKToEtcdBucket(cohabitatingResources map[string]map[schema.GroupVersionKind]empty, gvk schema.GroupVersionKind, bucket string) {
if cohabitatingResources[bucket] == nil {
cohabitatingResources[bucket] = map[schema.GroupVersionKind]empty{}
}
cohabitatingResources[bucket][gvk] = empty{}
}
// getEtcdBucket assumes the last segment of the given etcd path is the name of the object.
// Thus it strips that segment to extract the object's storage "bucket" in etcd. We expect
// all objects that share the a bucket (cohabitating resources) to be stored as the same GVK.
func getEtcdBucket(path string) string {
idx := strings.LastIndex(path, "/")
if idx == -1 {
panic("path with no slashes " + path)
}
bucket := path[:idx]
if len(bucket) == 0 {
panic("invalid bucket for path " + path)
}
return bucket
}
// stable fields to compare as a sanity check // stable fields to compare as a sanity check
type metaObject struct { type metaObject struct {
// all of type meta // all of type meta
...@@ -699,6 +746,8 @@ func keyStringer(i interface{}) string { ...@@ -699,6 +746,8 @@ func keyStringer(i interface{}) string {
return base + key return base + key
case schema.GroupVersionResource: case schema.GroupVersionResource:
return base + key.String() return base + key.String()
case schema.GroupVersionKind:
return base + key.String()
default: default:
panic("unexpected type") panic("unexpected type")
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment