kubernetes instance_test 源码
kubernetes instance_test 代码
文件路径:/pkg/controlplane/instance_test.go
/*
Copyright 2014 The Kubernetes Authors.
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.
*/
package controlplane
import (
"context"
"crypto/tls"
"encoding/json"
"io/ioutil"
"net"
"net/http"
"net/http/httptest"
"reflect"
"strings"
"testing"
autoscalingapiv2beta1 "k8s.io/api/autoscaling/v2beta1"
autoscalingapiv2beta2 "k8s.io/api/autoscaling/v2beta2"
batchapiv1beta1 "k8s.io/api/batch/v1beta1"
certificatesapiv1beta1 "k8s.io/api/certificates/v1beta1"
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"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
utilnet "k8s.io/apimachinery/pkg/util/net"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/version"
"k8s.io/apiserver/pkg/authorization/authorizerfactory"
genericapiserver "k8s.io/apiserver/pkg/server"
"k8s.io/apiserver/pkg/server/options"
"k8s.io/apiserver/pkg/server/resourceconfig"
serverstorage "k8s.io/apiserver/pkg/server/storage"
etcd3testing "k8s.io/apiserver/pkg/storage/etcd3/testing"
"k8s.io/client-go/discovery"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
kubeversion "k8s.io/component-base/version"
"k8s.io/kubernetes/pkg/api/legacyscheme"
flowcontrolv1beta2 "k8s.io/kubernetes/pkg/apis/flowcontrol/v1beta2"
"k8s.io/kubernetes/pkg/controlplane/reconcilers"
"k8s.io/kubernetes/pkg/controlplane/storageversionhashdata"
"k8s.io/kubernetes/pkg/kubeapiserver"
kubeletclient "k8s.io/kubernetes/pkg/kubelet/client"
certificatesrest "k8s.io/kubernetes/pkg/registry/certificates/rest"
corerest "k8s.io/kubernetes/pkg/registry/core/rest"
"k8s.io/kubernetes/pkg/registry/registrytest"
netutils "k8s.io/utils/net"
"github.com/stretchr/testify/assert"
)
// setUp is a convenience function for setting up for (most) tests.
func setUp(t *testing.T) (*etcd3testing.EtcdTestServer, Config, *assert.Assertions) {
server, storageConfig := etcd3testing.NewUnsecuredEtcd3TestClientServer(t)
config := &Config{
GenericConfig: genericapiserver.NewConfig(legacyscheme.Codecs),
ExtraConfig: ExtraConfig{
APIResourceConfigSource: DefaultAPIResourceConfigSource(),
APIServerServicePort: 443,
MasterCount: 1,
EndpointReconcilerType: reconcilers.MasterCountReconcilerType,
ServiceIPRange: net.IPNet{IP: netutils.ParseIPSloppy("10.0.0.0"), Mask: net.CIDRMask(24, 32)},
},
}
storageFactoryConfig := kubeapiserver.NewStorageFactoryConfig()
resourceEncoding := resourceconfig.MergeResourceEncodingConfigs(storageFactoryConfig.DefaultResourceEncoding, storageFactoryConfig.ResourceEncodingOverrides)
storageFactory := serverstorage.NewDefaultStorageFactory(*storageConfig, "application/vnd.kubernetes.protobuf", storageFactoryConfig.Serializer, resourceEncoding, DefaultAPIResourceConfigSource(), nil)
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)
if err != nil {
t.Fatal(err)
}
kubeVersion := kubeversion.Get()
config.GenericConfig.Authorization.Authorizer = authorizerfactory.NewAlwaysAllowAuthorizer()
config.GenericConfig.Version = &kubeVersion
config.ExtraConfig.StorageFactory = storageFactory
config.GenericConfig.LoopbackClientConfig = &restclient.Config{APIPath: "/api", ContentConfig: restclient.ContentConfig{NegotiatedSerializer: legacyscheme.Codecs}}
config.GenericConfig.PublicAddress = netutils.ParseIPSloppy("192.168.10.4")
config.GenericConfig.LegacyAPIGroupPrefixes = sets.NewString("/api")
config.ExtraConfig.KubeletClientConfig = kubeletclient.KubeletClientConfig{Port: 10250}
config.ExtraConfig.ProxyTransport = utilnet.SetTransportDefaults(&http.Transport{
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { return nil, nil },
TLSClientConfig: &tls.Config{},
})
// set fake SecureServingInfo because the listener port is needed for the kubernetes service
config.GenericConfig.SecureServing = &genericapiserver.SecureServingInfo{Listener: fakeLocalhost443Listener{}}
clientset, err := kubernetes.NewForConfig(config.GenericConfig.LoopbackClientConfig)
if err != nil {
t.Fatalf("unable to create client set due to %v", err)
}
config.ExtraConfig.VersionedInformers = informers.NewSharedInformerFactory(clientset, config.GenericConfig.LoopbackClientConfig.Timeout)
return server, *config, assert.New(t)
}
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,
}
}
// 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) {
_, etcdserver, apiserverCfg, _ := newInstance(t)
defer etcdserver.Terminate(t)
storageProvider := corerest.LegacyRESTStorageProvider{
StorageFactory: apiserverCfg.ExtraConfig.StorageFactory,
ProxyTransport: apiserverCfg.ExtraConfig.ProxyTransport,
KubeletClientConfig: apiserverCfg.ExtraConfig.KubeletClientConfig,
EventTTL: apiserverCfg.ExtraConfig.EventTTL,
ServiceIPRange: apiserverCfg.ExtraConfig.ServiceIPRange,
ServiceNodePortRange: apiserverCfg.ExtraConfig.ServiceNodePortRange,
LoopbackClientConfig: apiserverCfg.GenericConfig.LoopbackClientConfig,
}
_, apiGroupInfo, err := storageProvider.NewLegacyRESTStorage(serverstorage.NewResourceConfig(), apiserverCfg.GenericConfig.RESTOptionsGetter)
if err != nil {
t.Errorf("failed to create legacy REST storage: %v", err)
}
strategyErrors := registrytest.ValidateStorageStrategies(apiGroupInfo.VersionedResourcesStorageMap["v1"])
for _, err := range strategyErrors {
t.Error(err)
}
}
func TestCertificatesRestStorageStrategies(t *testing.T) {
_, etcdserver, apiserverCfg, _ := newInstance(t)
defer etcdserver.Terminate(t)
certStorageProvider := certificatesrest.RESTStorageProvider{}
apiGroupInfo, err := certStorageProvider.NewRESTStorage(apiserverCfg.ExtraConfig.APIResourceConfigSource, apiserverCfg.GenericConfig.RESTOptionsGetter)
if err != nil {
t.Fatalf("unexpected error from REST storage: %v", err)
}
strategyErrors := registrytest.ValidateStorageStrategies(
apiGroupInfo.VersionedResourcesStorageMap[certificatesapiv1beta1.SchemeGroupVersion.Version])
for _, err := range strategyErrors {
t.Error(err)
}
}
func newInstance(t *testing.T) (*Instance, *etcd3testing.EtcdTestServer, Config, *assert.Assertions) {
etcdserver, config, assert := setUp(t)
apiserver, err := config.Complete().New(genericapiserver.NewEmptyDelegate())
if err != nil {
t.Fatalf("Error in bringing up the master: %v", err)
}
return apiserver, etcdserver, config, assert
}
// TestVersion tests /version
func TestVersion(t *testing.T) {
s, etcdserver, _, _ := newInstance(t)
defer etcdserver.Terminate(t)
req, _ := http.NewRequest("GET", "/version", nil)
resp := httptest.NewRecorder()
s.GenericAPIServer.Handler.ServeHTTP(resp, req)
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)
}
if !reflect.DeepEqual(kubeversion.Get(), info) {
t.Errorf("Expected %#v, Got %#v", kubeversion.Get(), info)
}
}
func decodeResponse(resp *http.Response, obj interface{}) error {
defer resp.Body.Close()
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
if err := json.Unmarshal(data, obj); err != nil {
return err
}
return nil
}
// 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) {
apiserver, etcdserver, _, assert := newInstance(t)
defer etcdserver.Terminate(t)
server := httptest.NewServer(apiserver.GenericAPIServer.Handler.GoRestfulContainer.ServeMux)
// /api exists in release-1.1
resp, err := http.Get(server.URL + "/api")
if err != nil {
t.Errorf("unexpected error: %v", err)
}
apiVersions := metav1.APIVersions{}
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)
}
resourceList := metav1.APIResourceList{}
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)
}
groupList := metav1.APIGroupList{}
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)
}
group := metav1.APIGroup{}
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)
}
resourceList = metav1.APIResourceList{}
assert.NoError(decodeResponse(resp, &resourceList))
assert.Equal(resourceList.APIVersion, "v1")
}
// This test doesn't cover the apiregistration and apiextensions group, as they are installed by other apiservers.
func TestStorageVersionHashes(t *testing.T) {
apiserver, etcdserver, _, _ := newInstance(t)
defer etcdserver.Terminate(t)
server := httptest.NewServer(apiserver.GenericAPIServer.Handler.GoRestfulContainer.ServeMux)
c := &restclient.Config{
Host: server.URL,
APIPath: "/api",
ContentConfig: restclient.ContentConfig{NegotiatedSerializer: legacyscheme.Codecs},
}
discover := discovery.NewDiscoveryClientForConfigOrDie(c)
_, all, err := discover.ServerGroupsAndResources()
if err != nil {
t.Error(err)
}
var count int
apiResources := sets.NewString()
for _, g := range all {
for _, r := range g.APIResources {
apiResources.Insert(g.GroupVersion + "/" + r.Name)
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) {
knownResources := sets.StringKeySet(storageversionhashdata.GVRToStorageVersionHash)
t.Errorf("please remove the redundant entries from GVRToStorageVersionHash: %v", knownResources.Difference(apiResources).List())
}
}
func TestNoAlphaVersionsEnabledByDefault(t *testing.T) {
config := DefaultAPIResourceConfigSource()
for gv, enable := range config.GroupVersionConfigs {
if enable && strings.Contains(gv.Version, "alpha") {
t.Errorf("Alpha API version %s enabled by default", gv.String())
}
}
}
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())
}
}
}
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,
storageapiv1beta1.SchemeGroupVersion.WithResource("csistoragecapacities"): 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{
storageapiv1beta1.SchemeGroupVersion.WithResource("csistoragecapacities").GroupResource(): true,
flowcontrolv1beta2.SchemeGroupVersion.WithResource("flowschemas").GroupResource(): true,
flowcontrolv1beta2.SchemeGroupVersion.WithResource("prioritylevelconfigurations").GroupResource(): true,
}
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)
}
}
相关信息
相关文章
kubernetes import_known_versions 源码
0
赞
热门推荐
-
2、 - 优质文章
-
3、 gate.io
-
7、 golang
-
9、 openharmony
-
10、 Vue中input框自动聚焦