...

Source file src/k8s.io/kubernetes/pkg/registry/storage/csidriver/strategy_test.go

Documentation: k8s.io/kubernetes/pkg/registry/storage/csidriver

     1  /*
     2  Copyright 2019 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 csidriver
    18  
    19  import (
    20  	"testing"
    21  
    22  	"github.com/stretchr/testify/require"
    23  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    24  	"k8s.io/apimachinery/pkg/util/validation/field"
    25  	genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
    26  	utilfeature "k8s.io/apiserver/pkg/util/feature"
    27  	featuregatetesting "k8s.io/component-base/featuregate/testing"
    28  	"k8s.io/kubernetes/pkg/apis/storage"
    29  	"k8s.io/kubernetes/pkg/features"
    30  )
    31  
    32  func getValidCSIDriver(name string) *storage.CSIDriver {
    33  	enabled := true
    34  	return &storage.CSIDriver{
    35  		ObjectMeta: metav1.ObjectMeta{
    36  			Name: name,
    37  		},
    38  		Spec: storage.CSIDriverSpec{
    39  			AttachRequired:    &enabled,
    40  			PodInfoOnMount:    &enabled,
    41  			StorageCapacity:   &enabled,
    42  			RequiresRepublish: &enabled,
    43  			SELinuxMount:      &enabled,
    44  		},
    45  	}
    46  }
    47  
    48  func TestCSIDriverStrategy(t *testing.T) {
    49  	ctx := genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{
    50  		APIGroup:   "storage.k8s.io",
    51  		APIVersion: "v1",
    52  		Resource:   "csidrivers",
    53  	})
    54  	if Strategy.NamespaceScoped() {
    55  		t.Errorf("CSIDriver must not be namespace scoped")
    56  	}
    57  	if Strategy.AllowCreateOnUpdate() {
    58  		t.Errorf("CSIDriver should not allow create on update")
    59  	}
    60  
    61  	csiDriver := getValidCSIDriver("valid-csidriver")
    62  
    63  	Strategy.PrepareForCreate(ctx, csiDriver)
    64  
    65  	errs := Strategy.Validate(ctx, csiDriver)
    66  	if len(errs) != 0 {
    67  		t.Errorf("unexpected error validating %v", errs)
    68  	}
    69  
    70  	// Update of spec is disallowed
    71  	newCSIDriver := csiDriver.DeepCopy()
    72  	attachNotRequired := false
    73  	newCSIDriver.Spec.AttachRequired = &attachNotRequired
    74  
    75  	Strategy.PrepareForUpdate(ctx, newCSIDriver, csiDriver)
    76  
    77  	errs = Strategy.ValidateUpdate(ctx, newCSIDriver, csiDriver)
    78  	if len(errs) == 0 {
    79  		t.Errorf("Expected a validation error")
    80  	}
    81  }
    82  
    83  func TestCSIDriverPrepareForUpdate(t *testing.T) {
    84  	ctx := genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{
    85  		APIGroup:   "storage.k8s.io",
    86  		APIVersion: "v1",
    87  		Resource:   "csidrivers",
    88  	})
    89  
    90  	attachRequired := true
    91  	driverWithNothing := &storage.CSIDriver{
    92  		ObjectMeta: metav1.ObjectMeta{
    93  			Name: "foo",
    94  		},
    95  	}
    96  	driverWithPersistent := &storage.CSIDriver{
    97  		ObjectMeta: metav1.ObjectMeta{
    98  			Name: "foo",
    99  		},
   100  		Spec: storage.CSIDriverSpec{
   101  			AttachRequired: &attachRequired,
   102  			VolumeLifecycleModes: []storage.VolumeLifecycleMode{
   103  				storage.VolumeLifecyclePersistent,
   104  			},
   105  		},
   106  	}
   107  	enabled := true
   108  	disabled := false
   109  	gcp := "gcp"
   110  	noneFsGroupPolicy := storage.NoneFSGroupPolicy
   111  	readWriteOnceWithFSTypeFSGroupPolicy := storage.ReadWriteOnceWithFSTypeFSGroupPolicy
   112  	fileFSGroupPolicy := storage.FileFSGroupPolicy
   113  	driverWithPodInfoOnMountEnabled := &storage.CSIDriver{
   114  		ObjectMeta: metav1.ObjectMeta{
   115  			Name: "foo",
   116  		},
   117  		Spec: storage.CSIDriverSpec{
   118  			PodInfoOnMount: &enabled,
   119  		},
   120  	}
   121  	driverWithPodInfoOnMountDisabled := &storage.CSIDriver{
   122  		ObjectMeta: metav1.ObjectMeta{
   123  			Name: "foo",
   124  		},
   125  		Spec: storage.CSIDriverSpec{
   126  			PodInfoOnMount: &disabled,
   127  		},
   128  	}
   129  	driverWithNoneFSGroupPolicy := &storage.CSIDriver{
   130  		ObjectMeta: metav1.ObjectMeta{
   131  			Name: "foo",
   132  		},
   133  		Spec: storage.CSIDriverSpec{
   134  			FSGroupPolicy: &noneFsGroupPolicy,
   135  		},
   136  	}
   137  	driverWithReadWriteOnceWithFSTypeFSGroupPolicy := &storage.CSIDriver{
   138  		ObjectMeta: metav1.ObjectMeta{
   139  			Name: "foo",
   140  		},
   141  		Spec: storage.CSIDriverSpec{
   142  			FSGroupPolicy: &readWriteOnceWithFSTypeFSGroupPolicy,
   143  		},
   144  	}
   145  	driverWithFileFSGroupPolicy := &storage.CSIDriver{
   146  		ObjectMeta: metav1.ObjectMeta{
   147  			Name: "foo",
   148  		},
   149  		Spec: storage.CSIDriverSpec{
   150  			FSGroupPolicy: &fileFSGroupPolicy,
   151  		},
   152  	}
   153  	driverWithCapacityEnabled := &storage.CSIDriver{
   154  		ObjectMeta: metav1.ObjectMeta{
   155  			Name: "foo",
   156  		},
   157  		Spec: storage.CSIDriverSpec{
   158  			StorageCapacity: &enabled,
   159  		},
   160  	}
   161  	driverWithCapacityDisabled := &storage.CSIDriver{
   162  		ObjectMeta: metav1.ObjectMeta{
   163  			Name: "foo",
   164  		},
   165  		Spec: storage.CSIDriverSpec{
   166  			StorageCapacity: &disabled,
   167  		},
   168  	}
   169  	driverWithServiceAccountTokenGCP := &storage.CSIDriver{
   170  		ObjectMeta: metav1.ObjectMeta{
   171  			Name: "foo",
   172  		},
   173  		Spec: storage.CSIDriverSpec{
   174  			TokenRequests:     []storage.TokenRequest{{Audience: gcp}},
   175  			RequiresRepublish: &enabled,
   176  		},
   177  	}
   178  	driverWithSELinuxMountEnabled := &storage.CSIDriver{
   179  		ObjectMeta: metav1.ObjectMeta{
   180  			Name: "foo",
   181  		},
   182  		Spec: storage.CSIDriverSpec{
   183  			SELinuxMount: &enabled,
   184  		},
   185  	}
   186  	driverWithSELinuxMountDisabled := &storage.CSIDriver{
   187  		ObjectMeta: metav1.ObjectMeta{
   188  			Name: "foo",
   189  		},
   190  		Spec: storage.CSIDriverSpec{
   191  			SELinuxMount: &disabled,
   192  		},
   193  	}
   194  
   195  	resultPersistent := []storage.VolumeLifecycleMode{storage.VolumeLifecyclePersistent}
   196  
   197  	tests := []struct {
   198  		name                                string
   199  		old, update                         *storage.CSIDriver
   200  		seLinuxMountReadWriteOncePodEnabled bool
   201  		wantCapacity                        *bool
   202  		wantModes                           []storage.VolumeLifecycleMode
   203  		wantTokenRequests                   []storage.TokenRequest
   204  		wantRequiresRepublish               *bool
   205  		wantGeneration                      int64
   206  		wantSELinuxMount                    *bool
   207  	}{
   208  		{
   209  			name:           "podInfoOnMount feature enabled, before: none, update: enabled",
   210  			old:            driverWithNothing,
   211  			update:         driverWithPodInfoOnMountEnabled,
   212  			wantGeneration: 1,
   213  		},
   214  		{
   215  			name:           "podInfoOnMount feature enabled, before: enabled, update: disabled",
   216  			old:            driverWithPodInfoOnMountEnabled,
   217  			update:         driverWithPodInfoOnMountDisabled,
   218  			wantGeneration: 1,
   219  		},
   220  		{
   221  			name:           "fSGroupPolicy feature enabled, before: nil, update: none",
   222  			old:            driverWithNothing,
   223  			update:         driverWithNoneFSGroupPolicy,
   224  			wantGeneration: 1,
   225  		},
   226  		{
   227  			name:           "fSGroupPolicy feature enabled, before: nil, update: readWriteOnceWithFSType",
   228  			old:            driverWithNothing,
   229  			update:         driverWithReadWriteOnceWithFSTypeFSGroupPolicy,
   230  			wantGeneration: 1,
   231  		},
   232  		{
   233  			name:           "fSGroupPolicy feature enabled, before: nil, update: file",
   234  			old:            driverWithNothing,
   235  			update:         driverWithFileFSGroupPolicy,
   236  			wantGeneration: 1,
   237  		},
   238  		{
   239  			name:           "fSGroupPolicy feature enabled, before: none, update: readWriteOnceWithFSType",
   240  			old:            driverWithNoneFSGroupPolicy,
   241  			update:         driverWithReadWriteOnceWithFSTypeFSGroupPolicy,
   242  			wantGeneration: 1,
   243  		},
   244  		{
   245  			name:           "fSGroupPolicy feature enabled, before: none, update: file",
   246  			old:            driverWithNoneFSGroupPolicy,
   247  			update:         driverWithFileFSGroupPolicy,
   248  			wantGeneration: 1,
   249  		},
   250  		{
   251  			name:           "fSGroupPolicy feature enabled, before: readWriteOnceWithFSType, update: none",
   252  			old:            driverWithReadWriteOnceWithFSTypeFSGroupPolicy,
   253  			update:         driverWithNoneFSGroupPolicy,
   254  			wantGeneration: 1,
   255  		},
   256  		{
   257  			name:           "fSGroupPolicy feature enabled, before: readWriteOnceWithFSType, update: file",
   258  			old:            driverWithReadWriteOnceWithFSTypeFSGroupPolicy,
   259  			update:         driverWithFileFSGroupPolicy,
   260  			wantGeneration: 1,
   261  		},
   262  		{
   263  			name:           "fSGroupPolicy feature enabled, before: file, update: none",
   264  			old:            driverWithFileFSGroupPolicy,
   265  			update:         driverWithNoneFSGroupPolicy,
   266  			wantGeneration: 1,
   267  		},
   268  		{
   269  			name:           "fSGroupPolicy feature enabled, before: file, update: readWriteOnceWithFSType",
   270  			old:            driverWithFileFSGroupPolicy,
   271  			update:         driverWithReadWriteOnceWithFSTypeFSGroupPolicy,
   272  			wantGeneration: 1,
   273  		},
   274  		{
   275  			name:           "capacity feature enabled, before: none, update: enabled",
   276  			old:            driverWithNothing,
   277  			update:         driverWithCapacityEnabled,
   278  			wantCapacity:   &enabled,
   279  			wantGeneration: 1,
   280  		},
   281  		{
   282  			name:           "capacity feature enabled, before: enabled, update: disabled",
   283  			old:            driverWithCapacityEnabled,
   284  			update:         driverWithCapacityDisabled,
   285  			wantCapacity:   &disabled,
   286  			wantGeneration: 1,
   287  		},
   288  		{
   289  			name:           "inline feature enabled, before: none, update: persistent",
   290  			old:            driverWithNothing,
   291  			update:         driverWithPersistent,
   292  			wantModes:      resultPersistent,
   293  			wantGeneration: 1,
   294  		},
   295  		{
   296  			name:                  "service account token feature enabled, before: none, update: audience=gcp",
   297  			old:                   driverWithNothing,
   298  			update:                driverWithServiceAccountTokenGCP,
   299  			wantTokenRequests:     []storage.TokenRequest{{Audience: gcp}},
   300  			wantRequiresRepublish: &enabled,
   301  			wantGeneration:        1,
   302  		},
   303  		{
   304  			name:                                "SELinux mount support feature enabled, before: nil, update: on",
   305  			seLinuxMountReadWriteOncePodEnabled: true,
   306  			old:                                 driverWithNothing,
   307  			update:                              driverWithSELinuxMountEnabled,
   308  			wantSELinuxMount:                    &enabled,
   309  			wantGeneration:                      1,
   310  		},
   311  		{
   312  			name:                                "SELinux mount support feature enabled, before: off, update: on",
   313  			seLinuxMountReadWriteOncePodEnabled: true,
   314  			old:                                 driverWithSELinuxMountDisabled,
   315  			update:                              driverWithSELinuxMountEnabled,
   316  			wantSELinuxMount:                    &enabled,
   317  			wantGeneration:                      1,
   318  		},
   319  		{
   320  			name:                                "SELinux mount support feature enabled, before: on, update: off",
   321  			seLinuxMountReadWriteOncePodEnabled: true,
   322  			old:                                 driverWithSELinuxMountEnabled,
   323  			update:                              driverWithSELinuxMountDisabled,
   324  			wantSELinuxMount:                    &disabled,
   325  			wantGeneration:                      1,
   326  		},
   327  		{
   328  			name:                                "SELinux mount support feature disabled, before: nil, update: on",
   329  			seLinuxMountReadWriteOncePodEnabled: false,
   330  			old:                                 driverWithNothing,
   331  			update:                              driverWithSELinuxMountEnabled,
   332  			wantSELinuxMount:                    nil,
   333  			wantGeneration:                      0,
   334  		},
   335  		{
   336  			name:                                "SELinux mount support feature disabled, before: off, update: on",
   337  			seLinuxMountReadWriteOncePodEnabled: false,
   338  			old:                                 driverWithSELinuxMountDisabled,
   339  			update:                              driverWithSELinuxMountEnabled,
   340  			wantSELinuxMount:                    &enabled,
   341  			wantGeneration:                      1,
   342  		},
   343  		{
   344  			name:                                "SELinux mount support feature enabled, before: on, update: off",
   345  			seLinuxMountReadWriteOncePodEnabled: false,
   346  			old:                                 driverWithSELinuxMountEnabled,
   347  			update:                              driverWithSELinuxMountDisabled,
   348  			wantSELinuxMount:                    &disabled,
   349  			wantGeneration:                      1,
   350  		},
   351  	}
   352  
   353  	for _, test := range tests {
   354  		t.Run(test.name, func(t *testing.T) {
   355  			defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, test.seLinuxMountReadWriteOncePodEnabled)()
   356  
   357  			csiDriver := test.update.DeepCopy()
   358  			Strategy.PrepareForUpdate(ctx, csiDriver, test.old)
   359  			require.Equal(t, test.wantGeneration, csiDriver.GetGeneration())
   360  			require.Equal(t, test.wantCapacity, csiDriver.Spec.StorageCapacity)
   361  			require.Equal(t, test.wantModes, csiDriver.Spec.VolumeLifecycleModes)
   362  			require.Equal(t, test.wantTokenRequests, csiDriver.Spec.TokenRequests)
   363  			require.Equal(t, test.wantRequiresRepublish, csiDriver.Spec.RequiresRepublish)
   364  			require.Equal(t, test.wantSELinuxMount, csiDriver.Spec.SELinuxMount)
   365  		})
   366  	}
   367  }
   368  
   369  func TestCSIDriverValidation(t *testing.T) {
   370  	enabled := true
   371  	disabled := true
   372  	gcp := "gcp"
   373  
   374  	tests := []struct {
   375  		name        string
   376  		csiDriver   *storage.CSIDriver
   377  		expectError bool
   378  	}{
   379  		{
   380  			"valid csidriver",
   381  			getValidCSIDriver("foo"),
   382  			false,
   383  		},
   384  		{
   385  			"true for all flags",
   386  			&storage.CSIDriver{
   387  				ObjectMeta: metav1.ObjectMeta{
   388  					Name: "foo",
   389  				},
   390  				Spec: storage.CSIDriverSpec{
   391  					AttachRequired:    &enabled,
   392  					PodInfoOnMount:    &enabled,
   393  					StorageCapacity:   &enabled,
   394  					RequiresRepublish: &enabled,
   395  					SELinuxMount:      &enabled,
   396  				},
   397  			},
   398  			false,
   399  		},
   400  		{
   401  			"false for all flags",
   402  			&storage.CSIDriver{
   403  				ObjectMeta: metav1.ObjectMeta{
   404  					Name: "foo",
   405  				},
   406  				Spec: storage.CSIDriverSpec{
   407  					AttachRequired:    &disabled,
   408  					PodInfoOnMount:    &disabled,
   409  					StorageCapacity:   &disabled,
   410  					RequiresRepublish: &disabled,
   411  					SELinuxMount:      &disabled,
   412  				},
   413  			},
   414  			false,
   415  		},
   416  		{
   417  			"invalid driver name",
   418  			&storage.CSIDriver{
   419  				ObjectMeta: metav1.ObjectMeta{
   420  					Name: "*foo#",
   421  				},
   422  				Spec: storage.CSIDriverSpec{
   423  					AttachRequired:    &enabled,
   424  					PodInfoOnMount:    &enabled,
   425  					StorageCapacity:   &enabled,
   426  					RequiresRepublish: &enabled,
   427  					SELinuxMount:      &enabled,
   428  				},
   429  			},
   430  			true,
   431  		},
   432  		{
   433  			"invalid volume mode",
   434  			&storage.CSIDriver{
   435  				ObjectMeta: metav1.ObjectMeta{
   436  					Name: "foo",
   437  				},
   438  				Spec: storage.CSIDriverSpec{
   439  					AttachRequired:  &enabled,
   440  					PodInfoOnMount:  &enabled,
   441  					StorageCapacity: &enabled,
   442  					VolumeLifecycleModes: []storage.VolumeLifecycleMode{
   443  						storage.VolumeLifecycleMode("no-such-mode"),
   444  					},
   445  					RequiresRepublish: &enabled,
   446  					SELinuxMount:      &enabled,
   447  				},
   448  			},
   449  			true,
   450  		},
   451  		{
   452  			"persistent volume mode",
   453  			&storage.CSIDriver{
   454  				ObjectMeta: metav1.ObjectMeta{
   455  					Name: "foo",
   456  				},
   457  				Spec: storage.CSIDriverSpec{
   458  					AttachRequired:  &enabled,
   459  					PodInfoOnMount:  &enabled,
   460  					StorageCapacity: &enabled,
   461  					VolumeLifecycleModes: []storage.VolumeLifecycleMode{
   462  						storage.VolumeLifecyclePersistent,
   463  					},
   464  					RequiresRepublish: &enabled,
   465  					SELinuxMount:      &enabled,
   466  				},
   467  			},
   468  			false,
   469  		},
   470  		{
   471  			"ephemeral volume mode",
   472  			&storage.CSIDriver{
   473  				ObjectMeta: metav1.ObjectMeta{
   474  					Name: "foo",
   475  				},
   476  				Spec: storage.CSIDriverSpec{
   477  					AttachRequired:  &enabled,
   478  					PodInfoOnMount:  &enabled,
   479  					StorageCapacity: &enabled,
   480  					VolumeLifecycleModes: []storage.VolumeLifecycleMode{
   481  						storage.VolumeLifecycleEphemeral,
   482  					},
   483  					RequiresRepublish: &enabled,
   484  					SELinuxMount:      &enabled,
   485  				},
   486  			},
   487  			false,
   488  		},
   489  		{
   490  			"both volume modes",
   491  			&storage.CSIDriver{
   492  				ObjectMeta: metav1.ObjectMeta{
   493  					Name: "foo",
   494  				},
   495  				Spec: storage.CSIDriverSpec{
   496  					AttachRequired:  &enabled,
   497  					PodInfoOnMount:  &enabled,
   498  					StorageCapacity: &enabled,
   499  					VolumeLifecycleModes: []storage.VolumeLifecycleMode{
   500  						storage.VolumeLifecyclePersistent,
   501  						storage.VolumeLifecycleEphemeral,
   502  					},
   503  					RequiresRepublish: &enabled,
   504  					SELinuxMount:      &enabled,
   505  				},
   506  			},
   507  			false,
   508  		},
   509  		{
   510  			"service account token with gcp as audience",
   511  			&storage.CSIDriver{
   512  				ObjectMeta: metav1.ObjectMeta{
   513  					Name: "foo",
   514  				},
   515  				Spec: storage.CSIDriverSpec{
   516  					AttachRequired:    &enabled,
   517  					PodInfoOnMount:    &enabled,
   518  					StorageCapacity:   &enabled,
   519  					TokenRequests:     []storage.TokenRequest{{Audience: gcp}},
   520  					RequiresRepublish: &enabled,
   521  					SELinuxMount:      &enabled,
   522  				},
   523  			},
   524  			false,
   525  		},
   526  		{
   527  			"invalid SELinuxMount",
   528  			&storage.CSIDriver{
   529  				ObjectMeta: metav1.ObjectMeta{
   530  					Name: "foo",
   531  				},
   532  				Spec: storage.CSIDriverSpec{
   533  					AttachRequired:  &enabled,
   534  					PodInfoOnMount:  &enabled,
   535  					StorageCapacity: &enabled,
   536  					SELinuxMount:    nil,
   537  				},
   538  			},
   539  			true,
   540  		},
   541  	}
   542  
   543  	for _, test := range tests {
   544  		t.Run(test.name, func(t *testing.T) {
   545  			// assume this feature is on for this test, detailed enabled/disabled tests in TestCSIDriverValidationSELinuxMountEnabledDisabled
   546  			defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)()
   547  
   548  			testValidation := func(csiDriver *storage.CSIDriver, apiVersion string) field.ErrorList {
   549  				ctx := genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{
   550  					APIGroup:   "storage.k8s.io",
   551  					APIVersion: "v1",
   552  					Resource:   "csidrivers",
   553  				})
   554  				return Strategy.Validate(ctx, csiDriver)
   555  			}
   556  
   557  			err := testValidation(test.csiDriver, "v1")
   558  			if len(err) > 0 && !test.expectError {
   559  				t.Errorf("Validation of v1 object failed: %+v", err)
   560  			}
   561  			if len(err) == 0 && test.expectError {
   562  				t.Errorf("Validation of v1 object unexpectedly succeeded")
   563  			}
   564  		})
   565  	}
   566  }
   567  

View as plain text