2014-11-02 15:52:31 -05:00
/ *
2016-06-02 20:25:58 -04:00
Copyright 2014 The Kubernetes Authors .
2014-11-02 15:52:31 -05:00
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
2020-09-02 12:08:35 -04:00
package controlplane
2014-11-02 15:52:31 -05:00
import (
2018-05-18 18:14:37 -04:00
"context"
2015-10-09 01:18:16 -04:00
"crypto/tls"
2015-08-20 01:08:26 -04:00
"encoding/json"
2023-05-02 09:08:18 -04:00
"io"
2015-09-03 13:35:04 -04:00
"net"
2015-08-19 14:02:01 -04:00
"net/http"
"net/http/httptest"
2015-08-20 01:08:26 -04:00
"reflect"
2017-09-05 21:51:04 -04:00
"strings"
2014-11-02 15:52:31 -05:00
"testing"
2022-02-07 13:32:01 -05:00
autoscalingapiv2beta1 "k8s.io/api/autoscaling/v2beta1"
autoscalingapiv2beta2 "k8s.io/api/autoscaling/v2beta2"
batchapiv1beta1 "k8s.io/api/batch/v1beta1"
2017-07-18 10:52:42 -04:00
certificatesapiv1beta1 "k8s.io/api/certificates/v1beta1"
2022-02-07 13:32:01 -05:00
discoveryv1beta1 "k8s.io/api/discovery/v1beta1"
eventsv1beta1 "k8s.io/api/events/v1beta1"
nodev1beta1 "k8s.io/api/node/v1beta1"
policyapiv1beta1 "k8s.io/api/policy/v1beta1"
storageapiv1beta1 "k8s.io/api/storage/v1beta1"
2023-03-03 13:49:50 -05:00
extensionsapiserver "k8s.io/apiextensions-apiserver/pkg/apiserver"
2017-01-11 09:09:48 -05:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2019-01-14 22:31:25 -05:00
"k8s.io/apimachinery/pkg/runtime/schema"
2017-01-11 09:09:48 -05:00
utilnet "k8s.io/apimachinery/pkg/util/net"
"k8s.io/apimachinery/pkg/util/sets"
2017-01-16 06:05:15 -05:00
"k8s.io/apimachinery/pkg/version"
2019-01-14 22:31:25 -05:00
"k8s.io/apiserver/pkg/authorization/authorizerfactory"
2023-03-03 13:49:50 -05:00
openapinamer "k8s.io/apiserver/pkg/endpoints/openapi"
2017-02-02 04:25:56 -05:00
genericapiserver "k8s.io/apiserver/pkg/server"
2017-02-11 06:14:34 -05:00
"k8s.io/apiserver/pkg/server/options"
2019-01-14 22:31:25 -05:00
"k8s.io/apiserver/pkg/server/resourceconfig"
2017-02-11 06:26:43 -05:00
serverstorage "k8s.io/apiserver/pkg/server/storage"
2019-07-01 04:38:19 -04:00
etcd3testing "k8s.io/apiserver/pkg/storage/etcd3/testing"
2023-03-03 13:49:50 -05:00
"k8s.io/apiserver/pkg/util/openapi"
2019-01-14 22:31:25 -05:00
"k8s.io/client-go/discovery"
2017-05-01 09:07:46 -04:00
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
2017-01-19 13:27:59 -05:00
restclient "k8s.io/client-go/rest"
2019-09-10 17:42:55 -04:00
kubeversion "k8s.io/component-base/version"
2023-03-03 13:49:50 -05:00
aggregatorscheme "k8s.io/kube-aggregator/pkg/apiserver/scheme"
2017-10-16 07:41:50 -04:00
"k8s.io/kubernetes/pkg/api/legacyscheme"
2023-08-09 06:53:07 -04:00
flowcontrolv1bet3 "k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta3"
2020-09-02 13:47:23 -04:00
"k8s.io/kubernetes/pkg/controlplane/reconcilers"
"k8s.io/kubernetes/pkg/controlplane/storageversionhashdata"
2023-03-03 13:49:50 -05:00
generatedopenapi "k8s.io/kubernetes/pkg/generated/openapi"
2022-07-01 03:20:56 -04:00
"k8s.io/kubernetes/pkg/kubeapiserver"
2020-09-02 13:49:40 -04:00
kubeletclient "k8s.io/kubernetes/pkg/kubelet/client"
2017-07-18 10:52:42 -04:00
certificatesrest "k8s.io/kubernetes/pkg/registry/certificates/rest"
corerest "k8s.io/kubernetes/pkg/registry/core/rest"
"k8s.io/kubernetes/pkg/registry/registrytest"
2021-08-19 19:16:14 -04:00
netutils "k8s.io/utils/net"
2015-09-09 17:36:19 -04:00
"github.com/stretchr/testify/assert"
2014-11-02 15:52:31 -05:00
)
2019-11-05 22:43:20 -05:00
// setUp is a convenience function for setting up for (most) tests.
2019-07-01 04:38:19 -04:00
func setUp ( t * testing . T ) ( * etcd3testing . EtcdTestServer , Config , * assert . Assertions ) {
server , storageConfig := etcd3testing . NewUnsecuredEtcd3TestClientServer ( t )
2015-11-17 08:35:00 -05:00
2016-09-26 07:51:04 -04:00
config := & Config {
2017-10-16 07:41:50 -04:00
GenericConfig : genericapiserver . NewConfig ( legacyscheme . Codecs ) ,
2017-09-06 11:46:05 -04:00
ExtraConfig : ExtraConfig {
APIResourceConfigSource : DefaultAPIResourceConfigSource ( ) ,
APIServerServicePort : 443 ,
MasterCount : 1 ,
2017-09-11 11:13:47 -04:00
EndpointReconcilerType : reconcilers . MasterCountReconcilerType ,
2021-08-19 19:16:14 -04:00
ServiceIPRange : net . IPNet { IP : netutils . ParseIPSloppy ( "10.0.0.0" ) , Mask : net . CIDRMask ( 24 , 32 ) } ,
2017-09-06 11:46:05 -04:00
} ,
2015-11-16 16:46:00 -05:00
}
2016-03-16 10:17:04 -04:00
2022-07-01 03:20:56 -04:00
storageFactoryConfig := kubeapiserver . NewStorageFactoryConfig ( )
2023-06-02 10:52:21 -04:00
storageConfig . StorageObjectCountTracker = config . GenericConfig . StorageObjectCountTracker
2022-07-01 03:20:56 -04:00
resourceEncoding := resourceconfig . MergeResourceEncodingConfigs ( storageFactoryConfig . DefaultResourceEncoding , storageFactoryConfig . ResourceEncodingOverrides )
storageFactory := serverstorage . NewDefaultStorageFactory ( * storageConfig , "application/vnd.kubernetes.protobuf" , storageFactoryConfig . Serializer , resourceEncoding , DefaultAPIResourceConfigSource ( ) , nil )
2018-02-26 10:46:47 -05:00
etcdOptions := options . NewEtcdOptions ( storageConfig )
// unit tests don't need watch cache and it leaks lots of goroutines with etcd testing functions during unit tests
etcdOptions . EnableWatchCache = false
err := etcdOptions . ApplyWithStorageFactoryTo ( storageFactory , config . GenericConfig )
2017-02-11 06:14:34 -05:00
if err != nil {
t . Fatal ( err )
}
2017-01-16 06:05:15 -05:00
kubeVersion := kubeversion . Get ( )
2019-01-14 22:31:25 -05:00
config . GenericConfig . Authorization . Authorizer = authorizerfactory . NewAlwaysAllowAuthorizer ( )
2016-10-17 14:51:59 -04:00
config . GenericConfig . Version = & kubeVersion
2017-09-06 11:46:05 -04:00
config . ExtraConfig . StorageFactory = storageFactory
2017-10-16 07:41:50 -04:00
config . GenericConfig . LoopbackClientConfig = & restclient . Config { APIPath : "/api" , ContentConfig : restclient . ContentConfig { NegotiatedSerializer : legacyscheme . Codecs } }
2021-08-19 19:16:14 -04:00
config . GenericConfig . PublicAddress = netutils . ParseIPSloppy ( "192.168.10.4" )
2016-10-10 14:52:39 -04:00
config . GenericConfig . LegacyAPIGroupPrefixes = sets . NewString ( "/api" )
2017-09-06 11:46:05 -04:00
config . ExtraConfig . KubeletClientConfig = kubeletclient . KubeletClientConfig { Port : 10250 }
config . ExtraConfig . ProxyTransport = utilnet . SetTransportDefaults ( & http . Transport {
2018-05-18 18:14:37 -04:00
DialContext : func ( ctx context . Context , network , addr string ) ( net . Conn , error ) { return nil , nil } ,
2016-10-17 15:16:58 -04:00
TLSClientConfig : & tls . Config { } ,
} )
2015-10-09 01:18:16 -04:00
2018-07-06 13:20:45 -04:00
// set fake SecureServingInfo because the listener port is needed for the kubernetes service
config . GenericConfig . SecureServing = & genericapiserver . SecureServingInfo { Listener : fakeLocalhost443Listener { } }
2023-03-03 13:49:50 -05:00
getOpenAPIDefinitions := openapi . GetOpenAPIDefinitionsWithoutDisabledFeatures ( generatedopenapi . GetOpenAPIDefinitions )
namer := openapinamer . NewDefinitionNamer ( legacyscheme . Scheme , extensionsapiserver . Scheme , aggregatorscheme . Scheme )
config . GenericConfig . OpenAPIV3Config = genericapiserver . DefaultOpenAPIV3Config ( getOpenAPIDefinitions , namer )
2017-05-01 09:07:46 -04:00
clientset , err := kubernetes . NewForConfig ( config . GenericConfig . LoopbackClientConfig )
if err != nil {
t . Fatalf ( "unable to create client set due to %v" , err )
}
2018-08-02 00:11:58 -04:00
config . ExtraConfig . VersionedInformers = informers . NewSharedInformerFactory ( clientset , config . GenericConfig . LoopbackClientConfig . Timeout )
2017-05-01 09:07:46 -04:00
2018-08-02 00:11:58 -04:00
return server , * config , assert . New ( t )
2016-04-07 18:34:40 -04:00
}
2018-07-06 13:20:45 -04:00
type fakeLocalhost443Listener struct { }
func ( fakeLocalhost443Listener ) Accept ( ) ( net . Conn , error ) {
return nil , nil
}
func ( fakeLocalhost443Listener ) Close ( ) error {
return nil
}
func ( fakeLocalhost443Listener ) Addr ( ) net . Addr {
return & net . TCPAddr {
IP : net . IPv4 ( 127 , 0 , 0 , 1 ) ,
Port : 443 ,
}
}
2017-07-18 10:52:42 -04:00
// TestLegacyRestStorageStrategies ensures that all Storage objects which are using the generic registry Store have
// their various strategies properly wired up. This surfaced as a bug where strategies defined Export functions, but
// they were never used outside of unit tests because the export strategies were not assigned inside the Store.
func TestLegacyRestStorageStrategies ( t * testing . T ) {
2020-09-24 16:30:08 -04:00
_ , etcdserver , apiserverCfg , _ := newInstance ( t )
2017-08-15 23:18:06 -04:00
defer etcdserver . Terminate ( t )
2023-07-04 06:58:21 -04:00
storageProvider , err := corerest . New ( corerest . Config {
GenericConfig : corerest . GenericConfig {
2023-07-03 06:33:28 -04:00
StorageFactory : apiserverCfg . ExtraConfig . StorageFactory ,
EventTTL : apiserverCfg . ExtraConfig . EventTTL ,
LoopbackClientConfig : apiserverCfg . GenericConfig . LoopbackClientConfig ,
Informers : apiserverCfg . ExtraConfig . VersionedInformers ,
} ,
2023-07-04 13:04:20 -04:00
Proxy : corerest . ProxyConfig {
Transport : apiserverCfg . ExtraConfig . ProxyTransport ,
KubeletClientConfig : apiserverCfg . ExtraConfig . KubeletClientConfig ,
} ,
Services : corerest . ServicesConfig {
ClusterIPRange : apiserverCfg . ExtraConfig . ServiceIPRange ,
NodePortRange : apiserverCfg . ExtraConfig . ServiceNodePortRange ,
} ,
2023-07-04 06:58:21 -04:00
} )
if err != nil {
t . Fatalf ( "unexpected error from REST storage: %v" , err )
2017-07-18 10:52:42 -04:00
}
2023-07-03 06:36:42 -04:00
apiGroupInfo , err := storageProvider . NewRESTStorage ( serverstorage . NewResourceConfig ( ) , apiserverCfg . GenericConfig . RESTOptionsGetter )
2017-07-18 10:52:42 -04:00
if err != nil {
t . Errorf ( "failed to create legacy REST storage: %v" , err )
}
2021-01-22 09:21:56 -05:00
strategyErrors := registrytest . ValidateStorageStrategies ( apiGroupInfo . VersionedResourcesStorageMap [ "v1" ] )
2017-07-18 10:52:42 -04:00
for _ , err := range strategyErrors {
t . Error ( err )
}
}
func TestCertificatesRestStorageStrategies ( t * testing . T ) {
2020-09-24 16:30:08 -04:00
_ , etcdserver , apiserverCfg , _ := newInstance ( t )
2017-08-15 23:18:06 -04:00
defer etcdserver . Terminate ( t )
2017-07-18 10:52:42 -04:00
certStorageProvider := certificatesrest . RESTStorageProvider { }
2022-02-21 17:23:19 -05:00
apiGroupInfo , err := certStorageProvider . NewRESTStorage ( apiserverCfg . ExtraConfig . APIResourceConfigSource , apiserverCfg . GenericConfig . RESTOptionsGetter )
2019-08-12 16:55:33 -04:00
if err != nil {
t . Fatalf ( "unexpected error from REST storage: %v" , err )
}
2017-07-18 10:52:42 -04:00
strategyErrors := registrytest . ValidateStorageStrategies (
2021-01-22 09:21:56 -05:00
apiGroupInfo . VersionedResourcesStorageMap [ certificatesapiv1beta1 . SchemeGroupVersion . Version ] )
2017-07-18 10:52:42 -04:00
for _ , err := range strategyErrors {
t . Error ( err )
}
}
2020-09-24 16:30:08 -04:00
func newInstance ( t * testing . T ) ( * Instance , * etcd3testing . EtcdTestServer , Config , * assert . Assertions ) {
2018-08-02 00:11:58 -04:00
etcdserver , config , assert := setUp ( t )
2016-04-07 18:34:40 -04:00
2020-09-24 16:30:08 -04:00
apiserver , err := config . Complete ( ) . New ( genericapiserver . NewEmptyDelegate ( ) )
2016-04-07 18:34:40 -04:00
if err != nil {
t . Fatalf ( "Error in bringing up the master: %v" , err )
}
2020-09-24 16:30:08 -04:00
return apiserver , etcdserver , config , assert
2016-04-07 18:34:40 -04:00
}
2016-09-06 07:20:36 -04:00
// TestVersion tests /version
func TestVersion ( t * testing . T ) {
2020-09-24 16:30:08 -04:00
s , etcdserver , _ , _ := newInstance ( t )
2016-09-06 07:20:36 -04:00
defer etcdserver . Terminate ( t )
req , _ := http . NewRequest ( "GET" , "/version" , nil )
resp := httptest . NewRecorder ( )
2017-03-09 14:39:56 -05:00
s . GenericAPIServer . Handler . ServeHTTP ( resp , req )
2016-09-06 07:20:36 -04:00
if resp . Code != 200 {
t . Fatalf ( "expected http 200, got: %d" , resp . Code )
}
var info version . Info
err := json . NewDecoder ( resp . Body ) . Decode ( & info )
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
2017-01-16 06:05:15 -05:00
if ! reflect . DeepEqual ( kubeversion . Get ( ) , info ) {
t . Errorf ( "Expected %#v, Got %#v" , kubeversion . Get ( ) , info )
2016-09-06 07:20:36 -04:00
}
}
2016-09-29 13:01:49 -04:00
func decodeResponse ( resp * http . Response , obj interface { } ) error {
defer resp . Body . Close ( )
2023-05-02 09:08:18 -04:00
data , err := io . ReadAll ( resp . Body )
2016-09-29 13:01:49 -04:00
if err != nil {
return err
}
if err := json . Unmarshal ( data , obj ) ; err != nil {
return err
}
return nil
}
2016-02-11 20:03:43 -05:00
// Because we need to be backwards compatible with release 1.1, at endpoints
// that exist in release 1.1, the responses should have empty APIVersion.
func TestAPIVersionOfDiscoveryEndpoints ( t * testing . T ) {
2020-09-24 16:30:08 -04:00
apiserver , etcdserver , _ , assert := newInstance ( t )
2016-02-11 20:03:43 -05:00
defer etcdserver . Terminate ( t )
2020-09-24 16:30:08 -04:00
server := httptest . NewServer ( apiserver . GenericAPIServer . Handler . GoRestfulContainer . ServeMux )
2016-02-11 20:03:43 -05:00
// /api exists in release-1.1
resp , err := http . Get ( server . URL + "/api" )
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
2016-12-03 13:57:26 -05:00
apiVersions := metav1 . APIVersions { }
2016-02-11 20:03:43 -05:00
assert . NoError ( decodeResponse ( resp , & apiVersions ) )
assert . Equal ( apiVersions . APIVersion , "" )
// /api/v1 exists in release-1.1
resp , err = http . Get ( server . URL + "/api/v1" )
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
2016-12-03 13:57:26 -05:00
resourceList := metav1 . APIResourceList { }
2016-02-11 20:03:43 -05:00
assert . NoError ( decodeResponse ( resp , & resourceList ) )
assert . Equal ( resourceList . APIVersion , "" )
// /apis exists in release-1.1
resp , err = http . Get ( server . URL + "/apis" )
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
2016-12-03 13:57:26 -05:00
groupList := metav1 . APIGroupList { }
2016-02-11 20:03:43 -05:00
assert . NoError ( decodeResponse ( resp , & groupList ) )
assert . Equal ( groupList . APIVersion , "" )
// /apis/autoscaling doesn't exist in release-1.1, so the APIVersion field
// should be non-empty in the results returned by the server.
resp , err = http . Get ( server . URL + "/apis/autoscaling" )
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
2021-03-25 13:10:07 -04:00
group := metav1 . APIGroup { }
2016-02-11 20:03:43 -05:00
assert . NoError ( decodeResponse ( resp , & group ) )
assert . Equal ( group . APIVersion , "v1" )
// apis/autoscaling/v1 doesn't exist in release-1.1, so the APIVersion field
// should be non-empty in the results returned by the server.
resp , err = http . Get ( server . URL + "/apis/autoscaling/v1" )
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
2016-12-03 13:57:26 -05:00
resourceList = metav1 . APIResourceList { }
2016-02-11 20:03:43 -05:00
assert . NoError ( decodeResponse ( resp , & resourceList ) )
assert . Equal ( resourceList . APIVersion , "v1" )
}
2017-09-05 21:51:04 -04:00
2019-01-14 22:31:25 -05:00
// This test doesn't cover the apiregistration and apiextensions group, as they are installed by other apiservers.
func TestStorageVersionHashes ( t * testing . T ) {
2020-09-24 16:30:08 -04:00
apiserver , etcdserver , _ , _ := newInstance ( t )
2019-01-14 22:31:25 -05:00
defer etcdserver . Terminate ( t )
2020-09-24 16:30:08 -04:00
server := httptest . NewServer ( apiserver . GenericAPIServer . Handler . GoRestfulContainer . ServeMux )
2019-01-14 22:31:25 -05:00
c := & restclient . Config {
Host : server . URL ,
APIPath : "/api" ,
ContentConfig : restclient . ContentConfig { NegotiatedSerializer : legacyscheme . Codecs } ,
}
2023-01-09 12:51:19 -05:00
discover := discovery . NewDiscoveryClientForConfigOrDie ( c ) . WithLegacy ( )
2021-12-22 03:14:09 -05:00
_ , all , err := discover . ServerGroupsAndResources ( )
2019-01-14 22:31:25 -05:00
if err != nil {
t . Error ( err )
}
var count int
2021-03-25 13:10:07 -04:00
apiResources := sets . NewString ( )
2019-01-14 22:31:25 -05:00
for _ , g := range all {
for _ , r := range g . APIResources {
2021-03-25 13:10:07 -04:00
apiResources . Insert ( g . GroupVersion + "/" + r . Name )
2019-01-14 22:31:25 -05:00
if strings . Contains ( r . Name , "/" ) ||
storageversionhashdata . NoStorageVersionHash . Has ( g . GroupVersion + "/" + r . Name ) {
if r . StorageVersionHash != "" {
t . Errorf ( "expect resource %s/%s to have empty storageVersionHash, got hash %q" , g . GroupVersion , r . Name , r . StorageVersionHash )
}
continue
}
if r . StorageVersionHash == "" {
t . Errorf ( "expect the storageVersionHash of %s/%s to exist" , g . GroupVersion , r . Name )
continue
}
// Uncomment the following line if you want to update storageversionhash/data.go
// fmt.Printf("\"%s/%s\": \"%s\",\n", g.GroupVersion, r.Name, r.StorageVersionHash)
expected := storageversionhashdata . GVRToStorageVersionHash [ g . GroupVersion + "/" + r . Name ]
if r . StorageVersionHash != expected {
t . Errorf ( "expect the storageVersionHash of %s/%s to be %q, got %q" , g . GroupVersion , r . Name , expected , r . StorageVersionHash )
}
count ++
}
}
if count != len ( storageversionhashdata . GVRToStorageVersionHash ) {
2021-03-25 13:10:07 -04:00
knownResources := sets . StringKeySet ( storageversionhashdata . GVRToStorageVersionHash )
t . Errorf ( "please remove the redundant entries from GVRToStorageVersionHash: %v" , knownResources . Difference ( apiResources ) . List ( ) )
2019-01-14 22:31:25 -05:00
}
}
2017-09-05 21:51:04 -04:00
func TestNoAlphaVersionsEnabledByDefault ( t * testing . T ) {
config := DefaultAPIResourceConfigSource ( )
2018-01-27 02:18:25 -05:00
for gv , enable := range config . GroupVersionConfigs {
if enable && strings . Contains ( gv . Version , "alpha" ) {
2017-09-05 21:51:04 -04:00
t . Errorf ( "Alpha API version %s enabled by default" , gv . String ( ) )
}
}
2022-09-12 13:09:41 -04:00
for gvr , enabled := range config . ResourceConfigs {
if ! strings . Contains ( gvr . Version , "alpha" ) || ! enabled {
continue
}
// we have enabled an alpha api by resource {g,v,r}, we also expect the
// alpha api by version {g,v} to be disabled. This is so a programmer
// remembers to add the new alpha version to alphaAPIGroupVersionsDisabledByDefault.
gr := gvr . GroupVersion ( )
if enabled , found := config . GroupVersionConfigs [ gr ] ; ! found || enabled {
t . Errorf ( "Alpha API version %q should be disabled by default" , gr . String ( ) )
}
}
2017-09-05 21:51:04 -04:00
}
2022-02-07 13:32:01 -05:00
func TestNoBetaVersionsEnabledByDefault ( t * testing . T ) {
config := DefaultAPIResourceConfigSource ( )
for gv , enable := range config . GroupVersionConfigs {
if enable && strings . Contains ( gv . Version , "beta" ) {
t . Errorf ( "Beta API version %s enabled by default" , gv . String ( ) )
}
}
2022-09-12 13:09:41 -04:00
for gvr , enabled := range config . ResourceConfigs {
if ! strings . Contains ( gvr . Version , "beta" ) || ! enabled {
continue
}
// we have enabled a beta api by resource {g,v,r}, we also expect the
// beta api by version {g,v} to be disabled. This is so a programmer
// remembers to add the new beta version to betaAPIGroupVersionsDisabledByDefault.
gr := gvr . GroupVersion ( )
if enabled , found := config . GroupVersionConfigs [ gr ] ; ! found || enabled {
t . Errorf ( "Beta API version %q should be disabled by default" , gr . String ( ) )
}
}
}
func TestDefaultVars ( t * testing . T ) {
// stableAPIGroupVersionsEnabledByDefault should not contain beta or alpha
for i := range stableAPIGroupVersionsEnabledByDefault {
gv := stableAPIGroupVersionsEnabledByDefault [ i ]
if strings . Contains ( gv . Version , "beta" ) || strings . Contains ( gv . Version , "alpha" ) {
t . Errorf ( "stableAPIGroupVersionsEnabledByDefault should contain stable version, but found: %q" , gv . String ( ) )
}
}
// legacyBetaEnabledByDefaultResources should contain only beta version
for i := range legacyBetaEnabledByDefaultResources {
gv := legacyBetaEnabledByDefaultResources [ i ]
if ! strings . Contains ( gv . Version , "beta" ) {
t . Errorf ( "legacyBetaEnabledByDefaultResources should contain beta version, but found: %q" , gv . String ( ) )
}
}
// betaAPIGroupVersionsDisabledByDefault should contain only beta version
for i := range betaAPIGroupVersionsDisabledByDefault {
gv := betaAPIGroupVersionsDisabledByDefault [ i ]
if ! strings . Contains ( gv . Version , "beta" ) {
t . Errorf ( "betaAPIGroupVersionsDisabledByDefault should contain beta version, but found: %q" , gv . String ( ) )
}
}
// alphaAPIGroupVersionsDisabledByDefault should contain only alpha version
for i := range alphaAPIGroupVersionsDisabledByDefault {
gv := alphaAPIGroupVersionsDisabledByDefault [ i ]
if ! strings . Contains ( gv . Version , "alpha" ) {
t . Errorf ( "alphaAPIGroupVersionsDisabledByDefault should contain alpha version, but found: %q" , gv . String ( ) )
}
}
2022-02-07 13:32:01 -05:00
}
func TestNewBetaResourcesEnabledByDefault ( t * testing . T ) {
// legacyEnabledBetaResources is nearly a duplication from elsewhere. This is intentional. These types already have
// GA equivalents available and should therefore never have a beta enabled by default again.
legacyEnabledBetaResources := map [ schema . GroupVersionResource ] bool {
autoscalingapiv2beta1 . SchemeGroupVersion . WithResource ( "horizontalpodautoscalers" ) : true ,
autoscalingapiv2beta2 . SchemeGroupVersion . WithResource ( "horizontalpodautoscalers" ) : true ,
batchapiv1beta1 . SchemeGroupVersion . WithResource ( "cronjobs" ) : true ,
discoveryv1beta1 . SchemeGroupVersion . WithResource ( "endpointslices" ) : true ,
eventsv1beta1 . SchemeGroupVersion . WithResource ( "events" ) : true ,
nodev1beta1 . SchemeGroupVersion . WithResource ( "runtimeclasses" ) : true ,
policyapiv1beta1 . SchemeGroupVersion . WithResource ( "poddisruptionbudgets" ) : true ,
policyapiv1beta1 . SchemeGroupVersion . WithResource ( "podsecuritypolicies" ) : true ,
storageapiv1beta1 . SchemeGroupVersion . WithResource ( "csinodes" ) : true ,
}
// legacyBetaResourcesWithoutStableEquivalents contains those groupresources that were enabled by default as beta
// before we changed that policy and do not have stable versions. These resources are allowed to have additional
// beta versions enabled by default. Nothing new should be added here. There are no future exceptions because there
// are no more beta resources enabled by default.
legacyBetaResourcesWithoutStableEquivalents := map [ schema . GroupResource ] bool {
2023-08-09 06:53:07 -04:00
flowcontrolv1bet3 . SchemeGroupVersion . WithResource ( "flowschemas" ) . GroupResource ( ) : true ,
flowcontrolv1bet3 . SchemeGroupVersion . WithResource ( "prioritylevelconfigurations" ) . GroupResource ( ) : true ,
2022-02-07 13:32:01 -05:00
}
config := DefaultAPIResourceConfigSource ( )
for gvr , enable := range config . ResourceConfigs {
if ! strings . Contains ( gvr . Version , "beta" ) {
continue // only check beta things
}
if ! enable {
continue // only check things that are enabled
}
if legacyEnabledBetaResources [ gvr ] {
continue // this is a legacy beta resource
}
if legacyBetaResourcesWithoutStableEquivalents [ gvr . GroupResource ( ) ] {
continue // this is another beta of a legacy beta resource with no stable equivalent
}
t . Errorf ( "no new beta resources can be enabled by default, see https://github.com/kubernetes/enhancements/blob/0ad0fc8269165ca300d05ca51c7ce190a79976a5/keps/sig-architecture/3136-beta-apis-off-by-default/README.md: %v" , gvr )
}
}