...

Source file src/k8s.io/kubernetes/test/integration/apiserver/openapi/openapi_v2_merge_test.go

Documentation: k8s.io/kubernetes/test/integration/apiserver/openapi

     1  /*
     2  Copyright 2022 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package openapi
    18  
    19  import (
    20  	"context"
    21  	"encoding/json"
    22  	"strings"
    23  	"testing"
    24  	"time"
    25  
    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/apimachinery/pkg/util/wait"
    31  	"k8s.io/client-go/dynamic"
    32  	kubernetes "k8s.io/client-go/kubernetes"
    33  	"k8s.io/kube-openapi/pkg/validation/spec"
    34  	apiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
    35  	"k8s.io/kubernetes/test/integration/framework"
    36  )
    37  
    38  func TestOpenAPIV2CRDMergeNoDuplicateTypes(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  	clientset, err := kubernetes.NewForConfig(config)
    55  	if err != nil {
    56  		t.Fatal(err)
    57  	}
    58  
    59  	foo := &apiextensionsv1.CustomResourceDefinition{
    60  		ObjectMeta: metav1.ObjectMeta{
    61  			Name: "foosubs.cr.bar.com",
    62  		},
    63  		Spec: apiextensionsv1.CustomResourceDefinitionSpec{
    64  			Group: "cr.bar.com",
    65  			Scope: apiextensionsv1.NamespaceScoped,
    66  			Names: apiextensionsv1.CustomResourceDefinitionNames{
    67  				Plural: "foosubs",
    68  				Kind:   "FooSub",
    69  			},
    70  			Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
    71  				{
    72  					Name:    "v1",
    73  					Served:  true,
    74  					Storage: true,
    75  					Schema: &apiextensionsv1.CustomResourceValidation{
    76  						OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
    77  							Type: "object",
    78  							Properties: map[string]apiextensionsv1.JSONSchemaProps{
    79  								"spec": {
    80  									Type: "object",
    81  									Properties: map[string]apiextensionsv1.JSONSchemaProps{
    82  										"replicas": {
    83  											Type: "integer",
    84  										},
    85  									},
    86  								},
    87  								"status": {
    88  									Type: "object",
    89  									Properties: map[string]apiextensionsv1.JSONSchemaProps{
    90  										"replicas": {
    91  											Type: "integer",
    92  										},
    93  									},
    94  								},
    95  							},
    96  						},
    97  					},
    98  					Subresources: &apiextensionsv1.CustomResourceSubresources{
    99  						Status: &apiextensionsv1.CustomResourceSubresourceStatus{},
   100  						Scale: &apiextensionsv1.CustomResourceSubresourceScale{
   101  							SpecReplicasPath:   ".spec.replicas",
   102  							StatusReplicasPath: ".status.replicas",
   103  						},
   104  					},
   105  				},
   106  			},
   107  		},
   108  	}
   109  
   110  	baz := &apiextensionsv1.CustomResourceDefinition{
   111  		ObjectMeta: metav1.ObjectMeta{
   112  			Name: "bazsubs.cr.bar.com",
   113  		},
   114  		Spec: apiextensionsv1.CustomResourceDefinitionSpec{
   115  			Group: "cr.bar.com",
   116  			Scope: apiextensionsv1.NamespaceScoped,
   117  			Names: apiextensionsv1.CustomResourceDefinitionNames{
   118  				Plural: "bazsubs",
   119  				Kind:   "BazSub",
   120  			},
   121  			Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
   122  				{
   123  					Name:    "v1",
   124  					Served:  true,
   125  					Storage: true,
   126  					Schema: &apiextensionsv1.CustomResourceValidation{
   127  						OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
   128  							Type: "object",
   129  							Properties: map[string]apiextensionsv1.JSONSchemaProps{
   130  								"spec": {
   131  									Type: "object",
   132  									Properties: map[string]apiextensionsv1.JSONSchemaProps{
   133  										"replicas": {
   134  											Type: "integer",
   135  										},
   136  									},
   137  								},
   138  								"status": {
   139  									Type: "object",
   140  									Properties: map[string]apiextensionsv1.JSONSchemaProps{
   141  										"replicas": {
   142  											Type: "integer",
   143  										},
   144  									},
   145  								},
   146  							},
   147  						},
   148  					},
   149  					Subresources: &apiextensionsv1.CustomResourceSubresources{
   150  						Status: &apiextensionsv1.CustomResourceSubresourceStatus{},
   151  						Scale: &apiextensionsv1.CustomResourceSubresourceScale{
   152  							SpecReplicasPath:   ".spec.replicas",
   153  							StatusReplicasPath: ".status.replicas",
   154  						},
   155  					},
   156  				},
   157  			},
   158  		},
   159  	}
   160  
   161  	_, err = fixtures.CreateNewV1CustomResourceDefinition(foo, apiExtensionClient, dynamicClient)
   162  	if err != nil {
   163  		t.Fatal(err)
   164  	}
   165  
   166  	_, err = fixtures.CreateNewV1CustomResourceDefinition(baz, apiExtensionClient, dynamicClient)
   167  	if err != nil {
   168  		t.Fatal(err)
   169  	}
   170  
   171  	var openAPISpec spec.Swagger
   172  	// Poll for the OpenAPI to be updated with the new CRD
   173  	wait.Poll(time.Second*1, wait.ForeverTestTimeout, func() (bool, error) {
   174  		jsonData, err := clientset.RESTClient().Get().AbsPath("/openapi/v2").Do(context.TODO()).Raw()
   175  		if err != nil {
   176  			t.Fatal(err)
   177  		}
   178  		openAPISpec = spec.Swagger{}
   179  		err = json.Unmarshal(jsonData, &openAPISpec)
   180  		if err != nil {
   181  			t.Fatal(err)
   182  		}
   183  		for schemaName := range openAPISpec.Definitions {
   184  			if strings.HasPrefix(schemaName, "com.bar.cr.v1.BazSub") {
   185  				return true, nil
   186  			}
   187  		}
   188  		return false, nil
   189  	})
   190  
   191  	for schemaName := range openAPISpec.Definitions {
   192  		if strings.HasSuffix(schemaName, "_v2") {
   193  			t.Errorf("Error: Expected no _v2 types, got %s", schemaName)
   194  		}
   195  	}
   196  }
   197  

View as plain text