...

Source file src/k8s.io/apiextensions-apiserver/test/integration/versioning_test.go

Documentation: k8s.io/apiextensions-apiserver/test/integration

     1  /*
     2  Copyright 2018 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 integration
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"net/http"
    23  	"reflect"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/stretchr/testify/assert"
    28  	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
    29  	"k8s.io/apiextensions-apiserver/test/integration/fixtures"
    30  	"k8s.io/apimachinery/pkg/api/errors"
    31  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    32  	"k8s.io/apimachinery/pkg/types"
    33  	"k8s.io/apimachinery/pkg/util/wait"
    34  )
    35  
    36  func TestInternalVersionIsHandlerVersion(t *testing.T) {
    37  	tearDown, apiExtensionClient, dynamicClient, err := fixtures.StartDefaultServerWithClients(t)
    38  	if err != nil {
    39  		t.Fatal(err)
    40  	}
    41  	defer tearDown()
    42  
    43  	noxuDefinition := fixtures.NewMultipleVersionNoxuCRD(apiextensionsv1.NamespaceScoped)
    44  
    45  	assert.Equal(t, "v1beta1", noxuDefinition.Spec.Versions[0].Name)
    46  	assert.Equal(t, "v1beta2", noxuDefinition.Spec.Versions[1].Name)
    47  	assert.True(t, noxuDefinition.Spec.Versions[1].Storage)
    48  
    49  	noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
    50  	if err != nil {
    51  		t.Fatal(err)
    52  	}
    53  
    54  	ns := "not-the-default"
    55  
    56  	noxuNamespacedResourceClientV1beta1 := newNamespacedCustomResourceVersionedClient(ns, dynamicClient, noxuDefinition, "v1beta1") // use the non-storage version v1beta1
    57  
    58  	t.Logf("Creating foo")
    59  	noxuInstanceToCreate := fixtures.NewNoxuInstance(ns, "foo")
    60  	_, err = noxuNamespacedResourceClientV1beta1.Create(context.TODO(), noxuInstanceToCreate, metav1.CreateOptions{})
    61  	if err != nil {
    62  		t.Fatal(err)
    63  	}
    64  
    65  	// update validation via update because the cache priming in CreateCRDUsingRemovedAPI will fail otherwise
    66  	t.Logf("Updating CRD to validate apiVersion")
    67  	noxuDefinition, err = UpdateCustomResourceDefinitionWithRetry(apiExtensionClient, noxuDefinition.Name, func(crd *apiextensionsv1.CustomResourceDefinition) {
    68  		for i := range crd.Spec.Versions {
    69  			crd.Spec.Versions[i].Schema = &apiextensionsv1.CustomResourceValidation{
    70  				OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
    71  					Type: "object",
    72  					Properties: map[string]apiextensionsv1.JSONSchemaProps{
    73  						"apiVersion": {
    74  							Pattern: "^mygroup.example.com/v1beta1$", // this means we can only patch via the v1beta1 handler version
    75  							Type:    "string",
    76  						},
    77  					},
    78  					Required: []string{"apiVersion"},
    79  				},
    80  			}
    81  		}
    82  	})
    83  	assert.NoError(t, err)
    84  
    85  	time.Sleep(time.Second)
    86  
    87  	// patches via handler version v1beta1 should succeed (validation allows that API version)
    88  	{
    89  		t.Logf("patch of handler version v1beta1 (non-storage version) should succeed")
    90  		i := 0
    91  		err = wait.PollImmediate(time.Millisecond*100, wait.ForeverTestTimeout, func() (bool, error) {
    92  			patch := []byte(fmt.Sprintf(`{"i": %d}`, i))
    93  			i++
    94  
    95  			_, err := noxuNamespacedResourceClientV1beta1.Patch(context.TODO(), "foo", types.MergePatchType, patch, metav1.PatchOptions{})
    96  			if err != nil {
    97  				// work around "grpc: the client connection is closing" error
    98  				// TODO: fix the grpc error
    99  				if err, ok := err.(*errors.StatusError); ok && err.Status().Code == http.StatusInternalServerError {
   100  					return false, nil
   101  				}
   102  				return false, err
   103  			}
   104  			return true, nil
   105  		})
   106  		assert.NoError(t, err)
   107  	}
   108  
   109  	// patches via handler version matching storage version should fail (validation does not allow that API version)
   110  	{
   111  		t.Logf("patch of handler version v1beta2 (storage version) should fail")
   112  		i := 0
   113  		noxuNamespacedResourceClientV1beta2 := newNamespacedCustomResourceVersionedClient(ns, dynamicClient, noxuDefinition, "v1beta2") // use the storage version v1beta2
   114  		err = wait.PollImmediate(time.Millisecond*100, wait.ForeverTestTimeout, func() (bool, error) {
   115  			patch := []byte(fmt.Sprintf(`{"i": %d}`, i))
   116  			i++
   117  
   118  			_, err := noxuNamespacedResourceClientV1beta2.Patch(context.TODO(), "foo", types.MergePatchType, patch, metav1.PatchOptions{})
   119  			assert.Error(t, err)
   120  
   121  			// work around "grpc: the client connection is closing" error
   122  			// TODO: fix the grpc error
   123  			if err, ok := err.(*errors.StatusError); ok && err.Status().Code == http.StatusInternalServerError {
   124  				return false, nil
   125  			}
   126  
   127  			assert.Contains(t, err.Error(), "apiVersion")
   128  			return true, nil
   129  		})
   130  		assert.NoError(t, err)
   131  	}
   132  }
   133  
   134  func TestVersionedNamespacedScopedCRD(t *testing.T) {
   135  	tearDown, apiExtensionClient, dynamicClient, err := fixtures.StartDefaultServerWithClients(t)
   136  	if err != nil {
   137  		t.Fatal(err)
   138  	}
   139  	defer tearDown()
   140  
   141  	noxuDefinition := fixtures.NewMultipleVersionNoxuCRD(apiextensionsv1.NamespaceScoped)
   142  	noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
   143  	if err != nil {
   144  		t.Fatal(err)
   145  	}
   146  
   147  	ns := "not-the-default"
   148  	testSimpleCRUD(t, ns, noxuDefinition, dynamicClient)
   149  }
   150  
   151  func TestVersionedClusterScopedCRD(t *testing.T) {
   152  	tearDown, apiExtensionClient, dynamicClient, err := fixtures.StartDefaultServerWithClients(t)
   153  	if err != nil {
   154  		t.Fatal(err)
   155  	}
   156  	defer tearDown()
   157  
   158  	noxuDefinition := fixtures.NewMultipleVersionNoxuCRD(apiextensionsv1.ClusterScoped)
   159  	noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
   160  	if err != nil {
   161  		t.Fatal(err)
   162  	}
   163  
   164  	ns := ""
   165  	testSimpleCRUD(t, ns, noxuDefinition, dynamicClient)
   166  }
   167  
   168  func TestStoragedVersionInNamespacedCRDStatus(t *testing.T) {
   169  	noxuDefinition := fixtures.NewMultipleVersionNoxuCRD(apiextensionsv1.NamespaceScoped)
   170  	ns := "not-the-default"
   171  	testStoragedVersionInCRDStatus(t, ns, noxuDefinition)
   172  }
   173  
   174  func TestStoragedVersionInClusterScopedCRDStatus(t *testing.T) {
   175  	noxuDefinition := fixtures.NewMultipleVersionNoxuCRD(apiextensionsv1.ClusterScoped)
   176  	ns := ""
   177  	testStoragedVersionInCRDStatus(t, ns, noxuDefinition)
   178  }
   179  
   180  func testStoragedVersionInCRDStatus(t *testing.T, ns string, noxuDefinition *apiextensionsv1.CustomResourceDefinition) {
   181  	versionsV1Beta1Storage := []apiextensionsv1.CustomResourceDefinitionVersion{
   182  		{
   183  			Name:    "v1beta1",
   184  			Served:  true,
   185  			Storage: true,
   186  			Schema:  fixtures.AllowAllSchema(),
   187  		},
   188  		{
   189  			Name:    "v1beta2",
   190  			Served:  true,
   191  			Storage: false,
   192  			Schema:  fixtures.AllowAllSchema(),
   193  		},
   194  	}
   195  	versionsV1Beta2Storage := []apiextensionsv1.CustomResourceDefinitionVersion{
   196  		{
   197  			Name:    "v1beta1",
   198  			Served:  true,
   199  			Storage: false,
   200  			Schema:  fixtures.AllowAllSchema(),
   201  		},
   202  		{
   203  			Name:    "v1beta2",
   204  			Served:  true,
   205  			Storage: true,
   206  			Schema:  fixtures.AllowAllSchema(),
   207  		},
   208  	}
   209  	tearDown, apiExtensionClient, dynamicClient, err := fixtures.StartDefaultServerWithClients(t)
   210  	if err != nil {
   211  		t.Fatal(err)
   212  	}
   213  	defer tearDown()
   214  
   215  	noxuDefinition.Spec.Versions = versionsV1Beta1Storage
   216  	noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
   217  	if err != nil {
   218  		t.Fatal(err)
   219  	}
   220  
   221  	// The storage version list should be initilized to storage version
   222  	crd, err := apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), noxuDefinition.Name, metav1.GetOptions{})
   223  	if err != nil {
   224  		t.Fatal(err)
   225  	}
   226  	if e, a := []string{"v1beta1"}, crd.Status.StoredVersions; !reflect.DeepEqual(e, a) {
   227  		t.Errorf("expected %v, got %v", e, a)
   228  	}
   229  
   230  	// Changing CRD storage version should be reflected immediately
   231  	crd.Spec.Versions = versionsV1Beta2Storage
   232  	_, err = apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Update(context.TODO(), crd, metav1.UpdateOptions{})
   233  	if err != nil {
   234  		t.Fatal(err)
   235  	}
   236  	crd, err = apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), noxuDefinition.Name, metav1.GetOptions{})
   237  	if err != nil {
   238  		t.Fatal(err)
   239  	}
   240  	if e, a := []string{"v1beta1", "v1beta2"}, crd.Status.StoredVersions; !reflect.DeepEqual(e, a) {
   241  		t.Errorf("expected %v, got %v", e, a)
   242  	}
   243  
   244  	err = fixtures.DeleteV1CustomResourceDefinition(crd, apiExtensionClient)
   245  	if err != nil {
   246  		t.Fatal(err)
   247  	}
   248  }
   249  

View as plain text