mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 11:50:44 +00:00
Add CRD e2e tests for list, delete collection, and status sub-resource operations
This commit is contained in:
parent
f4e39afea0
commit
472555152c
@ -370,6 +370,29 @@ func DeleteCustomResourceDefinition(crd *apiextensionsv1beta1.CustomResourceDefi
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteCustomResourceDefinitions deletes all CRD matching the provided deleteListOpts and waits until all the CRDs disappear from discovery.
|
||||||
|
func DeleteCustomResourceDefinitions(deleteListOpts metav1.ListOptions, apiExtensionsClient clientset.Interface) error {
|
||||||
|
list, err := apiExtensionsClient.ApiextensionsV1beta1().CustomResourceDefinitions().List(deleteListOpts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = apiExtensionsClient.ApiextensionsV1beta1().CustomResourceDefinitions().DeleteCollection(nil, deleteListOpts); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, crd := range list.Items {
|
||||||
|
for _, version := range servedVersions(&crd) {
|
||||||
|
err := wait.PollImmediate(500*time.Millisecond, 30*time.Second, func() (bool, error) {
|
||||||
|
exists, err := existsInDiscovery(&crd, apiExtensionsClient, version)
|
||||||
|
return !exists, err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// CreateNewVersionedScaleClient returns a scale client.
|
// CreateNewVersionedScaleClient returns a scale client.
|
||||||
func CreateNewVersionedScaleClient(crd *apiextensionsv1beta1.CustomResourceDefinition, config *rest.Config, version string) (scale.ScalesGetter, error) {
|
func CreateNewVersionedScaleClient(crd *apiextensionsv1beta1.CustomResourceDefinition, config *rest.Config, version string) (scale.ScalesGetter, error) {
|
||||||
discoveryClient, err := discovery.NewDiscoveryClientForConfig(config)
|
discoveryClient, err := discovery.NewDiscoveryClientForConfig(config)
|
||||||
|
@ -57,6 +57,7 @@ go_library(
|
|||||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/runtime: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/types:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
|
||||||
@ -74,6 +75,7 @@ go_library(
|
|||||||
"//staging/src/k8s.io/client-go/rest:go_default_library",
|
"//staging/src/k8s.io/client-go/rest:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/util/cert:go_default_library",
|
"//staging/src/k8s.io/client-go/util/cert:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/util/keyutil:go_default_library",
|
"//staging/src/k8s.io/client-go/util/keyutil:go_default_library",
|
||||||
|
"//staging/src/k8s.io/client-go/util/retry:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/util/workqueue:go_default_library",
|
"//staging/src/k8s.io/client-go/util/workqueue:go_default_library",
|
||||||
"//staging/src/k8s.io/kube-aggregator/pkg/apis/apiregistration/v1:go_default_library",
|
"//staging/src/k8s.io/kube-aggregator/pkg/apis/apiregistration/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset:go_default_library",
|
"//staging/src/k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset:go_default_library",
|
||||||
|
@ -17,14 +17,23 @@ limitations under the License.
|
|||||||
package apimachinery
|
package apimachinery
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/onsi/ginkgo"
|
||||||
|
|
||||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||||
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||||
"k8s.io/apiextensions-apiserver/test/integration/fixtures"
|
"k8s.io/apiextensions-apiserver/test/integration/fixtures"
|
||||||
|
"k8s.io/apimachinery/pkg/api/equality"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
"k8s.io/apimachinery/pkg/util/diff"
|
||||||
|
"k8s.io/apimachinery/pkg/util/uuid"
|
||||||
utilversion "k8s.io/apimachinery/pkg/util/version"
|
utilversion "k8s.io/apimachinery/pkg/util/version"
|
||||||
|
"k8s.io/client-go/dynamic"
|
||||||
|
"k8s.io/client-go/util/retry"
|
||||||
"k8s.io/kubernetes/test/e2e/framework"
|
"k8s.io/kubernetes/test/e2e/framework"
|
||||||
e2elog "k8s.io/kubernetes/test/e2e/framework/log"
|
e2elog "k8s.io/kubernetes/test/e2e/framework/log"
|
||||||
|
|
||||||
"github.com/onsi/ginkgo"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var crdVersion = utilversion.MustParseSemantic("v1.7.0")
|
var crdVersion = utilversion.MustParseSemantic("v1.7.0")
|
||||||
@ -42,29 +51,147 @@ var _ = SIGDescribe("CustomResourceDefinition resources", func() {
|
|||||||
framework.ConformanceIt("creating/deleting custom resource definition objects works ", func() {
|
framework.ConformanceIt("creating/deleting custom resource definition objects works ", func() {
|
||||||
|
|
||||||
config, err := framework.LoadConfig()
|
config, err := framework.LoadConfig()
|
||||||
if err != nil {
|
framework.ExpectNoError(err, "loading config")
|
||||||
e2elog.Failf("failed to load config: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
apiExtensionClient, err := clientset.NewForConfig(config)
|
apiExtensionClient, err := clientset.NewForConfig(config)
|
||||||
if err != nil {
|
framework.ExpectNoError(err, "initializing apiExtensionClient")
|
||||||
e2elog.Failf("failed to initialize apiExtensionClient: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
randomDefinition := fixtures.NewRandomNameCustomResourceDefinition(v1beta1.ClusterScoped)
|
randomDefinition := fixtures.NewRandomNameCustomResourceDefinition(v1beta1.ClusterScoped)
|
||||||
|
|
||||||
//create CRD and waits for the resource to be recognized and available.
|
// Create CRD and waits for the resource to be recognized and available.
|
||||||
randomDefinition, err = fixtures.CreateNewCustomResourceDefinition(randomDefinition, apiExtensionClient, f.DynamicClient)
|
randomDefinition, err = fixtures.CreateNewCustomResourceDefinition(randomDefinition, apiExtensionClient, f.DynamicClient)
|
||||||
if err != nil {
|
framework.ExpectNoError(err, "creating CustomResourceDefinition")
|
||||||
e2elog.Failf("failed to create CustomResourceDefinition: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
err = fixtures.DeleteCustomResourceDefinition(randomDefinition, apiExtensionClient)
|
err = fixtures.DeleteCustomResourceDefinition(randomDefinition, apiExtensionClient)
|
||||||
if err != nil {
|
framework.ExpectNoError(err, "deleting CustomResourceDefinition")
|
||||||
e2elog.Failf("failed to delete CustomResourceDefinition: %v", err)
|
|
||||||
}
|
|
||||||
}()
|
}()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
Release : v1.16
|
||||||
|
Testname: Custom Resource Definition, list
|
||||||
|
Description: Create a API extension client, define 10 random custom resource definitions and list them using a label selector. API server MUST be able to list the custom resource definitions and delete them via delete collection.
|
||||||
|
*/
|
||||||
|
ginkgo.It("listing custom resource definition objects works ", func() {
|
||||||
|
testListSize := 10
|
||||||
|
config, err := framework.LoadConfig()
|
||||||
|
framework.ExpectNoError(err, "loading config")
|
||||||
|
apiExtensionClient, err := clientset.NewForConfig(config)
|
||||||
|
framework.ExpectNoError(err, "initializing apiExtensionClient")
|
||||||
|
|
||||||
|
// Label the CRDs we create so we can list only them even though they are cluster scoped
|
||||||
|
testUUID := string(uuid.NewUUID())
|
||||||
|
|
||||||
|
// Create CRD and wait for the resource to be recognized and available.
|
||||||
|
crds := make([]*v1beta1.CustomResourceDefinition, testListSize)
|
||||||
|
for i := 0; i < testListSize; i++ {
|
||||||
|
crd := fixtures.NewRandomNameCustomResourceDefinition(v1beta1.ClusterScoped)
|
||||||
|
crd.Labels = map[string]string{"e2e-list-test-uuid": testUUID}
|
||||||
|
crd, err = fixtures.CreateNewCustomResourceDefinition(crd, apiExtensionClient, f.DynamicClient)
|
||||||
|
framework.ExpectNoError(err, "creating CustomResourceDefinition")
|
||||||
|
crds[i] = crd
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a crd w/o the label to ensure the label selector matching works correctly
|
||||||
|
crd := fixtures.NewRandomNameCustomResourceDefinition(v1beta1.ClusterScoped)
|
||||||
|
crd, err = fixtures.CreateNewCustomResourceDefinition(crd, apiExtensionClient, f.DynamicClient)
|
||||||
|
framework.ExpectNoError(err, "creating CustomResourceDefinition")
|
||||||
|
defer func() {
|
||||||
|
err = fixtures.DeleteCustomResourceDefinition(crd, apiExtensionClient)
|
||||||
|
framework.ExpectNoError(err, "deleting CustomResourceDefinition")
|
||||||
|
}()
|
||||||
|
|
||||||
|
selectorListOpts := metav1.ListOptions{LabelSelector: "e2e-list-test-uuid=" + testUUID}
|
||||||
|
list, err := apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().List(selectorListOpts)
|
||||||
|
framework.ExpectNoError(err, "listing CustomResourceDefinitions")
|
||||||
|
framework.ExpectEqual(len(list.Items), testListSize)
|
||||||
|
for _, actual := range list.Items {
|
||||||
|
var expected *v1beta1.CustomResourceDefinition
|
||||||
|
for _, e := range crds {
|
||||||
|
if e.Name == actual.Name && e.Namespace == actual.Namespace {
|
||||||
|
expected = e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
framework.ExpectNotEqual(expected, nil)
|
||||||
|
if !equality.Semantic.DeepEqual(actual.Spec, expected.Spec) {
|
||||||
|
e2elog.Failf("Expected CustomResourceDefinition in list with name %s to match crd created with same name, but got different specs:\n%s",
|
||||||
|
actual.Name, diff.ObjectReflectDiff(expected.Spec, actual.Spec))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use delete collection to remove the CRDs
|
||||||
|
err = fixtures.DeleteCustomResourceDefinitions(selectorListOpts, apiExtensionClient)
|
||||||
|
framework.ExpectNoError(err, "deleting CustomResourceDefinitions")
|
||||||
|
_, err = apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(crd.Name, metav1.GetOptions{})
|
||||||
|
framework.ExpectNoError(err, "getting remaining CustomResourceDefinition")
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
Release : v1.16
|
||||||
|
Testname: Custom Resource Definition, status sub-resource
|
||||||
|
Description: Create a API extension client, create a custom resource definition and then read, update and patch its status sub-resource. API server MUST be able to perform the operations against the status sub-resource.
|
||||||
|
*/
|
||||||
|
ginkgo.It("getting/updating/patching custom resource definition status sub-resource works ", func() {
|
||||||
|
config, err := framework.LoadConfig()
|
||||||
|
framework.ExpectNoError(err, "loading config")
|
||||||
|
apiExtensionClient, err := clientset.NewForConfig(config)
|
||||||
|
framework.ExpectNoError(err, "initializing apiExtensionClient")
|
||||||
|
dynamicClient, err := dynamic.NewForConfig(config)
|
||||||
|
framework.ExpectNoError(err, "initializing dynamic client")
|
||||||
|
gvr := v1beta1.SchemeGroupVersion.WithResource("customresourcedefinitions")
|
||||||
|
resourceClient := dynamicClient.Resource(gvr)
|
||||||
|
|
||||||
|
// Create CRD and waits for the resource to be recognized and available.
|
||||||
|
crd := fixtures.NewRandomNameCustomResourceDefinition(v1beta1.ClusterScoped)
|
||||||
|
crd, err = fixtures.CreateNewCustomResourceDefinition(crd, apiExtensionClient, f.DynamicClient)
|
||||||
|
framework.ExpectNoError(err, "creating CustomResourceDefinition")
|
||||||
|
defer func() {
|
||||||
|
err = fixtures.DeleteCustomResourceDefinition(crd, apiExtensionClient)
|
||||||
|
framework.ExpectNoError(err, "deleting CustomResourceDefinition")
|
||||||
|
}()
|
||||||
|
|
||||||
|
var updated *v1beta1.CustomResourceDefinition
|
||||||
|
updateCondition := v1beta1.CustomResourceDefinitionCondition{Message: "updated"}
|
||||||
|
err = retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
||||||
|
// Use dynamic client to read the status sub-resource since typed client does not expose it.
|
||||||
|
u, err := resourceClient.Get(crd.GetName(), metav1.GetOptions{}, "status")
|
||||||
|
framework.ExpectNoError(err, "getting CustomResourceDefinition status")
|
||||||
|
status := unstructuredToCRD(u)
|
||||||
|
if !equality.Semantic.DeepEqual(status.Spec, crd.Spec) {
|
||||||
|
e2elog.Failf("Expected CustomResourceDefinition Spec to match status sub-resource Spec, but got:\n%s", diff.ObjectReflectDiff(status.Spec, crd.Spec))
|
||||||
|
}
|
||||||
|
status.Status.Conditions = append(status.Status.Conditions, updateCondition)
|
||||||
|
updated, err = apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().UpdateStatus(status)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
framework.ExpectNoError(err, "updating CustomResourceDefinition status")
|
||||||
|
expectCondition(updated.Status.Conditions, updateCondition)
|
||||||
|
|
||||||
|
patchCondition := v1beta1.CustomResourceDefinitionCondition{Message: "patched"}
|
||||||
|
patched, err := apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Patch(
|
||||||
|
crd.GetName(),
|
||||||
|
types.JSONPatchType,
|
||||||
|
[]byte(`[{"op": "add", "path": "/status/conditions", "value": [{"message": "patched"}]}]`),
|
||||||
|
"status")
|
||||||
|
framework.ExpectNoError(err, "patching CustomResourceDefinition status")
|
||||||
|
expectCondition(updated.Status.Conditions, updateCondition)
|
||||||
|
expectCondition(patched.Status.Conditions, patchCondition)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
func unstructuredToCRD(obj *unstructured.Unstructured) *v1beta1.CustomResourceDefinition {
|
||||||
|
crd := new(v1beta1.CustomResourceDefinition)
|
||||||
|
err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, crd)
|
||||||
|
framework.ExpectNoError(err, "converting unstructured to CustomResourceDefinition")
|
||||||
|
return crd
|
||||||
|
}
|
||||||
|
|
||||||
|
func expectCondition(conditions []v1beta1.CustomResourceDefinitionCondition, expected v1beta1.CustomResourceDefinitionCondition) {
|
||||||
|
for _, c := range conditions {
|
||||||
|
if equality.Semantic.DeepEqual(c, expected) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
e2elog.Failf("Condition %#v not found in conditions %#v", expected, conditions)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user