...

Source file src/k8s.io/kubernetes/plugin/pkg/admission/storage/persistentvolume/resize/admission_test.go

Documentation: k8s.io/kubernetes/plugin/pkg/admission/storage/persistentvolume/resize

     1  /*
     2  Copyright 2017 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 resize
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"strings"
    23  	"testing"
    24  
    25  	storagev1 "k8s.io/api/storage/v1"
    26  	"k8s.io/apimachinery/pkg/api/resource"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	"k8s.io/apimachinery/pkg/runtime"
    29  	"k8s.io/apimachinery/pkg/runtime/schema"
    30  	"k8s.io/apiserver/pkg/admission"
    31  	"k8s.io/client-go/informers"
    32  	api "k8s.io/kubernetes/pkg/apis/core"
    33  	"k8s.io/kubernetes/pkg/controller"
    34  )
    35  
    36  func getResourceList(storage string) api.ResourceList {
    37  	res := api.ResourceList{}
    38  	if storage != "" {
    39  		res[api.ResourceStorage] = resource.MustParse(storage)
    40  	}
    41  	return res
    42  }
    43  
    44  func TestPVCResizeAdmission(t *testing.T) {
    45  	goldClassName := "gold"
    46  	trueVal := true
    47  	falseVar := false
    48  	goldClass := &storagev1.StorageClass{
    49  		TypeMeta: metav1.TypeMeta{
    50  			Kind: "StorageClass",
    51  		},
    52  		ObjectMeta: metav1.ObjectMeta{
    53  			Name: goldClassName,
    54  		},
    55  		Provisioner:          "kubernetes.io/glusterfs",
    56  		AllowVolumeExpansion: &trueVal,
    57  	}
    58  	silverClassName := "silver"
    59  	silverClass := &storagev1.StorageClass{
    60  		TypeMeta: metav1.TypeMeta{
    61  			Kind: "StorageClass",
    62  		},
    63  		ObjectMeta: metav1.ObjectMeta{
    64  			Name: silverClassName,
    65  		},
    66  		Provisioner:          "kubernetes.io/glusterfs",
    67  		AllowVolumeExpansion: &falseVar,
    68  	}
    69  	expectNoError := func(err error) bool {
    70  		return err == nil
    71  	}
    72  	expectDynamicallyProvisionedError := func(err error) bool {
    73  		return strings.Contains(err.Error(), "only dynamically provisioned pvc can be resized and "+
    74  			"the storageclass that provisions the pvc must support resize")
    75  	}
    76  	tests := []struct {
    77  		name        string
    78  		resource    schema.GroupVersionResource
    79  		subresource string
    80  		oldObj      runtime.Object
    81  		newObj      runtime.Object
    82  
    83  		checkError func(error) bool
    84  	}{
    85  		{
    86  			name:     "pvc-resize, update, no error",
    87  			resource: api.SchemeGroupVersion.WithResource("persistentvolumeclaims"),
    88  			oldObj: &api.PersistentVolumeClaim{
    89  				Spec: api.PersistentVolumeClaimSpec{
    90  					VolumeName: "volume1",
    91  					Resources: api.VolumeResourceRequirements{
    92  						Requests: getResourceList("1Gi"),
    93  					},
    94  					StorageClassName: &goldClassName,
    95  				},
    96  				Status: api.PersistentVolumeClaimStatus{
    97  					Capacity: getResourceList("1Gi"),
    98  					Phase:    api.ClaimBound,
    99  				},
   100  			},
   101  			newObj: &api.PersistentVolumeClaim{
   102  				Spec: api.PersistentVolumeClaimSpec{
   103  					VolumeName: "volume1",
   104  					Resources: api.VolumeResourceRequirements{
   105  						Requests: getResourceList("2Gi"),
   106  					},
   107  					StorageClassName: &goldClassName,
   108  				},
   109  				Status: api.PersistentVolumeClaimStatus{
   110  					Capacity: getResourceList("2Gi"),
   111  					Phase:    api.ClaimBound,
   112  				},
   113  			},
   114  			checkError: expectNoError,
   115  		},
   116  		{
   117  			name:     "pvc-resize, update, dynamically provisioned error",
   118  			resource: api.SchemeGroupVersion.WithResource("persistentvolumeclaims"),
   119  			oldObj: &api.PersistentVolumeClaim{
   120  				Spec: api.PersistentVolumeClaimSpec{
   121  					VolumeName: "volume3",
   122  					Resources: api.VolumeResourceRequirements{
   123  						Requests: getResourceList("1Gi"),
   124  					},
   125  				},
   126  				Status: api.PersistentVolumeClaimStatus{
   127  					Capacity: getResourceList("1Gi"),
   128  					Phase:    api.ClaimBound,
   129  				},
   130  			},
   131  			newObj: &api.PersistentVolumeClaim{
   132  				Spec: api.PersistentVolumeClaimSpec{
   133  					VolumeName: "volume3",
   134  					Resources: api.VolumeResourceRequirements{
   135  						Requests: getResourceList("2Gi"),
   136  					},
   137  				},
   138  				Status: api.PersistentVolumeClaimStatus{
   139  					Capacity: getResourceList("2Gi"),
   140  					Phase:    api.ClaimBound,
   141  				},
   142  			},
   143  			checkError: expectDynamicallyProvisionedError,
   144  		},
   145  		{
   146  			name:     "pvc-resize, update, dynamically provisioned error",
   147  			resource: api.SchemeGroupVersion.WithResource("persistentvolumeclaims"),
   148  			oldObj: &api.PersistentVolumeClaim{
   149  				Spec: api.PersistentVolumeClaimSpec{
   150  					VolumeName: "volume4",
   151  					Resources: api.VolumeResourceRequirements{
   152  						Requests: getResourceList("1Gi"),
   153  					},
   154  					StorageClassName: &silverClassName,
   155  				},
   156  				Status: api.PersistentVolumeClaimStatus{
   157  					Capacity: getResourceList("1Gi"),
   158  					Phase:    api.ClaimBound,
   159  				},
   160  			},
   161  			newObj: &api.PersistentVolumeClaim{
   162  				Spec: api.PersistentVolumeClaimSpec{
   163  					VolumeName: "volume4",
   164  					Resources: api.VolumeResourceRequirements{
   165  						Requests: getResourceList("2Gi"),
   166  					},
   167  					StorageClassName: &silverClassName,
   168  				},
   169  				Status: api.PersistentVolumeClaimStatus{
   170  					Capacity: getResourceList("2Gi"),
   171  					Phase:    api.ClaimBound,
   172  				},
   173  			},
   174  			checkError: expectDynamicallyProvisionedError,
   175  		},
   176  		{
   177  			name:     "PVC update with no change in size",
   178  			resource: api.SchemeGroupVersion.WithResource("persistentvolumeclaims"),
   179  			oldObj: &api.PersistentVolumeClaim{
   180  				Spec: api.PersistentVolumeClaimSpec{
   181  					Resources: api.VolumeResourceRequirements{
   182  						Requests: getResourceList("1Gi"),
   183  					},
   184  					StorageClassName: &silverClassName,
   185  				},
   186  				Status: api.PersistentVolumeClaimStatus{
   187  					Capacity: getResourceList("0Gi"),
   188  					Phase:    api.ClaimPending,
   189  				},
   190  			},
   191  			newObj: &api.PersistentVolumeClaim{
   192  				Spec: api.PersistentVolumeClaimSpec{
   193  					VolumeName: "volume4",
   194  					Resources: api.VolumeResourceRequirements{
   195  						Requests: getResourceList("1Gi"),
   196  					},
   197  					StorageClassName: &silverClassName,
   198  				},
   199  				Status: api.PersistentVolumeClaimStatus{
   200  					Capacity: getResourceList("1Gi"),
   201  					Phase:    api.ClaimBound,
   202  				},
   203  			},
   204  			checkError: expectNoError,
   205  		},
   206  		{
   207  			name:     "expand pvc in pending state",
   208  			resource: api.SchemeGroupVersion.WithResource("persistentvolumeclaims"),
   209  			oldObj: &api.PersistentVolumeClaim{
   210  				Spec: api.PersistentVolumeClaimSpec{
   211  					Resources: api.VolumeResourceRequirements{
   212  						Requests: getResourceList("1Gi"),
   213  					},
   214  					StorageClassName: &silverClassName,
   215  				},
   216  				Status: api.PersistentVolumeClaimStatus{
   217  					Capacity: getResourceList("0Gi"),
   218  					Phase:    api.ClaimPending,
   219  				},
   220  			},
   221  			newObj: &api.PersistentVolumeClaim{
   222  				Spec: api.PersistentVolumeClaimSpec{
   223  					Resources: api.VolumeResourceRequirements{
   224  						Requests: getResourceList("2Gi"),
   225  					},
   226  					StorageClassName: &silverClassName,
   227  				},
   228  				Status: api.PersistentVolumeClaimStatus{
   229  					Capacity: getResourceList("0Gi"),
   230  					Phase:    api.ClaimPending,
   231  				},
   232  			},
   233  			checkError: func(err error) bool {
   234  				return strings.Contains(err.Error(), "Only bound persistent volume claims can be expanded")
   235  			},
   236  		},
   237  	}
   238  
   239  	ctrl := newPlugin()
   240  	informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
   241  	ctrl.SetExternalKubeInformerFactory(informerFactory)
   242  	err := ctrl.ValidateInitialization()
   243  	if err != nil {
   244  		t.Fatalf("neither pv lister nor storageclass lister can be nil")
   245  	}
   246  
   247  	scs := []*storagev1.StorageClass{}
   248  	scs = append(scs, goldClass, silverClass)
   249  	for _, sc := range scs {
   250  		err := informerFactory.Storage().V1().StorageClasses().Informer().GetStore().Add(sc)
   251  		if err != nil {
   252  			fmt.Println("add storageclass error: ", err)
   253  		}
   254  	}
   255  
   256  	for _, tc := range tests {
   257  		operation := admission.Update
   258  		operationOptions := &metav1.CreateOptions{}
   259  		attributes := admission.NewAttributesRecord(tc.newObj, tc.oldObj, schema.GroupVersionKind{}, metav1.NamespaceDefault, "foo", tc.resource, tc.subresource, operation, operationOptions, false, nil)
   260  
   261  		err := ctrl.Validate(context.TODO(), attributes, nil)
   262  		if !tc.checkError(err) {
   263  			t.Errorf("%v: unexpected err: %v", tc.name, err)
   264  		}
   265  	}
   266  
   267  }
   268  

View as plain text