Commit a90cab07 authored by Dr. Stefan Schimanski's avatar Dr. Stefan Schimanski

e2e: cleanup test/util/crd to decouple tests

parent 746404f8
...@@ -63,7 +63,6 @@ go_library( ...@@ -63,7 +63,6 @@ go_library(
"//staging/src/k8s.io/apimachinery/pkg/util/uuid:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/version:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/version:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/yaml:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/endpoints/discovery:go_default_library", "//staging/src/k8s.io/apiserver/pkg/endpoints/discovery:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/storage/names:go_default_library", "//staging/src/k8s.io/apiserver/pkg/storage/names:go_default_library",
......
...@@ -106,15 +106,20 @@ var _ = SIGDescribe("CustomResourceConversionWebhook [Feature:CustomResourceWebh ...@@ -106,15 +106,20 @@ var _ = SIGDescribe("CustomResourceConversionWebhook [Feature:CustomResourceWebh
}) })
ginkgo.It("Should be able to convert from CR v1 to CR v2", func() { ginkgo.It("Should be able to convert from CR v1 to CR v2", func() {
testcrd, err := crd.CreateMultiVersionTestCRD(f, "stable.example.com", apiVersions, testcrd, err := crd.CreateMultiVersionTestCRD(f, "stable.example.com", func(crd *v1beta1.CustomResourceDefinition) {
&v1beta1.WebhookClientConfig{ crd.Spec.Conversion = &v1beta1.CustomResourceConversion{
CABundle: context.signingCert, Strategy: v1beta1.WebhookConverter,
Service: &v1beta1.ServiceReference{ WebhookClientConfig: &v1beta1.WebhookClientConfig{
Namespace: f.Namespace.Name, CABundle: context.signingCert,
Name: serviceCRDName, Service: &v1beta1.ServiceReference{
Path: pointer.StringPtr("/crdconvert"), Namespace: f.Namespace.Name,
Port: pointer.Int32Ptr(serviceCRDPort), Name: serviceCRDName,
}}) Path: pointer.StringPtr("/crdconvert"),
Port: pointer.Int32Ptr(serviceCRDPort),
},
},
}
})
if err != nil { if err != nil {
return return
} }
...@@ -123,15 +128,20 @@ var _ = SIGDescribe("CustomResourceConversionWebhook [Feature:CustomResourceWebh ...@@ -123,15 +128,20 @@ var _ = SIGDescribe("CustomResourceConversionWebhook [Feature:CustomResourceWebh
}) })
ginkgo.It("Should be able to convert a non homogeneous list of CRs", func() { ginkgo.It("Should be able to convert a non homogeneous list of CRs", func() {
testcrd, err := crd.CreateMultiVersionTestCRD(f, "stable.example.com", apiVersions, testcrd, err := crd.CreateMultiVersionTestCRD(f, "stable.example.com", func(crd *v1beta1.CustomResourceDefinition) {
&v1beta1.WebhookClientConfig{ crd.Spec.Conversion = &v1beta1.CustomResourceConversion{
CABundle: context.signingCert, Strategy: v1beta1.WebhookConverter,
Service: &v1beta1.ServiceReference{ WebhookClientConfig: &v1beta1.WebhookClientConfig{
Namespace: f.Namespace.Name, CABundle: context.signingCert,
Name: serviceCRDName, Service: &v1beta1.ServiceReference{
Path: pointer.StringPtr("/crdconvert"), Namespace: f.Namespace.Name,
Port: pointer.Int32Ptr(serviceCRDPort), Name: serviceCRDName,
}}) Path: pointer.StringPtr("/crdconvert"),
Port: pointer.Int32Ptr(serviceCRDPort),
},
},
}
})
if err != nil { if err != nil {
return return
} }
......
...@@ -532,10 +532,10 @@ var _ = SIGDescribe("ResourceQuota", func() { ...@@ -532,10 +532,10 @@ var _ = SIGDescribe("ResourceQuota", func() {
framework.ExpectNoError(err) framework.ExpectNoError(err)
ginkgo.By("Creating a custom resource") ginkgo.By("Creating a custom resource")
resourceClient := testcrd.GetV1DynamicClient() resourceClient := testcrd.DynamicClients["v1"]
testcr, err := instantiateCustomResource(&unstructured.Unstructured{ testcr, err := instantiateCustomResource(&unstructured.Unstructured{
Object: map[string]interface{}{ Object: map[string]interface{}{
"apiVersion": testcrd.APIGroup + "/" + testcrd.GetAPIVersions()[0], "apiVersion": testcrd.Crd.Spec.Group + "/" + testcrd.Crd.Spec.Versions[0].Name,
"kind": testcrd.Crd.Spec.Names.Kind, "kind": testcrd.Crd.Spec.Names.Kind,
"metadata": map[string]interface{}{ "metadata": map[string]interface{}{
"name": "test-cr-1", "name": "test-cr-1",
...@@ -553,7 +553,7 @@ var _ = SIGDescribe("ResourceQuota", func() { ...@@ -553,7 +553,7 @@ var _ = SIGDescribe("ResourceQuota", func() {
ginkgo.By("Creating a second custom resource") ginkgo.By("Creating a second custom resource")
_, err = instantiateCustomResource(&unstructured.Unstructured{ _, err = instantiateCustomResource(&unstructured.Unstructured{
Object: map[string]interface{}{ Object: map[string]interface{}{
"apiVersion": testcrd.APIGroup + "/" + testcrd.GetAPIVersions()[0], "apiVersion": testcrd.Crd.Spec.Group + "/" + testcrd.Crd.Spec.Versions[0].Name,
"kind": testcrd.Crd.Spec.Names.Kind, "kind": testcrd.Crd.Spec.Names.Kind,
"metadata": map[string]interface{}{ "metadata": map[string]interface{}{
"name": "test-cr-2", "name": "test-cr-2",
......
...@@ -24,7 +24,7 @@ import ( ...@@ -24,7 +24,7 @@ import (
"k8s.io/api/admissionregistration/v1beta1" "k8s.io/api/admissionregistration/v1beta1"
apps "k8s.io/api/apps/v1" apps "k8s.io/api/apps/v1"
"k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
rbacv1beta1 "k8s.io/api/rbac/v1beta1" rbacv1beta1 "k8s.io/api/rbac/v1beta1"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
crdclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" crdclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
...@@ -46,6 +46,7 @@ import ( ...@@ -46,6 +46,7 @@ import (
"github.com/onsi/ginkgo" "github.com/onsi/ginkgo"
"github.com/onsi/gomega" "github.com/onsi/gomega"
// ensure libs have a chance to initialize // ensure libs have a chance to initialize
_ "github.com/stretchr/testify/assert" _ "github.com/stretchr/testify/assert"
) )
...@@ -143,7 +144,7 @@ var _ = SIGDescribe("AdmissionWebhook", func() { ...@@ -143,7 +144,7 @@ var _ = SIGDescribe("AdmissionWebhook", func() {
defer testcrd.CleanUp() defer testcrd.CleanUp()
webhookCleanup := registerWebhookForCustomResource(f, context, testcrd) webhookCleanup := registerWebhookForCustomResource(f, context, testcrd)
defer webhookCleanup() defer webhookCleanup()
testCustomResourceWebhook(f, testcrd.Crd, testcrd.GetV1DynamicClient()) testCustomResourceWebhook(f, testcrd.Crd, testcrd.DynamicClients["v1"])
}) })
ginkgo.It("Should unconditionally reject operations on fail closed webhook", func() { ginkgo.It("Should unconditionally reject operations on fail closed webhook", func() {
...@@ -180,7 +181,7 @@ var _ = SIGDescribe("AdmissionWebhook", func() { ...@@ -180,7 +181,7 @@ var _ = SIGDescribe("AdmissionWebhook", func() {
defer testcrd.CleanUp() defer testcrd.CleanUp()
webhookCleanup := registerMutatingWebhookForCustomResource(f, context, testcrd) webhookCleanup := registerMutatingWebhookForCustomResource(f, context, testcrd)
defer webhookCleanup() defer webhookCleanup()
testMutatingCustomResourceWebhook(f, testcrd.Crd, testcrd.GetV1DynamicClient()) testMutatingCustomResourceWebhook(f, testcrd.Crd, testcrd.DynamicClients["v1"])
}) })
ginkgo.It("Should deny crd creation", func() { ginkgo.It("Should deny crd creation", func() {
...@@ -191,7 +192,7 @@ var _ = SIGDescribe("AdmissionWebhook", func() { ...@@ -191,7 +192,7 @@ var _ = SIGDescribe("AdmissionWebhook", func() {
}) })
ginkgo.It("Should mutate custom resource with different stored version", func() { ginkgo.It("Should mutate custom resource with different stored version", func() {
testcrd, err := crd.CreateMultiVersionTestCRDWithV1Storage(f) testcrd, err := createAdmissionWebhookMultiVersionTestCRDWithV1Storage(f)
if err != nil { if err != nil {
return return
} }
...@@ -1217,9 +1218,9 @@ func registerWebhookForCustomResource(f *framework.Framework, context *certConte ...@@ -1217,9 +1218,9 @@ func registerWebhookForCustomResource(f *framework.Framework, context *certConte
Rules: []v1beta1.RuleWithOperations{{ Rules: []v1beta1.RuleWithOperations{{
Operations: []v1beta1.OperationType{v1beta1.Create, v1beta1.Update}, Operations: []v1beta1.OperationType{v1beta1.Create, v1beta1.Update},
Rule: v1beta1.Rule{ Rule: v1beta1.Rule{
APIGroups: []string{testcrd.APIGroup}, APIGroups: []string{testcrd.Crd.Spec.Group},
APIVersions: testcrd.GetAPIVersions(), APIVersions: servedAPIVersions(testcrd.Crd),
Resources: []string{testcrd.GetPluralName()}, Resources: []string{testcrd.Crd.Spec.Names.Plural},
}, },
}}, }},
ClientConfig: v1beta1.WebhookClientConfig{ ClientConfig: v1beta1.WebhookClientConfig{
...@@ -1259,9 +1260,9 @@ func registerMutatingWebhookForCustomResource(f *framework.Framework, context *c ...@@ -1259,9 +1260,9 @@ func registerMutatingWebhookForCustomResource(f *framework.Framework, context *c
Rules: []v1beta1.RuleWithOperations{{ Rules: []v1beta1.RuleWithOperations{{
Operations: []v1beta1.OperationType{v1beta1.Create, v1beta1.Update}, Operations: []v1beta1.OperationType{v1beta1.Create, v1beta1.Update},
Rule: v1beta1.Rule{ Rule: v1beta1.Rule{
APIGroups: []string{testcrd.APIGroup}, APIGroups: []string{testcrd.Crd.Spec.Group},
APIVersions: testcrd.GetAPIVersions(), APIVersions: servedAPIVersions(testcrd.Crd),
Resources: []string{testcrd.GetPluralName()}, Resources: []string{testcrd.Crd.Spec.Names.Plural},
}, },
}}, }},
ClientConfig: v1beta1.WebhookClientConfig{ ClientConfig: v1beta1.WebhookClientConfig{
...@@ -1279,9 +1280,9 @@ func registerMutatingWebhookForCustomResource(f *framework.Framework, context *c ...@@ -1279,9 +1280,9 @@ func registerMutatingWebhookForCustomResource(f *framework.Framework, context *c
Rules: []v1beta1.RuleWithOperations{{ Rules: []v1beta1.RuleWithOperations{{
Operations: []v1beta1.OperationType{v1beta1.Create}, Operations: []v1beta1.OperationType{v1beta1.Create},
Rule: v1beta1.Rule{ Rule: v1beta1.Rule{
APIGroups: []string{testcrd.APIGroup}, APIGroups: []string{testcrd.Crd.Spec.Group},
APIVersions: testcrd.GetAPIVersions(), APIVersions: servedAPIVersions(testcrd.Crd),
Resources: []string{testcrd.GetPluralName()}, Resources: []string{testcrd.Crd.Spec.Names.Plural},
}, },
}}, }},
ClientConfig: v1beta1.WebhookClientConfig{ ClientConfig: v1beta1.WebhookClientConfig{
...@@ -1357,7 +1358,7 @@ func testMutatingCustomResourceWebhook(f *framework.Framework, crd *apiextension ...@@ -1357,7 +1358,7 @@ func testMutatingCustomResourceWebhook(f *framework.Framework, crd *apiextension
} }
func testMultiVersionCustomResourceWebhook(f *framework.Framework, testcrd *crd.TestCrd) { func testMultiVersionCustomResourceWebhook(f *framework.Framework, testcrd *crd.TestCrd) {
customResourceClient := testcrd.GetV1DynamicClient() customResourceClient := testcrd.DynamicClients["v1"]
ginkgo.By("Creating a custom resource while v1 is storage version") ginkgo.By("Creating a custom resource while v1 is storage version")
crName := "cr-instance-1" crName := "cr-instance-1"
cr := &unstructured.Unstructured{ cr := &unstructured.Unstructured{
...@@ -1446,12 +1447,6 @@ func testCRDDenyWebhook(f *framework.Framework) { ...@@ -1446,12 +1447,6 @@ func testCRDDenyWebhook(f *framework.Framework) {
Storage: true, Storage: true,
}, },
} }
testcrd := &crd.TestCrd{
Name: name,
Kind: kind,
APIGroup: group,
Versions: apiVersions,
}
// Creating a custom resource definition for use by assorted tests. // Creating a custom resource definition for use by assorted tests.
config, err := framework.LoadConfig() config, err := framework.LoadConfig()
...@@ -1466,19 +1461,19 @@ func testCRDDenyWebhook(f *framework.Framework) { ...@@ -1466,19 +1461,19 @@ func testCRDDenyWebhook(f *framework.Framework) {
} }
crd := &apiextensionsv1beta1.CustomResourceDefinition{ crd := &apiextensionsv1beta1.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: testcrd.GetMetaName(), Name: name + "s." + group,
Labels: map[string]string{ Labels: map[string]string{
"webhook-e2e-test": "webhook-disallow", "webhook-e2e-test": "webhook-disallow",
}, },
}, },
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{ Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: testcrd.APIGroup, Group: group,
Versions: testcrd.Versions, Versions: apiVersions,
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{ Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Plural: testcrd.GetPluralName(), Singular: name,
Singular: testcrd.Name, Kind: kind,
Kind: testcrd.Kind, ListKind: kind + "List",
ListKind: testcrd.GetListName(), Plural: name + "s",
}, },
Scope: apiextensionsv1beta1.NamespaceScoped, Scope: apiextensionsv1beta1.NamespaceScoped,
}, },
...@@ -1486,7 +1481,7 @@ func testCRDDenyWebhook(f *framework.Framework) { ...@@ -1486,7 +1481,7 @@ func testCRDDenyWebhook(f *framework.Framework) {
// create CRD // create CRD
_, err = apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Create(crd) _, err = apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Create(crd)
gomega.Expect(err).To(gomega.HaveOccurred(), "create custom resource definition %s should be denied by webhook", testcrd.GetMetaName()) gomega.Expect(err).To(gomega.HaveOccurred(), "create custom resource definition %s should be denied by webhook", crd.Name)
expectedErrMsg := "the crd contains unwanted label" expectedErrMsg := "the crd contains unwanted label"
if !strings.Contains(err.Error(), expectedErrMsg) { if !strings.Contains(err.Error(), expectedErrMsg) {
framework.Failf("expect error contains %q, got %q", expectedErrMsg, err.Error()) framework.Failf("expect error contains %q, got %q", expectedErrMsg, err.Error())
...@@ -1573,3 +1568,34 @@ func testSlowWebhookTimeoutNoError(f *framework.Framework) { ...@@ -1573,3 +1568,34 @@ func testSlowWebhookTimeoutNoError(f *framework.Framework) {
err = client.CoreV1().ConfigMaps(f.Namespace.Name).Delete(name, &metav1.DeleteOptions{}) err = client.CoreV1().ConfigMaps(f.Namespace.Name).Delete(name, &metav1.DeleteOptions{})
gomega.Expect(err).To(gomega.BeNil()) gomega.Expect(err).To(gomega.BeNil())
} }
// createAdmissionWebhookMultiVersionTestCRDWithV1Storage creates a new CRD specifically
// for the admissin webhook calling test.
func createAdmissionWebhookMultiVersionTestCRDWithV1Storage(f *framework.Framework) (*crd.TestCrd, error) {
group := fmt.Sprintf("%s-multiversion-crd-test.k8s.io", f.BaseName)
return crd.CreateMultiVersionTestCRD(f, group, func(crd *apiextensionsv1beta1.CustomResourceDefinition) {
crd.Spec.Versions = []apiextensionsv1beta1.CustomResourceDefinitionVersion{
{
Name: "v1",
Served: true,
Storage: true,
},
{
Name: "v2",
Served: true,
Storage: false,
},
}
})
}
// servedAPIVersions returns the API versions served by the CRD.
func servedAPIVersions(crd *apiextensionsv1beta1.CustomResourceDefinition) []string {
ret := []string{}
for _, v := range crd.Spec.Versions {
if v.Served {
ret = append(ret, v.Name)
}
}
return ret
}
...@@ -18,6 +18,7 @@ go_library( ...@@ -18,6 +18,7 @@ go_library(
"//pkg/kubectl/polymorphichelpers:go_default_library", "//pkg/kubectl/polymorphichelpers:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/api/rbac/v1beta1:go_default_library", "//staging/src/k8s.io/api/rbac/v1beta1:go_default_library",
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
......
...@@ -44,6 +44,7 @@ import ( ...@@ -44,6 +44,7 @@ import (
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
rbacv1beta1 "k8s.io/api/rbac/v1beta1" rbacv1beta1 "k8s.io/api/rbac/v1beta1"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
apierrs "k8s.io/apimachinery/pkg/api/errors" apierrs "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
...@@ -69,6 +70,7 @@ import ( ...@@ -69,6 +70,7 @@ import (
"github.com/onsi/ginkgo" "github.com/onsi/ginkgo"
"github.com/onsi/gomega" "github.com/onsi/gomega"
"k8s.io/kubernetes/pkg/kubectl/polymorphichelpers" "k8s.io/kubernetes/pkg/kubectl/polymorphichelpers"
imageutils "k8s.io/kubernetes/test/utils/image" imageutils "k8s.io/kubernetes/test/utils/image"
) )
...@@ -861,7 +863,7 @@ metadata: ...@@ -861,7 +863,7 @@ metadata:
ginkgo.By("sleep for 10s to wait for potential crd openapi publishing alpha feature") ginkgo.By("sleep for 10s to wait for potential crd openapi publishing alpha feature")
time.Sleep(10 * time.Second) time.Sleep(10 * time.Second)
meta := fmt.Sprintf(metaPattern, crd.Kind, crd.APIGroup, crd.Versions[0].Name, "test-cr") meta := fmt.Sprintf(metaPattern, crd.Crd.Spec.Names.Kind, crd.Crd.Spec.Group, crd.Crd.Spec.Versions[0].Name, "test-cr")
randomCR := fmt.Sprintf(`{%s,"a":{"b":[{"c":"d"}]}}`, meta) randomCR := fmt.Sprintf(`{%s,"a":{"b":[{"c":"d"}]}}`, meta)
if err := createApplyCustomResource(randomCR, f.Namespace.Name, "test-cr", crd); err != nil { if err := createApplyCustomResource(randomCR, f.Namespace.Name, "test-cr", crd); err != nil {
framework.Failf("%v", err) framework.Failf("%v", err)
...@@ -870,19 +872,21 @@ metadata: ...@@ -870,19 +872,21 @@ metadata:
ginkgo.It("should create/apply a valid CR for CRD with validation schema", func() { ginkgo.It("should create/apply a valid CR for CRD with validation schema", func() {
ginkgo.By("prepare CRD with validation schema") ginkgo.By("prepare CRD with validation schema")
crd, err := crd.CreateTestCRD(f) crd, err := crd.CreateTestCRD(f, func(crd *v1beta1.CustomResourceDefinition) {
props := &v1beta1.JSONSchemaProps{}
if err := yaml.Unmarshal(schemaFoo, props); err != nil {
framework.Failf("failed to unmarshal schema: %v", err)
}
})
if err != nil { if err != nil {
framework.Failf("failed to create test CRD: %v", err) framework.Failf("failed to create test CRD: %v", err)
} }
defer crd.CleanUp() defer crd.CleanUp()
if err := crd.PatchSchema(schemaFoo); err != nil {
framework.Failf("%v", err)
}
ginkgo.By("sleep for 10s to wait for potential crd openapi publishing alpha feature") ginkgo.By("sleep for 10s to wait for potential crd openapi publishing alpha feature")
time.Sleep(10 * time.Second) time.Sleep(10 * time.Second)
meta := fmt.Sprintf(metaPattern, crd.Kind, crd.APIGroup, crd.Versions[0].Name, "test-cr") meta := fmt.Sprintf(metaPattern, crd.Crd.Spec.Names.Kind, crd.Crd.Spec.Group, crd.Crd.Spec.Versions[0].Name, "test-cr")
validCR := fmt.Sprintf(`{%s,"spec":{"bars":[{"name":"test-bar"}]}}`, meta) validCR := fmt.Sprintf(`{%s,"spec":{"bars":[{"name":"test-bar"}]}}`, meta)
if err := createApplyCustomResource(validCR, f.Namespace.Name, "test-cr", crd); err != nil { if err := createApplyCustomResource(validCR, f.Namespace.Name, "test-cr", crd); err != nil {
framework.Failf("%v", err) framework.Failf("%v", err)
...@@ -891,19 +895,21 @@ metadata: ...@@ -891,19 +895,21 @@ metadata:
ginkgo.It("should create/apply a valid CR with arbitrary-extra properties for CRD with partially-specified validation schema", func() { ginkgo.It("should create/apply a valid CR with arbitrary-extra properties for CRD with partially-specified validation schema", func() {
ginkgo.By("prepare CRD with partially-specified validation schema") ginkgo.By("prepare CRD with partially-specified validation schema")
crd, err := crd.CreateTestCRD(f) crd, err := crd.CreateTestCRD(f, func(crd *v1beta1.CustomResourceDefinition) {
props := &v1beta1.JSONSchemaProps{}
if err := yaml.Unmarshal(schemaFoo, props); err != nil {
framework.Failf("failed to unmarshal schema: %v", err)
}
})
if err != nil { if err != nil {
framework.Failf("failed to create test CRD: %v", err) framework.Failf("failed to create test CRD: %v", err)
} }
defer crd.CleanUp() defer crd.CleanUp()
if err := crd.PatchSchema(schemaFoo); err != nil {
framework.Failf("%v", err)
}
ginkgo.By("sleep for 10s to wait for potential crd openapi publishing alpha feature") ginkgo.By("sleep for 10s to wait for potential crd openapi publishing alpha feature")
time.Sleep(10 * time.Second) time.Sleep(10 * time.Second)
meta := fmt.Sprintf(metaPattern, crd.Kind, crd.APIGroup, crd.Versions[0].Name, "test-cr") 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) 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 { if err := createApplyCustomResource(validArbitraryCR, f.Namespace.Name, "test-cr", crd); err != nil {
framework.Failf("%v", err) framework.Failf("%v", err)
...@@ -2258,14 +2264,14 @@ func createApplyCustomResource(resource, namespace, name string, crd *crd.TestCr ...@@ -2258,14 +2264,14 @@ func createApplyCustomResource(resource, namespace, name string, crd *crd.TestCr
if _, err := framework.RunKubectlInput(resource, ns, "create", "-f", "-"); err != nil { if _, err := framework.RunKubectlInput(resource, ns, "create", "-f", "-"); err != nil {
return fmt.Errorf("failed to create CR %s in namespace %s: %v", resource, ns, err) return fmt.Errorf("failed to create CR %s in namespace %s: %v", resource, ns, err)
} }
if _, err := framework.RunKubectl(ns, "delete", crd.GetPluralName(), name); err != nil { if _, err := framework.RunKubectl(ns, "delete", crd.Crd.Spec.Names.Plural, name); err != nil {
return fmt.Errorf("failed to delete CR %s: %v", name, err) return fmt.Errorf("failed to delete CR %s: %v", name, err)
} }
ginkgo.By("successfully apply CR") ginkgo.By("successfully apply CR")
if _, err := framework.RunKubectlInput(resource, ns, "apply", "-f", "-"); err != nil { if _, err := framework.RunKubectlInput(resource, ns, "apply", "-f", "-"); err != nil {
return fmt.Errorf("failed to apply CR %s in namespace %s: %v", resource, ns, err) return fmt.Errorf("failed to apply CR %s in namespace %s: %v", resource, ns, err)
} }
if _, err := framework.RunKubectl(ns, "delete", crd.GetPluralName(), name); err != nil { if _, err := framework.RunKubectl(ns, "delete", crd.Crd.Spec.Names.Plural, name); err != nil {
return fmt.Errorf("failed to delete CR %s: %v", name, err) return fmt.Errorf("failed to delete CR %s: %v", name, err)
} }
return nil return nil
......
...@@ -11,8 +11,6 @@ go_library( ...@@ -11,8 +11,6 @@ go_library(
"//staging/src/k8s.io/apiextensions-apiserver/test/integration/fixtures:go_default_library", "//staging/src/k8s.io/apiextensions-apiserver/test/integration/fixtures:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/yaml:go_default_library",
"//staging/src/k8s.io/client-go/dynamic:go_default_library", "//staging/src/k8s.io/client-go/dynamic:go_default_library",
"//test/e2e/framework:go_default_library", "//test/e2e/framework:go_default_library",
], ],
......
...@@ -24,8 +24,6 @@ import ( ...@@ -24,8 +24,6 @@ import (
"k8s.io/apiextensions-apiserver/test/integration/fixtures" "k8s.io/apiextensions-apiserver/test/integration/fixtures"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
utilyaml "k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/client-go/dynamic" "k8s.io/client-go/dynamic"
"k8s.io/kubernetes/test/e2e/framework" "k8s.io/kubernetes/test/e2e/framework"
) )
...@@ -35,27 +33,21 @@ type CleanCrdFn func() error ...@@ -35,27 +33,21 @@ type CleanCrdFn func() error
// TestCrd holds all the pieces needed to test with the CRD // TestCrd holds all the pieces needed to test with the CRD
type TestCrd struct { type TestCrd struct {
Name string
Kind string
APIGroup string
Versions []apiextensionsv1beta1.CustomResourceDefinitionVersion
APIExtensionClient *crdclientset.Clientset APIExtensionClient *crdclientset.Clientset
Crd *apiextensionsv1beta1.CustomResourceDefinition Crd *apiextensionsv1beta1.CustomResourceDefinition
DynamicClients map[string]dynamic.ResourceInterface DynamicClients map[string]dynamic.ResourceInterface
CleanUp CleanCrdFn CleanUp CleanCrdFn
} }
// Option is a modifier for a CRD object used to customize CreateMultiVersionTestCRD and CreateTestCRD.
type Option func(crd *apiextensionsv1beta1.CustomResourceDefinition)
// CreateMultiVersionTestCRD creates a new CRD specifically for the calling test. // CreateMultiVersionTestCRD creates a new CRD specifically for the calling test.
func CreateMultiVersionTestCRD(f *framework.Framework, group string, apiVersions []apiextensionsv1beta1.CustomResourceDefinitionVersion, conversionWebhook *apiextensionsv1beta1.WebhookClientConfig) (*TestCrd, error) { func CreateMultiVersionTestCRD(f *framework.Framework, group string, opts ...Option) (*TestCrd, error) {
suffix := framework.RandomSuffix() suffix := framework.RandomSuffix()
name := fmt.Sprintf("e2e-test-%s-%s-crd", f.BaseName, suffix) name := fmt.Sprintf("e2e-test-%s-%s-crd", f.BaseName, suffix)
kind := fmt.Sprintf("E2e-test-%s-%s-crd", f.BaseName, suffix) kind := fmt.Sprintf("E2e-test-%s-%s-crd", f.BaseName, suffix)
testcrd := &TestCrd{ testcrd := &TestCrd{}
Name: name,
Kind: kind,
APIGroup: group,
Versions: apiVersions,
}
// Creating a custom resource definition for use by assorted tests. // Creating a custom resource definition for use by assorted tests.
config, err := framework.LoadConfig() config, err := framework.LoadConfig()
...@@ -74,13 +66,24 @@ func CreateMultiVersionTestCRD(f *framework.Framework, group string, apiVersions ...@@ -74,13 +66,24 @@ func CreateMultiVersionTestCRD(f *framework.Framework, group string, apiVersions
return nil, err return nil, err
} }
crd := newCRDForTest(testcrd) crd := &apiextensionsv1beta1.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: name + "s." + group},
if conversionWebhook != nil { Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
crd.Spec.Conversion = &apiextensionsv1beta1.CustomResourceConversion{ Group: group,
Strategy: "Webhook", Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
WebhookClientConfig: conversionWebhook, Plural: name + "s",
} Singular: name,
Kind: kind,
ListKind: kind + "List",
},
Scope: apiextensionsv1beta1.NamespaceScoped,
},
}
for _, opt := range opts {
opt(crd)
}
if len(crd.Spec.Versions) == 0 && len(crd.Spec.Version) == 0 {
crd.Spec.Version = "v1"
} }
//create CRD and waits for the resource to be recognized and available. //create CRD and waits for the resource to be recognized and available.
...@@ -112,92 +115,15 @@ func CreateMultiVersionTestCRD(f *framework.Framework, group string, apiVersions ...@@ -112,92 +115,15 @@ func CreateMultiVersionTestCRD(f *framework.Framework, group string, apiVersions
} }
// CreateTestCRD creates a new CRD specifically for the calling test. // CreateTestCRD creates a new CRD specifically for the calling test.
func CreateTestCRD(f *framework.Framework) (*TestCrd, error) { func CreateTestCRD(f *framework.Framework, opts ...Option) (*TestCrd, error) {
group := fmt.Sprintf("%s-crd-test.k8s.io", f.BaseName) group := fmt.Sprintf("%s-crd-test.k8s.io", f.BaseName)
apiVersions := []apiextensionsv1beta1.CustomResourceDefinitionVersion{ return CreateMultiVersionTestCRD(f, group, append([]Option{func(crd *apiextensionsv1beta1.CustomResourceDefinition) {
{ crd.Spec.Versions = []apiextensionsv1beta1.CustomResourceDefinitionVersion{
Name: "v1", {
Served: true, Name: "v1",
Storage: true, Served: true,
}, Storage: true,
}
return CreateMultiVersionTestCRD(f, group, apiVersions, nil)
}
// CreateMultiVersionTestCRDWithV1Storage creates a new CRD specifically for the calling test.
func CreateMultiVersionTestCRDWithV1Storage(f *framework.Framework) (*TestCrd, error) {
group := fmt.Sprintf("%s-multiversion-crd-test.k8s.io", f.BaseName)
apiVersions := []apiextensionsv1beta1.CustomResourceDefinitionVersion{
{
Name: "v1",
Served: true,
Storage: true,
},
{
Name: "v2",
Served: true,
Storage: false,
},
}
return CreateMultiVersionTestCRD(f, group, apiVersions, nil)
}
// newCRDForTest generates a CRD definition for the test
func newCRDForTest(testcrd *TestCrd) *apiextensionsv1beta1.CustomResourceDefinition {
return &apiextensionsv1beta1.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: testcrd.GetMetaName()},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: testcrd.APIGroup,
Versions: testcrd.Versions,
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Plural: testcrd.GetPluralName(),
Singular: testcrd.Name,
Kind: testcrd.Kind,
ListKind: testcrd.GetListName(),
}, },
Scope: apiextensionsv1beta1.NamespaceScoped,
},
}
}
// GetMetaName returns the metaname for the CRD.
func (c *TestCrd) GetMetaName() string {
return c.Name + "s." + c.APIGroup
}
// GetPluralName returns the plural form of the CRD name
func (c *TestCrd) GetPluralName() string {
return c.Name + "s"
}
// GetListName returns the name for the CRD list resources
func (c *TestCrd) GetListName() string {
return c.Name + "List"
}
// GetAPIVersions returns the API versions served by the CRD.
func (c *TestCrd) GetAPIVersions() []string {
ret := []string{}
for _, v := range c.Versions {
if v.Served {
ret = append(ret, v.Name)
} }
} }}, opts...)...)
return ret
}
// GetV1DynamicClient returns the dynamic client for v1.
func (c *TestCrd) GetV1DynamicClient() dynamic.ResourceInterface {
return c.DynamicClients["v1"]
}
// PatchSchema takes validation schema in YAML and patches it to given CRD
func (c *TestCrd) PatchSchema(schema []byte) error {
s, err := utilyaml.ToJSON(schema)
if err != nil {
return fmt.Errorf("failed to create json patch: %v", err)
}
patch := []byte(fmt.Sprintf(`{"spec":{"validation":{"openAPIV3Schema":%s}}}`, string(s)))
c.Crd, err = c.APIExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Patch(c.GetMetaName(), types.MergePatchType, patch)
return err
} }
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