...

Source file src/k8s.io/kubernetes/test/integration/apiserver/apply/apply_crd_beta_test.go

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

     1  /*
     2  Copyright 2021 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 apiserver
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"reflect"
    23  	"testing"
    24  
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  
    27  	apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
    28  	"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
    29  	"k8s.io/apiextensions-apiserver/test/integration/fixtures"
    30  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    31  	"k8s.io/apimachinery/pkg/types"
    32  	"k8s.io/client-go/dynamic"
    33  	apiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
    34  	"k8s.io/kubernetes/test/integration/framework"
    35  )
    36  
    37  // TestApplyCRDNoSchema tests that CRDs and CRs can both be applied to with a PATCH request with the apply content type
    38  // when there is no validation field provided.
    39  func TestApplyCRDNoSchema(t *testing.T) {
    40  	server, err := apiservertesting.StartTestServer(t, apiservertesting.NewDefaultTestServerOptions(), nil, framework.SharedEtcd())
    41  	if err != nil {
    42  		t.Fatal(err)
    43  	}
    44  	defer server.TearDownFn()
    45  	config := server.ClientConfig
    46  
    47  	apiExtensionClient, err := clientset.NewForConfig(config)
    48  	if err != nil {
    49  		t.Fatal(err)
    50  	}
    51  	dynamicClient, err := dynamic.NewForConfig(config)
    52  	if err != nil {
    53  		t.Fatal(err)
    54  	}
    55  
    56  	noxuBetaDefinition := nearlyRemovedBetaMultipleVersionNoxuCRD(apiextensionsv1beta1.ClusterScoped)
    57  
    58  	noxuDefinition, err := fixtures.CreateCRDUsingRemovedAPI(server.EtcdClient, server.EtcdStoragePrefix, noxuBetaDefinition, apiExtensionClient, dynamicClient)
    59  	if err != nil {
    60  		t.Fatal(err)
    61  	}
    62  
    63  	kind := noxuDefinition.Spec.Names.Kind
    64  	apiVersion := noxuDefinition.Spec.Group + "/" + noxuDefinition.Spec.Versions[0].Name
    65  	name := "mytest"
    66  
    67  	rest := apiExtensionClient.Discovery().RESTClient()
    68  	yamlBody := []byte(fmt.Sprintf(`
    69  apiVersion: %s
    70  kind: %s
    71  metadata:
    72    name: %s
    73  spec:
    74    replicas: 1`, apiVersion, kind, name))
    75  	result, err := rest.Patch(types.ApplyPatchType).
    76  		AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
    77  		Name(name).
    78  		Param("fieldManager", "apply_test").
    79  		Body(yamlBody).
    80  		DoRaw(context.TODO())
    81  	if err != nil {
    82  		t.Fatalf("failed to create custom resource with apply: %v:\n%v", err, string(result))
    83  	}
    84  	verifyReplicas(t, result, 1)
    85  
    86  	// Patch object to change the number of replicas
    87  	result, err = rest.Patch(types.MergePatchType).
    88  		AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
    89  		Name(name).
    90  		Body([]byte(`{"spec":{"replicas": 5}}`)).
    91  		DoRaw(context.TODO())
    92  	if err != nil {
    93  		t.Fatalf("failed to update number of replicas with merge patch: %v:\n%v", err, string(result))
    94  	}
    95  	verifyReplicas(t, result, 5)
    96  
    97  	// Re-apply, we should get conflicts now, since the number of replicas was changed.
    98  	result, err = rest.Patch(types.ApplyPatchType).
    99  		AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
   100  		Name(name).
   101  		Param("fieldManager", "apply_test").
   102  		Body(yamlBody).
   103  		DoRaw(context.TODO())
   104  	if err == nil {
   105  		t.Fatalf("Expecting to get conflicts when applying object after updating replicas, got no error: %s", result)
   106  	}
   107  	status, ok := err.(*apierrors.StatusError)
   108  	if !ok {
   109  		t.Fatalf("Expecting to get conflicts as API error")
   110  	}
   111  	if len(status.Status().Details.Causes) != 1 {
   112  		t.Fatalf("Expecting to get one conflict when applying object after updating replicas, got: %v", status.Status().Details.Causes)
   113  	}
   114  
   115  	// Re-apply with force, should work fine.
   116  	result, err = rest.Patch(types.ApplyPatchType).
   117  		AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
   118  		Name(name).
   119  		Param("force", "true").
   120  		Param("fieldManager", "apply_test").
   121  		Body(yamlBody).
   122  		DoRaw(context.TODO())
   123  	if err != nil {
   124  		t.Fatalf("failed to apply object with force after updating replicas: %v:\n%v", err, string(result))
   125  	}
   126  	verifyReplicas(t, result, 1)
   127  
   128  	// Try to set managed fields using a subresource and verify that it has no effect
   129  	existingManagedFields, err := getManagedFields(result)
   130  	if err != nil {
   131  		t.Fatalf("failed to get managedFields from response: %v", err)
   132  	}
   133  	updateBytes := []byte(`{
   134  		"metadata": {
   135  			"managedFields": [{
   136  				"manager":"testing",
   137  				"operation":"Update",
   138  				"apiVersion":"v1",
   139  				"fieldsType":"FieldsV1",
   140  				"fieldsV1":{
   141  					"f:spec":{
   142  						"f:containers":{
   143  							"k:{\"name\":\"testing\"}":{
   144  								".":{},
   145  								"f:image":{},
   146  								"f:name":{}
   147  							}
   148  						}
   149  					}
   150  				}
   151  			}]
   152  		}
   153  	}`)
   154  	result, err = rest.Patch(types.MergePatchType).
   155  		AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
   156  		SubResource("status").
   157  		Name(name).
   158  		Param("fieldManager", "subresource_test").
   159  		Body(updateBytes).
   160  		DoRaw(context.TODO())
   161  	if err != nil {
   162  		t.Fatalf("Error updating subresource: %v ", err)
   163  	}
   164  	newManagedFields, err := getManagedFields(result)
   165  	if err != nil {
   166  		t.Fatalf("failed to get managedFields from response: %v", err)
   167  	}
   168  	if !reflect.DeepEqual(existingManagedFields, newManagedFields) {
   169  		t.Fatalf("Expected managed fields to not have changed when trying manually setting them via subresoures.\n\nExpected: %#v\n\nGot: %#v", existingManagedFields, newManagedFields)
   170  	}
   171  
   172  	// However, it is possible to modify managed fields using the main resource
   173  	result, err = rest.Patch(types.MergePatchType).
   174  		AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
   175  		Name(name).
   176  		Param("fieldManager", "subresource_test").
   177  		Body([]byte(`{"metadata":{"managedFields":[{}]}}`)).
   178  		DoRaw(context.TODO())
   179  	if err != nil {
   180  		t.Fatalf("Error updating managed fields of the main resource: %v ", err)
   181  	}
   182  	newManagedFields, err = getManagedFields(result)
   183  	if err != nil {
   184  		t.Fatalf("failed to get managedFields from response: %v", err)
   185  	}
   186  
   187  	if len(newManagedFields) != 0 {
   188  		t.Fatalf("Expected managed fields to have been reset, but got: %v", newManagedFields)
   189  	}
   190  }
   191  
   192  func nearlyRemovedBetaMultipleVersionNoxuCRD(scope apiextensionsv1beta1.ResourceScope) *apiextensionsv1beta1.CustomResourceDefinition {
   193  	return &apiextensionsv1beta1.CustomResourceDefinition{
   194  		ObjectMeta: metav1.ObjectMeta{Name: "noxus.mygroup.example.com"},
   195  		Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
   196  			Group:   "mygroup.example.com",
   197  			Version: "v1beta1",
   198  			Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
   199  				Plural:     "noxus",
   200  				Singular:   "nonenglishnoxu",
   201  				Kind:       "WishIHadChosenNoxu",
   202  				ShortNames: []string{"foo", "bar", "abc", "def"},
   203  				ListKind:   "NoxuItemList",
   204  				Categories: []string{"all"},
   205  			},
   206  			Scope: scope,
   207  			Versions: []apiextensionsv1beta1.CustomResourceDefinitionVersion{
   208  				{
   209  					Name:    "v1beta1",
   210  					Served:  true,
   211  					Storage: false,
   212  				},
   213  				{
   214  					Name:    "v1beta2",
   215  					Served:  true,
   216  					Storage: true,
   217  				},
   218  				{
   219  					Name:    "v0",
   220  					Served:  false,
   221  					Storage: false,
   222  				},
   223  			},
   224  			Subresources: &apiextensionsv1beta1.CustomResourceSubresources{
   225  				Status: &apiextensionsv1beta1.CustomResourceSubresourceStatus{},
   226  			},
   227  		},
   228  	}
   229  }
   230  

View as plain text