1
16
17 package apiserver
18
19 import (
20 "context"
21 "fmt"
22 "testing"
23 "time"
24
25 apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
26 "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
29 "k8s.io/apimachinery/pkg/runtime/schema"
30 "k8s.io/apimachinery/pkg/util/wait"
31 "k8s.io/client-go/dynamic"
32 apiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
33 "k8s.io/kubernetes/test/integration/framework"
34 "k8s.io/utils/pointer"
35 )
36
37
38 func TestCRDExponentialRecursionBug(t *testing.T) {
39 server, err := apiservertesting.StartTestServer(t, apiservertesting.NewDefaultTestServerOptions(), nil, framework.SharedEtcd())
40 if err != nil {
41 t.Fatal(err)
42 }
43 defer server.TearDownFn()
44 config := server.ClientConfig
45
46 apiExtensionClient, err := clientset.NewForConfig(config)
47 if err != nil {
48 t.Fatal(err)
49 }
50 dynamicClient, err := dynamic.NewForConfig(config)
51 if err != nil {
52 t.Fatal(err)
53 }
54
55 crd := &apiextensionsv1.CustomResourceDefinition{
56 ObjectMeta: metav1.ObjectMeta{
57 Name: "crontabs.stable.example.com",
58 },
59 Spec: apiextensionsv1.CustomResourceDefinitionSpec{
60 Group: "stable.example.com",
61 Scope: apiextensionsv1.ClusterScoped,
62 Names: apiextensionsv1.CustomResourceDefinitionNames{
63 Plural: "crontabs",
64 Singular: "crontab",
65 Kind: "CronTab",
66 ListKind: "CronTabList",
67 },
68 Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
69 {
70 Name: "v1beta1",
71 Served: true,
72 Storage: true,
73 Schema: &apiextensionsv1.CustomResourceValidation{
74 OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
75 XPreserveUnknownFields: pointer.BoolPtr(true),
76 Type: "object",
77 Properties: map[string]apiextensionsv1.JSONSchemaProps{},
78 },
79 },
80 },
81 },
82 },
83 }
84
85 crd, err = apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Create(context.TODO(), crd, metav1.CreateOptions{})
86 if err != nil {
87 t.Fatal(err)
88 }
89
90
91 err = wait.PollImmediate(100*time.Millisecond, 15*time.Second, func() (bool, error) {
92 groupResource, err := apiExtensionClient.Discovery().ServerResourcesForGroupVersion(crd.Spec.Group + "/" + crd.Spec.Versions[0].Name)
93 if err != nil {
94 return false, nil
95 }
96 for _, g := range groupResource.APIResources {
97 if g.Name == crd.Spec.Names.Plural {
98 return true, nil
99 }
100 }
101 return false, nil
102 })
103 if err != nil {
104 t.Fatal(err)
105 }
106
107 gvr := schema.GroupVersionResource{
108 Group: crd.Spec.Group,
109 Version: crd.Spec.Versions[0].Name,
110 Resource: crd.Spec.Names.Plural,
111 }
112
113 crClient := dynamicClient.Resource(gvr)
114
115 instance := &unstructured.Unstructured{
116 Object: map[string]interface{}{
117 "apiVersion": gvr.Group + "/" + gvr.Version,
118 "kind": crd.Spec.Names.Kind,
119 "metadata": map[string]interface{}{
120 "name": "instanceame",
121 },
122 "spec": map[string]interface{}{},
123 },
124 }
125
126
127 var m map[string]interface{}
128 m = instance.Object["spec"].(map[string]interface{})
129 for i := 0; i < 50; i++ {
130 m[fmt.Sprintf("field%d", i)] = map[string]interface{}{}
131 m = m[fmt.Sprintf("field%d", i)].(map[string]interface{})
132 }
133
134 _, err = crClient.Create(context.TODO(), instance, metav1.CreateOptions{})
135 if err != nil {
136 t.Errorf("Failed to create custom resource: %v", err)
137 }
138
139 }
140
View as plain text