From 044e92b5cf0f5cd35a72cff52b880b5fa1ca8819 Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Thu, 6 Jun 2019 13:56:57 -0400 Subject: [PATCH] Fix kubectl apply skew test with extra properties --- test/e2e/kubectl/BUILD | 1 + test/e2e/kubectl/kubectl.go | 74 ++++++++++++++++++++++++++++++++++++- 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/test/e2e/kubectl/BUILD b/test/e2e/kubectl/BUILD index 2880d843f03..54221e5ffa8 100644 --- a/test/e2e/kubectl/BUILD +++ b/test/e2e/kubectl/BUILD @@ -42,6 +42,7 @@ go_library( "//test/utils/crd:go_default_library", "//test/utils/image:go_default_library", "//vendor/github.com/elazarl/goproxy:go_default_library", + "//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library", "//vendor/github.com/onsi/ginkgo:go_default_library", "//vendor/github.com/onsi/gomega:go_default_library", "//vendor/golang.org/x/net/websocket:go_default_library", diff --git a/test/e2e/kubectl/kubectl.go b/test/e2e/kubectl/kubectl.go index 157f6d922ec..041a0c40586 100644 --- a/test/e2e/kubectl/kubectl.go +++ b/test/e2e/kubectl/kubectl.go @@ -40,6 +40,8 @@ import ( "time" "github.com/elazarl/goproxy" + openapi_v2 "github.com/googleapis/gnostic/OpenAPIv2" + v1 "k8s.io/api/core/v1" rbacv1beta1 "k8s.io/api/rbac/v1beta1" "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" @@ -851,6 +853,56 @@ metadata: }) }) + // definitionMatchesGVK returns true if the specified GVK is listed as an x-kubernetes-group-version-kind extension + definitionMatchesGVK := func(extensions []*openapi_v2.NamedAny, desiredGVK schema.GroupVersionKind) bool { + for _, extension := range extensions { + if extension.GetValue().GetYaml() == "" || + extension.GetName() != "x-kubernetes-group-version-kind" { + continue + } + var values []map[string]string + err := yaml.Unmarshal([]byte(extension.GetValue().GetYaml()), &values) + if err != nil { + e2elog.Logf("%v\n%s", err, string(extension.GetValue().GetYaml())) + continue + } + for _, value := range values { + if value["group"] != desiredGVK.Group { + continue + } + if value["version"] != desiredGVK.Version { + continue + } + if value["kind"] != desiredGVK.Kind { + continue + } + return true + } + } + return false + } + + // schemaForGVK returns a schema (if defined) for the specified GVK + schemaForGVK := func(desiredGVK schema.GroupVersionKind) *openapi_v2.Schema { + d, err := f.ClientSet.Discovery().OpenAPISchema() + if err != nil { + framework.Failf("%v", err) + } + if d == nil || d.Definitions == nil { + return nil + } + for _, p := range d.Definitions.AdditionalProperties { + if p == nil || p.Value == nil { + continue + } + if !definitionMatchesGVK(p.Value.VendorExtension, desiredGVK) { + continue + } + return p.Value + } + return nil + } + framework.KubeDescribe("Kubectl client-side validation", func() { ginkgo.It("should create/apply a CR with unknown fields for CRD with no validation schema", func() { ginkgo.By("create CRD with no validation schema") @@ -877,6 +929,7 @@ metadata: if err := yaml.Unmarshal(schemaFoo, props); err != nil { framework.Failf("failed to unmarshal schema: %v", err) } + crd.Spec.Validation = &v1beta1.CustomResourceValidation{OpenAPIV3Schema: props} }) if err != nil { framework.Failf("failed to create test CRD: %v", err) @@ -900,6 +953,7 @@ metadata: if err := yaml.Unmarshal(schemaFoo, props); err != nil { framework.Failf("failed to unmarshal schema: %v", err) } + crd.Spec.Validation = &v1beta1.CustomResourceValidation{OpenAPIV3Schema: props} }) if err != nil { framework.Failf("failed to create test CRD: %v", err) @@ -909,10 +963,28 @@ metadata: ginkgo.By("sleep for 10s to wait for potential crd openapi publishing alpha feature") time.Sleep(10 * time.Second) + publishedSchema := schemaForGVK(schema.GroupVersionKind{Group: crd.Crd.Spec.Group, Version: crd.Crd.Spec.Version, Kind: crd.Crd.Spec.Names.Kind}) + expectSuccess := false + if publishedSchema == nil || publishedSchema.Properties == nil || publishedSchema.Properties.AdditionalProperties == nil || len(publishedSchema.Properties.AdditionalProperties) == 0 { + // expect success in the following cases: + // - no schema was published + // - a schema was published with no properties + expectSuccess = true + e2elog.Logf("no schema with properties found, expect apply with extra properties to succeed") + } else { + e2elog.Logf("schema with properties found, expect apply with extra properties to fail") + } + meta := fmt.Sprintf(metaPattern, crd.Crd.Spec.Names.Kind, crd.Crd.Spec.Group, crd.Crd.Spec.Versions[0].Name, "test-cr") validArbitraryCR := fmt.Sprintf(`{%s,"spec":{"bars":[{"name":"test-bar"}],"extraProperty":"arbitrary-value"}}`, meta) if err := createApplyCustomResource(validArbitraryCR, f.Namespace.Name, "test-cr", crd); err != nil { - framework.Failf("%v", err) + if expectSuccess { + framework.Failf("%v", err) + } + } else { + if !expectSuccess { + framework.Failf("expected error, got none") + } } })