1
16
17 package openapi
18
19 import (
20 "context"
21 "encoding/json"
22 "testing"
23 "time"
24
25 "github.com/stretchr/testify/assert"
26 apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
27 "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
28 "k8s.io/apiextensions-apiserver/test/integration/fixtures"
29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30 "k8s.io/client-go/dynamic"
31 kubernetes "k8s.io/client-go/kubernetes"
32 "k8s.io/kube-openapi/pkg/spec3"
33 apiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
34 "k8s.io/kubernetes/test/integration/framework"
35 )
36
37 const scaleSchemaName = "io.k8s.api.autoscaling.v1.Scale"
38 const statusSchemaName = "io.k8s.apimachinery.pkg.apis.meta.v1.Status"
39 const objectMetaSchemaName = "io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta"
40
41 func TestOpenAPIV3MultipleCRDsSameGV(t *testing.T) {
42 server, err := apiservertesting.StartTestServer(t, apiservertesting.NewDefaultTestServerOptions(), nil, framework.SharedEtcd())
43 if err != nil {
44 t.Fatal(err)
45 }
46 defer server.TearDownFn()
47 config := server.ClientConfig
48
49 apiExtensionClient, err := clientset.NewForConfig(config)
50 if err != nil {
51 t.Fatal(err)
52 }
53 dynamicClient, err := dynamic.NewForConfig(config)
54 if err != nil {
55 t.Fatal(err)
56 }
57 clientset, err := kubernetes.NewForConfig(config)
58 if err != nil {
59 t.Fatal(err)
60 }
61
62 fooWithSubresourceCRD := &apiextensionsv1.CustomResourceDefinition{
63 ObjectMeta: metav1.ObjectMeta{
64 Name: "foosubs.cr.bar.com",
65 },
66 Spec: apiextensionsv1.CustomResourceDefinitionSpec{
67 Group: "cr.bar.com",
68 Scope: apiextensionsv1.NamespaceScoped,
69 Names: apiextensionsv1.CustomResourceDefinitionNames{
70 Plural: "foosubs",
71 Kind: "FooSub",
72 },
73 Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
74 {
75 Name: "v1",
76 Served: true,
77 Storage: true,
78 Schema: &apiextensionsv1.CustomResourceValidation{
79 OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
80 Type: "object",
81 Properties: map[string]apiextensionsv1.JSONSchemaProps{
82 "spec": {
83 Type: "object",
84 Properties: map[string]apiextensionsv1.JSONSchemaProps{
85 "replicas": {
86 Type: "integer",
87 },
88 },
89 },
90 "status": {
91 Type: "object",
92 Properties: map[string]apiextensionsv1.JSONSchemaProps{
93 "replicas": {
94 Type: "integer",
95 },
96 },
97 },
98 },
99 },
100 },
101 Subresources: &apiextensionsv1.CustomResourceSubresources{
102 Status: &apiextensionsv1.CustomResourceSubresourceStatus{},
103 Scale: &apiextensionsv1.CustomResourceSubresourceScale{
104 SpecReplicasPath: ".spec.replicas",
105 StatusReplicasPath: ".status.replicas",
106 },
107 },
108 },
109 },
110 },
111 }
112
113 bazWithSubresourceCRD := &apiextensionsv1.CustomResourceDefinition{
114 ObjectMeta: metav1.ObjectMeta{
115 Name: "bazsubs.cr.bar.com",
116 },
117 Spec: apiextensionsv1.CustomResourceDefinitionSpec{
118 Group: "cr.bar.com",
119 Scope: apiextensionsv1.NamespaceScoped,
120 Names: apiextensionsv1.CustomResourceDefinitionNames{
121 Plural: "bazsubs",
122 Kind: "BazSub",
123 },
124 Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
125 {
126 Name: "v1",
127 Served: true,
128 Storage: true,
129 Schema: &apiextensionsv1.CustomResourceValidation{
130 OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
131 Type: "object",
132 Properties: map[string]apiextensionsv1.JSONSchemaProps{
133 "spec": {
134 Type: "object",
135 Properties: map[string]apiextensionsv1.JSONSchemaProps{
136 "replicas": {
137 Type: "integer",
138 },
139 },
140 },
141 "status": {
142 Type: "object",
143 Properties: map[string]apiextensionsv1.JSONSchemaProps{
144 "replicas": {
145 Type: "integer",
146 },
147 },
148 },
149 },
150 },
151 },
152 Subresources: &apiextensionsv1.CustomResourceSubresources{
153 Status: &apiextensionsv1.CustomResourceSubresourceStatus{},
154 Scale: &apiextensionsv1.CustomResourceSubresourceScale{
155 SpecReplicasPath: ".spec.replicas",
156 StatusReplicasPath: ".status.replicas",
157 },
158 },
159 },
160 },
161 },
162 }
163
164 _, err = fixtures.CreateNewV1CustomResourceDefinition(fooWithSubresourceCRD, apiExtensionClient, dynamicClient)
165 if err != nil {
166 t.Fatal(err)
167 }
168
169 _, err = fixtures.CreateNewV1CustomResourceDefinition(bazWithSubresourceCRD, apiExtensionClient, dynamicClient)
170 if err != nil {
171 t.Fatal(err)
172 }
173
174
175 time.Sleep(4 * time.Second)
176
177 jsonData, err := clientset.RESTClient().Get().AbsPath("/openapi/v3/apis/cr.bar.com/v1").Do(context.TODO()).Raw()
178 if err != nil {
179 t.Fatal(err)
180 }
181
182 openAPISpec := spec3.OpenAPI{}
183 err = json.Unmarshal(jsonData, &openAPISpec)
184 if err != nil {
185 t.Fatal(err)
186 }
187
188
189
190 assert.Contains(t, openAPISpec.Components.Schemas, scaleSchemaName)
191 assert.Contains(t, openAPISpec.Components.Schemas, statusSchemaName)
192 assert.Contains(t, openAPISpec.Components.Schemas, objectMetaSchemaName)
193 assert.Contains(t, openAPISpec.Components.Schemas, "com.bar.cr.v1.BazSub")
194 assert.Contains(t, openAPISpec.Components.Schemas, "com.bar.cr.v1.FooSub")
195 }
196
View as plain text