...

Source file src/k8s.io/kubernetes/pkg/controlplane/apiserver/options/validation_test.go

Documentation: k8s.io/kubernetes/pkg/controlplane/apiserver/options

     1  /*
     2  Copyright 2023 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 options
    18  
    19  import (
    20  	"strings"
    21  	"testing"
    22  
    23  	kubeapiserveradmission "k8s.io/apiserver/pkg/admission"
    24  	genericoptions "k8s.io/apiserver/pkg/server/options"
    25  	utilfeature "k8s.io/apiserver/pkg/util/feature"
    26  	"k8s.io/component-base/featuregate"
    27  	basemetrics "k8s.io/component-base/metrics"
    28  	"k8s.io/kubernetes/pkg/features"
    29  
    30  	peerreconcilers "k8s.io/apiserver/pkg/reconcilers"
    31  	featuregatetesting "k8s.io/component-base/featuregate/testing"
    32  	kubeoptions "k8s.io/kubernetes/pkg/kubeapiserver/options"
    33  )
    34  
    35  func TestValidateAPIPriorityAndFairness(t *testing.T) {
    36  	const conflict = "conflicts with --enable-priority-and-fairness=true"
    37  	tests := []struct {
    38  		runtimeConfig    string
    39  		errShouldContain string
    40  	}{
    41  		{
    42  			runtimeConfig:    "api/all=false",
    43  			errShouldContain: conflict,
    44  		},
    45  		{
    46  			runtimeConfig:    "api/beta=false",
    47  			errShouldContain: "",
    48  		},
    49  		{
    50  			runtimeConfig:    "api/ga=false",
    51  			errShouldContain: conflict,
    52  		},
    53  		{
    54  			runtimeConfig:    "api/ga=true",
    55  			errShouldContain: "",
    56  		},
    57  		{
    58  			runtimeConfig:    "flowcontrol.apiserver.k8s.io/v1beta1=false",
    59  			errShouldContain: "",
    60  		},
    61  		{
    62  			runtimeConfig:    "flowcontrol.apiserver.k8s.io/v1beta2=false",
    63  			errShouldContain: "",
    64  		},
    65  		{
    66  			runtimeConfig:    "flowcontrol.apiserver.k8s.io/v1beta3=false",
    67  			errShouldContain: "",
    68  		},
    69  		{
    70  			runtimeConfig:    "flowcontrol.apiserver.k8s.io/v1beta3=true",
    71  			errShouldContain: "",
    72  		},
    73  		{
    74  			runtimeConfig:    "flowcontrol.apiserver.k8s.io/v1=true",
    75  			errShouldContain: "",
    76  		},
    77  		{
    78  			runtimeConfig:    "flowcontrol.apiserver.k8s.io/v1=false",
    79  			errShouldContain: conflict,
    80  		},
    81  		{
    82  			runtimeConfig:    "flowcontrol.apiserver.k8s.io/v1beta3=true,flowcontrol.apiserver.k8s.io/v1=false",
    83  			errShouldContain: conflict,
    84  		},
    85  	}
    86  
    87  	for _, test := range tests {
    88  		t.Run(test.runtimeConfig, func(t *testing.T) {
    89  			options := &Options{
    90  				Features: &genericoptions.FeatureOptions{
    91  					EnablePriorityAndFairness: true,
    92  				},
    93  				APIEnablement: genericoptions.NewAPIEnablementOptions(),
    94  			}
    95  			options.APIEnablement.RuntimeConfig.Set(test.runtimeConfig)
    96  
    97  			var errMessageGot string
    98  			if errs := validateAPIPriorityAndFairness(options); len(errs) > 0 {
    99  				errMessageGot = errs[0].Error()
   100  			}
   101  
   102  			switch {
   103  			case len(test.errShouldContain) == 0:
   104  				if len(errMessageGot) > 0 {
   105  					t.Errorf("Expected no error, but got: %q", errMessageGot)
   106  				}
   107  			default:
   108  				if !strings.Contains(errMessageGot, test.errShouldContain) {
   109  					t.Errorf("Expected error message to contain: %q, but got: %q", test.errShouldContain, errMessageGot)
   110  				}
   111  			}
   112  		})
   113  	}
   114  }
   115  
   116  func TestValidateUnknownVersionInteroperabilityProxy(t *testing.T) {
   117  	tests := []struct {
   118  		name                 string
   119  		featureEnabled       bool
   120  		errShouldContain     string
   121  		peerCAFile           string
   122  		peerAdvertiseAddress peerreconcilers.PeerAdvertiseAddress
   123  	}{
   124  		{
   125  			name:             "feature disabled but peerCAFile set",
   126  			featureEnabled:   false,
   127  			peerCAFile:       "foo",
   128  			errShouldContain: "--peer-ca-file requires UnknownVersionInteroperabilityProxy feature to be turned on",
   129  		},
   130  		{
   131  			name:                 "feature disabled but peerAdvertiseIP set",
   132  			featureEnabled:       false,
   133  			peerAdvertiseAddress: peerreconcilers.PeerAdvertiseAddress{PeerAdvertiseIP: "1.2.3.4"},
   134  			errShouldContain:     "--peer-advertise-ip requires UnknownVersionInteroperabilityProxy feature to be turned on",
   135  		},
   136  		{
   137  			name:                 "feature disabled but peerAdvertisePort set",
   138  			featureEnabled:       false,
   139  			peerAdvertiseAddress: peerreconcilers.PeerAdvertiseAddress{PeerAdvertisePort: "1"},
   140  			errShouldContain:     "--peer-advertise-port requires UnknownVersionInteroperabilityProxy feature to be turned on",
   141  		},
   142  	}
   143  
   144  	for _, test := range tests {
   145  		t.Run(test.name, func(t *testing.T) {
   146  			options := &Options{
   147  				PeerCAFile:           test.peerCAFile,
   148  				PeerAdvertiseAddress: test.peerAdvertiseAddress,
   149  			}
   150  			if test.featureEnabled {
   151  				defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.UnknownVersionInteroperabilityProxy, true)()
   152  			}
   153  			var errMessageGot string
   154  			if errs := validateUnknownVersionInteroperabilityProxyFlags(options); len(errs) > 0 {
   155  				errMessageGot = errs[0].Error()
   156  			}
   157  			if !strings.Contains(errMessageGot, test.errShouldContain) {
   158  				t.Errorf("Expected error message to contain: %q, but got: %q", test.errShouldContain, errMessageGot)
   159  			}
   160  
   161  		})
   162  	}
   163  }
   164  
   165  func TestValidateUnknownVersionInteroperabilityProxyFeature(t *testing.T) {
   166  	const conflict = "UnknownVersionInteroperabilityProxy feature requires StorageVersionAPI feature flag to be enabled"
   167  	tests := []struct {
   168  		name            string
   169  		featuresEnabled []featuregate.Feature
   170  	}{
   171  		{
   172  			name:            "enabled: UnknownVersionInteroperabilityProxy, disabled: StorageVersionAPI",
   173  			featuresEnabled: []featuregate.Feature{features.UnknownVersionInteroperabilityProxy},
   174  		},
   175  	}
   176  
   177  	for _, test := range tests {
   178  		t.Run(test.name, func(t *testing.T) {
   179  			for _, feature := range test.featuresEnabled {
   180  				defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, feature, true)()
   181  			}
   182  			var errMessageGot string
   183  			if errs := validateUnknownVersionInteroperabilityProxyFeature(); len(errs) > 0 {
   184  				errMessageGot = errs[0].Error()
   185  			}
   186  			if !strings.Contains(errMessageGot, conflict) {
   187  				t.Errorf("Expected error message to contain: %q, but got: %q", conflict, errMessageGot)
   188  			}
   189  		})
   190  	}
   191  }
   192  
   193  func TestValidateOptions(t *testing.T) {
   194  	testCases := []struct {
   195  		name         string
   196  		options      *Options
   197  		expectErrors bool
   198  	}{
   199  		{
   200  			name:         "validate master count equal 0",
   201  			expectErrors: true,
   202  			options: &Options{
   203  				GenericServerRunOptions: &genericoptions.ServerRunOptions{},
   204  				Etcd:                    &genericoptions.EtcdOptions{},
   205  				SecureServing:           &genericoptions.SecureServingOptionsWithLoopback{},
   206  				Audit:                   &genericoptions.AuditOptions{},
   207  				Admission: &kubeoptions.AdmissionOptions{
   208  					GenericAdmission: &genericoptions.AdmissionOptions{
   209  						EnablePlugins: []string{"foo"},
   210  						Plugins:       kubeapiserveradmission.NewPlugins(),
   211  					},
   212  					PluginNames: []string{"foo"},
   213  				},
   214  				Authentication: &kubeoptions.BuiltInAuthenticationOptions{
   215  					APIAudiences: []string{"bar"},
   216  					ServiceAccounts: &kubeoptions.ServiceAccountAuthenticationOptions{
   217  						Issuers: []string{"baz"},
   218  					},
   219  				},
   220  				APIEnablement:                genericoptions.NewAPIEnablementOptions(),
   221  				Metrics:                      &basemetrics.Options{},
   222  				ServiceAccountSigningKeyFile: "",
   223  				Features:                     &genericoptions.FeatureOptions{},
   224  			},
   225  		},
   226  		{
   227  			name:         "validate token request enable not attempted",
   228  			expectErrors: true,
   229  			options: &Options{
   230  				GenericServerRunOptions: &genericoptions.ServerRunOptions{},
   231  				Etcd:                    &genericoptions.EtcdOptions{},
   232  				SecureServing:           &genericoptions.SecureServingOptionsWithLoopback{},
   233  				Audit:                   &genericoptions.AuditOptions{},
   234  				Admission: &kubeoptions.AdmissionOptions{
   235  					GenericAdmission: &genericoptions.AdmissionOptions{
   236  						EnablePlugins: []string{""},
   237  						Plugins:       kubeapiserveradmission.NewPlugins(),
   238  					},
   239  					PluginNames: []string{""},
   240  				},
   241  				Authentication: &kubeoptions.BuiltInAuthenticationOptions{
   242  					ServiceAccounts: &kubeoptions.ServiceAccountAuthenticationOptions{},
   243  				},
   244  				APIEnablement:                genericoptions.NewAPIEnablementOptions(),
   245  				Metrics:                      &basemetrics.Options{},
   246  				ServiceAccountSigningKeyFile: "",
   247  				Features:                     &genericoptions.FeatureOptions{},
   248  			},
   249  		},
   250  	}
   251  
   252  	for _, tc := range testCases {
   253  		t.Run(tc.name, func(t *testing.T) {
   254  			errs := tc.options.Validate()
   255  			if len(errs) > 0 && !tc.expectErrors {
   256  				t.Errorf("expected no errors, errors found %+v", errs)
   257  			}
   258  
   259  			if len(errs) == 0 && tc.expectErrors {
   260  				t.Errorf("expected errors, no errors found")
   261  			}
   262  		})
   263  	}
   264  }
   265  

View as plain text