@@ -19,6 +19,7 @@ package master
19
19
import (
20
20
"encoding/json"
21
21
"fmt"
22
+ "strings"
22
23
"testing"
23
24
"time"
24
25
@@ -160,13 +161,36 @@ func TestCRDOpenAPI(t *testing.T) {
160
161
if err != nil {
161
162
t .Fatalf ("Unexpected error: %v" , err )
162
163
}
163
- t .Logf ("Trying to create a custom resource without conflict" )
164
- crd := & apiextensionsv1beta1.CustomResourceDefinition {
164
+
165
+ t .Logf ("Trying to create a CustomResourceDefinitions" )
166
+ nonStructuralCRD := & apiextensionsv1beta1.CustomResourceDefinition {
165
167
ObjectMeta : metav1.ObjectMeta {
166
- Name : "foos.cr.bar.com" ,
168
+ Name : "foos.nonstructural. cr.bar.com" ,
167
169
},
168
170
Spec : apiextensionsv1beta1.CustomResourceDefinitionSpec {
169
- Group : "cr.bar.com" ,
171
+ Group : "nonstructural.cr.bar.com" ,
172
+ Version : "v1" ,
173
+ Scope : apiextensionsv1beta1 .NamespaceScoped ,
174
+ Names : apiextensionsv1beta1.CustomResourceDefinitionNames {
175
+ Plural : "foos" ,
176
+ Kind : "Foo" ,
177
+ },
178
+ Validation : & apiextensionsv1beta1.CustomResourceValidation {
179
+ OpenAPIV3Schema : & apiextensionsv1beta1.JSONSchemaProps {
180
+ Type : "object" ,
181
+ Properties : map [string ]apiextensionsv1beta1.JSONSchemaProps {
182
+ "foo" : {},
183
+ },
184
+ },
185
+ },
186
+ },
187
+ }
188
+ structuralCRD := & apiextensionsv1beta1.CustomResourceDefinition {
189
+ ObjectMeta : metav1.ObjectMeta {
190
+ Name : "foos.structural.cr.bar.com" ,
191
+ },
192
+ Spec : apiextensionsv1beta1.CustomResourceDefinitionSpec {
193
+ Group : "structural.cr.bar.com" ,
170
194
Version : "v1" ,
171
195
Scope : apiextensionsv1beta1 .NamespaceScoped ,
172
196
Names : apiextensionsv1beta1.CustomResourceDefinitionNames {
@@ -184,55 +208,95 @@ func TestCRDOpenAPI(t *testing.T) {
184
208
},
185
209
},
186
210
}
187
- etcd .CreateTestCRDs (t , apiextensionsclient , false , crd )
188
- waitForSpec := func (expectedType string ) {
211
+ etcd .CreateTestCRDs (t , apiextensionsclient , false , nonStructuralCRD )
212
+ etcd .CreateTestCRDs (t , apiextensionsclient , false , structuralCRD )
213
+
214
+ getPublishedSchema := func (defName string ) (* spec.Schema , error ) {
215
+ bs , err := kubeclient .RESTClient ().Get ().AbsPath ("openapi" , "v2" ).DoRaw ()
216
+ if err != nil {
217
+ return nil , err
218
+ }
219
+ spec := spec.Swagger {}
220
+ if err := json .Unmarshal (bs , & spec ); err != nil {
221
+ return nil , err
222
+ }
223
+ if spec .SwaggerProps .Paths == nil {
224
+ return nil , nil
225
+ }
226
+ d , ok := spec .SwaggerProps .Definitions [defName ]
227
+ if ! ok {
228
+ return nil , nil
229
+ }
230
+ return & d , nil
231
+ }
232
+
233
+ waitForSpec := func (crd * apiextensionsv1beta1.CustomResourceDefinition , expectedType string ) {
189
234
t .Logf (`Waiting for {properties: {"foo": {"type":"%s"}}} to show up in schema` , expectedType )
190
235
lastMsg := ""
191
236
if err := wait .PollImmediate (500 * time .Millisecond , 10 * time .Second , func () (bool , error ) {
192
237
lastMsg = ""
193
- bs , err := kubeclient .RESTClient ().Get ().AbsPath ("openapi" , "v2" ).DoRaw ()
238
+ defName := crdDefinitionName (crd )
239
+ schema , err := getPublishedSchema (defName )
194
240
if err != nil {
195
- return false , err
196
- }
197
- spec := spec.Swagger {}
198
- if err := json .Unmarshal (bs , & spec ); err != nil {
199
- return false , err
200
- }
201
- if spec .SwaggerProps .Paths == nil {
202
- lastMsg = "spec.SwaggerProps.Paths is nil"
241
+ lastMsg = err .Error ()
203
242
return false , nil
204
243
}
205
- d , ok := spec .SwaggerProps .Definitions ["com.bar.cr.v1.Foo" ]
206
- if ! ok {
207
- lastMsg = `spec.SwaggerProps.Definitions["com.bar.cr.v1.Foo"] not found`
244
+ if schema == nil {
245
+ lastMsg = fmt .Sprintf ("spec.SwaggerProps.Definitions[%q] not found" , defName )
208
246
return false , nil
209
247
}
210
- p , ok := d .Properties ["foo" ]
248
+ p , ok := schema .Properties ["foo" ]
211
249
if ! ok {
212
- lastMsg = `spec.SwaggerProps.Definitions["com.bar.cr.v1.Foo" ].Properties["foo"] not found`
250
+ lastMsg = fmt . Sprintf ( `spec.SwaggerProps.Definitions[%q ].Properties["foo"] not found` , defName )
213
251
return false , nil
214
252
}
215
253
if ! p .Type .Contains (expectedType ) {
216
- lastMsg = fmt .Sprintf (`spec.SwaggerProps.Definitions["com.bar.cr.v1.Foo" ].Properties["foo"].Type should be %q, but got: %q` , expectedType , p .Type )
254
+ lastMsg = fmt .Sprintf (`spec.SwaggerProps.Definitions[%q ].Properties["foo"].Type should be %q, but got: %q` , defName , expectedType , p .Type )
217
255
return false , nil
218
256
}
219
257
return true , nil
220
258
}); err != nil {
221
- t .Fatalf ("Failed to see %s OpenAPI spec in discovery: %v, last message: %s" , crd .Name , err , lastMsg )
259
+ t .Fatalf ("Failed to see %s OpenAPI spec in discovery: %v, last message: %s" , structuralCRD .Name , err , lastMsg )
222
260
}
223
261
}
224
- waitForSpec ("string" )
225
- crd , err = apiextensionsclient .ApiextensionsV1beta1 ().CustomResourceDefinitions ().Get (crd .Name , metav1.GetOptions {})
262
+
263
+ t .Logf ("Check that structural schema is published" )
264
+ waitForSpec (structuralCRD , "string" )
265
+ structuralCRD , err = apiextensionsclient .ApiextensionsV1beta1 ().CustomResourceDefinitions ().Get (structuralCRD .Name , metav1.GetOptions {})
226
266
if err != nil {
227
267
t .Fatal (err )
228
268
}
229
- prop := crd .Spec .Validation .OpenAPIV3Schema .Properties ["foo" ]
269
+ prop := structuralCRD .Spec .Validation .OpenAPIV3Schema .Properties ["foo" ]
230
270
prop .Type = "boolean"
231
- crd .Spec .Validation .OpenAPIV3Schema .Properties ["foo" ] = prop
232
- if _ , err = apiextensionsclient .ApiextensionsV1beta1 ().CustomResourceDefinitions ().Update (crd ); err != nil {
271
+ structuralCRD .Spec .Validation .OpenAPIV3Schema .Properties ["foo" ] = prop
272
+ if _ , err = apiextensionsclient .ApiextensionsV1beta1 ().CustomResourceDefinitions ().Update (structuralCRD ); err != nil {
233
273
t .Fatal (err )
234
274
}
235
- waitForSpec ("boolean" )
275
+ waitForSpec (structuralCRD , "boolean" )
276
+
277
+ t .Logf ("Check that non-structural schema is not published" )
278
+ schema , err := getPublishedSchema (crdDefinitionName (nonStructuralCRD ))
279
+ if err != nil {
280
+ t .Fatal (err )
281
+ }
282
+ if schema == nil {
283
+ t .Fatal ("expected a non-nil schema" )
284
+ }
285
+ if foo , ok := schema .Properties ["foo" ]; ok {
286
+ t .Fatalf ("unexpected published 'foo' property: %#v" , foo )
287
+ }
288
+ }
289
+
290
+ func crdDefinitionName (crd * apiextensionsv1beta1.CustomResourceDefinition ) string {
291
+ sgmts := strings .Split (crd .Spec .Group , "." )
292
+ reverse (sgmts )
293
+ return strings .Join (append (sgmts , crd .Spec .Version , crd .Spec .Names .Kind ), "." )
294
+ }
295
+
296
+ func reverse (s []string ) {
297
+ for i , j := 0 , len (s )- 1 ; i < j ; i , j = i + 1 , j - 1 {
298
+ s [i ], s [j ] = s [j ], s [i ]
299
+ }
236
300
}
237
301
238
302
type Foo struct {
0 commit comments