feat: kubesphere 4.0 (#6115)
* feat: kubesphere 4.0 Signed-off-by: ci-bot <ci-bot@kubesphere.io> * feat: kubesphere 4.0 Signed-off-by: ci-bot <ci-bot@kubesphere.io> --------- Signed-off-by: ci-bot <ci-bot@kubesphere.io> Co-authored-by: ks-ci-bot <ks-ci-bot@example.com> Co-authored-by: joyceliu <joyceliu@yunify.com>
This commit is contained in:
committed by
GitHub
parent
b5015ec7b9
commit
447a51f08b
203
vendor/k8s.io/apiserver/pkg/server/genericapiserver.go
generated
vendored
203
vendor/k8s.io/apiserver/pkg/server/genericapiserver.go
generated
vendored
@@ -17,6 +17,8 @@ limitations under the License.
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
gpath "path"
|
||||
@@ -26,12 +28,15 @@ import (
|
||||
|
||||
systemd "github.com/coreos/go-systemd/v22/daemon"
|
||||
|
||||
"golang.org/x/time/rate"
|
||||
apidiscoveryv2beta1 "k8s.io/api/apidiscovery/v2beta1"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apimachinery/pkg/util/managedfields"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
utilwaitgroup "k8s.io/apimachinery/pkg/util/waitgroup"
|
||||
"k8s.io/apimachinery/pkg/version"
|
||||
@@ -41,22 +46,19 @@ import (
|
||||
genericapi "k8s.io/apiserver/pkg/endpoints"
|
||||
"k8s.io/apiserver/pkg/endpoints/discovery"
|
||||
discoveryendpoint "k8s.io/apiserver/pkg/endpoints/discovery/aggregated"
|
||||
"k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager"
|
||||
"k8s.io/apiserver/pkg/features"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
"k8s.io/apiserver/pkg/server/healthz"
|
||||
"k8s.io/apiserver/pkg/server/routes"
|
||||
"k8s.io/apiserver/pkg/storageversion"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
utilopenapi "k8s.io/apiserver/pkg/util/openapi"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/klog/v2"
|
||||
openapibuilder2 "k8s.io/kube-openapi/pkg/builder"
|
||||
openapibuilder3 "k8s.io/kube-openapi/pkg/builder3"
|
||||
openapicommon "k8s.io/kube-openapi/pkg/common"
|
||||
"k8s.io/kube-openapi/pkg/handler"
|
||||
"k8s.io/kube-openapi/pkg/handler3"
|
||||
openapiutil "k8s.io/kube-openapi/pkg/util"
|
||||
openapiproto "k8s.io/kube-openapi/pkg/util/proto"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
"k8s.io/utils/clock"
|
||||
)
|
||||
@@ -88,7 +90,7 @@ type APIGroupInfo struct {
|
||||
|
||||
// StaticOpenAPISpec is the spec derived from the definitions of all resources installed together.
|
||||
// It is set during InstallAPIGroups, InstallAPIGroup, and InstallLegacyAPIGroup.
|
||||
StaticOpenAPISpec *spec.Swagger
|
||||
StaticOpenAPISpec map[string]*spec.Schema
|
||||
}
|
||||
|
||||
func (a *APIGroupInfo) destroyStorage() {
|
||||
@@ -136,6 +138,10 @@ type GenericAPIServer struct {
|
||||
// Handler holds the handlers being used by this API server
|
||||
Handler *APIServerHandler
|
||||
|
||||
// UnprotectedDebugSocket is used to serve pprof information in a unix-domain socket. This socket is
|
||||
// not protected by authentication/authorization.
|
||||
UnprotectedDebugSocket *routes.DebugSocket
|
||||
|
||||
// listedPathProvider is a lister which provides the set of paths to show at /
|
||||
listedPathProvider routes.ListedPathProvider
|
||||
|
||||
@@ -152,7 +158,7 @@ type GenericAPIServer struct {
|
||||
openAPIConfig *openapicommon.Config
|
||||
|
||||
// Enable swagger and/or OpenAPI V3 if these configs are non-nil.
|
||||
openAPIV3Config *openapicommon.Config
|
||||
openAPIV3Config *openapicommon.OpenAPIV3Config
|
||||
|
||||
// SkipOpenAPIInstallation indicates not to install the OpenAPI handler
|
||||
// during PrepareRun.
|
||||
@@ -214,8 +220,14 @@ type GenericAPIServer struct {
|
||||
// delegationTarget is the next delegate in the chain. This is never nil.
|
||||
delegationTarget DelegationTarget
|
||||
|
||||
// HandlerChainWaitGroup allows you to wait for all chain handlers finish after the server shutdown.
|
||||
HandlerChainWaitGroup *utilwaitgroup.SafeWaitGroup
|
||||
// NonLongRunningRequestWaitGroup allows you to wait for all chain
|
||||
// handlers associated with non long-running requests
|
||||
// to complete while the server is shuting down.
|
||||
NonLongRunningRequestWaitGroup *utilwaitgroup.SafeWaitGroup
|
||||
// WatchRequestWaitGroup allows us to wait for all chain
|
||||
// handlers associated with active watch requests to
|
||||
// complete while the server is shuting down.
|
||||
WatchRequestWaitGroup *utilwaitgroup.RateLimitedSafeWaitGroup
|
||||
|
||||
// ShutdownDelayDuration allows to block shutdown for some time, e.g. until endpoints pointing to this API server
|
||||
// have converged on all node. During this time, the API server keeps serving, /healthz will return 200,
|
||||
@@ -255,6 +267,23 @@ type GenericAPIServer struct {
|
||||
// If enabled, after ShutdownDelayDuration elapses, any incoming request is
|
||||
// rejected with a 429 status code and a 'Retry-After' response.
|
||||
ShutdownSendRetryAfter bool
|
||||
|
||||
// ShutdownWatchTerminationGracePeriod, if set to a positive value,
|
||||
// is the maximum duration the apiserver will wait for all active
|
||||
// watch request(s) to drain.
|
||||
// Once this grace period elapses, the apiserver will no longer
|
||||
// wait for any active watch request(s) in flight to drain, it will
|
||||
// proceed to the next step in the graceful server shutdown process.
|
||||
// If set to a positive value, the apiserver will keep track of the
|
||||
// number of active watch request(s) in flight and during shutdown
|
||||
// it will wait, at most, for the specified duration and allow these
|
||||
// active watch requests to drain with some rate limiting in effect.
|
||||
// The default is zero, which implies the apiserver will not keep
|
||||
// track of active watch request(s) in flight and will not wait
|
||||
// for them to drain, this maintains backward compatibility.
|
||||
// This grace period is orthogonal to other grace periods, and
|
||||
// it is not overridden by any other grace period.
|
||||
ShutdownWatchTerminationGracePeriod time.Duration
|
||||
}
|
||||
|
||||
// DelegationTarget is an interface which allows for composition of API servers with top level handling that works
|
||||
@@ -401,11 +430,9 @@ func (s *GenericAPIServer) PrepareRun() preparedGenericAPIServer {
|
||||
}
|
||||
|
||||
if s.openAPIV3Config != nil && !s.skipOpenAPIInstallation {
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.OpenAPIV3) {
|
||||
s.OpenAPIV3VersionedService = routes.OpenAPI{
|
||||
Config: s.openAPIV3Config,
|
||||
}.InstallV3(s.Handler.GoRestfulContainer, s.Handler.NonGoRestfulMux)
|
||||
}
|
||||
s.OpenAPIV3VersionedService = routes.OpenAPI{
|
||||
V3Config: s.openAPIV3Config,
|
||||
}.InstallV3(s.Handler.GoRestfulContainer, s.Handler.NonGoRestfulMux)
|
||||
}
|
||||
|
||||
s.installHealthz()
|
||||
@@ -442,23 +469,27 @@ func (s *GenericAPIServer) PrepareRun() preparedGenericAPIServer {
|
||||
// | NotAcceptingNewRequest (notAcceptingNewRequestCh)
|
||||
// | |
|
||||
// | |
|
||||
// | |---------------------------------------------------------|
|
||||
// | | | | |
|
||||
// | [without [with | |
|
||||
// | ShutdownSendRetryAfter] ShutdownSendRetryAfter] | |
|
||||
// | | | | |
|
||||
// | | ---------------| |
|
||||
// | | | |
|
||||
// | | (HandlerChainWaitGroup::Wait) |
|
||||
// | | | |
|
||||
// | | InFlightRequestsDrained (drainedCh) |
|
||||
// | | | |
|
||||
// | ----------------------------------------|-----------------|
|
||||
// | | |
|
||||
// | |----------------------------------------------------------------------------------|
|
||||
// | | | | |
|
||||
// | [without [with | |
|
||||
// | ShutdownSendRetryAfter] ShutdownSendRetryAfter] | |
|
||||
// | | | | |
|
||||
// | | ---------------| |
|
||||
// | | | |
|
||||
// | | |----------------|-----------------------| |
|
||||
// | | | | |
|
||||
// | | (NonLongRunningRequestWaitGroup::Wait) (WatchRequestWaitGroup::Wait) |
|
||||
// | | | | |
|
||||
// | | |------------------|---------------------| |
|
||||
// | | | |
|
||||
// | | InFlightRequestsDrained (drainedCh) |
|
||||
// | | | |
|
||||
// | |-------------------|---------------------|----------------------------------------|
|
||||
// | | |
|
||||
// | stopHttpServerCh (AuditBackend::Shutdown())
|
||||
// | |
|
||||
// | |
|
||||
// | listenerStoppedCh
|
||||
// | |
|
||||
// | |
|
||||
// | HTTPServerStoppedListening (httpServerStoppedListeningCh)
|
||||
func (s preparedGenericAPIServer) Run(stopCh <-chan struct{}) error {
|
||||
delayedStopCh := s.lifecycleSignals.AfterShutdownDelayDuration
|
||||
@@ -467,6 +498,14 @@ func (s preparedGenericAPIServer) Run(stopCh <-chan struct{}) error {
|
||||
// Clean up resources on shutdown.
|
||||
defer s.Destroy()
|
||||
|
||||
// If UDS profiling is enabled, start a local http server listening on that socket
|
||||
if s.UnprotectedDebugSocket != nil {
|
||||
go func() {
|
||||
defer utilruntime.HandleCrash()
|
||||
klog.Error(s.UnprotectedDebugSocket.Run(stopCh))
|
||||
}()
|
||||
}
|
||||
|
||||
// spawn a new goroutine for closing the MuxAndDiscoveryComplete signal
|
||||
// registration happens during construction of the generic api server
|
||||
// the last server in the chain aggregates signals from the previous instances
|
||||
@@ -509,7 +548,7 @@ func (s preparedGenericAPIServer) Run(stopCh <-chan struct{}) error {
|
||||
// net/http waits for 1s for the peer to respond to a GO_AWAY frame, so
|
||||
// we should wait for a minimum of 2s
|
||||
shutdownTimeout = 2 * time.Second
|
||||
klog.V(1).InfoS("[graceful-termination] using HTTP Server shutdown timeout", "ShutdownTimeout", shutdownTimeout)
|
||||
klog.V(1).InfoS("[graceful-termination] using HTTP Server shutdown timeout", "shutdownTimeout", shutdownTimeout)
|
||||
}
|
||||
|
||||
notAcceptingNewRequestCh := s.lifecycleSignals.NotAcceptingNewRequest
|
||||
@@ -563,15 +602,17 @@ func (s preparedGenericAPIServer) Run(stopCh <-chan struct{}) error {
|
||||
<-preShutdownHooksHasStoppedCh.Signaled()
|
||||
}()
|
||||
|
||||
// wait for all in-flight non-long running requests to finish
|
||||
nonLongRunningRequestDrainedCh := make(chan struct{})
|
||||
go func() {
|
||||
defer klog.V(1).InfoS("[graceful-termination] shutdown event", "name", drainedCh.Name())
|
||||
defer drainedCh.Signal()
|
||||
defer close(nonLongRunningRequestDrainedCh)
|
||||
defer klog.V(1).Info("[graceful-termination] in-flight non long-running request(s) have drained")
|
||||
|
||||
// wait for the delayed stopCh before closing the handler chain (it rejects everything after Wait has been called).
|
||||
<-notAcceptingNewRequestCh.Signaled()
|
||||
|
||||
// Wait for all requests to finish, which are bounded by the RequestTimeout variable.
|
||||
// once HandlerChainWaitGroup.Wait is invoked, the apiserver is
|
||||
// once NonLongRunningRequestWaitGroup.Wait is invoked, the apiserver is
|
||||
// expected to reject any incoming request with a {503, Retry-After}
|
||||
// response via the WithWaitGroup filter. On the contrary, we observe
|
||||
// that incoming request(s) get a 'connection refused' error, this is
|
||||
@@ -583,7 +624,48 @@ func (s preparedGenericAPIServer) Run(stopCh <-chan struct{}) error {
|
||||
// 'Server.Shutdown' will be invoked only after in-flight requests
|
||||
// have been drained.
|
||||
// TODO: can we consolidate these two modes of graceful termination?
|
||||
s.HandlerChainWaitGroup.Wait()
|
||||
s.NonLongRunningRequestWaitGroup.Wait()
|
||||
}()
|
||||
|
||||
// wait for all in-flight watches to finish
|
||||
activeWatchesDrainedCh := make(chan struct{})
|
||||
go func() {
|
||||
defer close(activeWatchesDrainedCh)
|
||||
|
||||
<-notAcceptingNewRequestCh.Signaled()
|
||||
if s.ShutdownWatchTerminationGracePeriod <= time.Duration(0) {
|
||||
klog.V(1).InfoS("[graceful-termination] not going to wait for active watch request(s) to drain")
|
||||
return
|
||||
}
|
||||
|
||||
// Wait for all active watches to finish
|
||||
grace := s.ShutdownWatchTerminationGracePeriod
|
||||
activeBefore, activeAfter, err := s.WatchRequestWaitGroup.Wait(func(count int) (utilwaitgroup.RateLimiter, context.Context, context.CancelFunc) {
|
||||
qps := float64(count) / grace.Seconds()
|
||||
// TODO: we don't want the QPS (max requests drained per second) to
|
||||
// get below a certain floor value, since we want the server to
|
||||
// drain the active watch requests as soon as possible.
|
||||
// For now, it's hard coded to 200, and it is subject to change
|
||||
// based on the result from the scale testing.
|
||||
if qps < 200 {
|
||||
qps = 200
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), grace)
|
||||
// We don't expect more than one token to be consumed
|
||||
// in a single Wait call, so setting burst to 1.
|
||||
return rate.NewLimiter(rate.Limit(qps), 1), ctx, cancel
|
||||
})
|
||||
klog.V(1).InfoS("[graceful-termination] active watch request(s) have drained",
|
||||
"duration", grace, "activeWatchesBefore", activeBefore, "activeWatchesAfter", activeAfter, "error", err)
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer klog.V(1).InfoS("[graceful-termination] shutdown event", "name", drainedCh.Name())
|
||||
defer drainedCh.Signal()
|
||||
|
||||
<-nonLongRunningRequestDrainedCh
|
||||
<-activeWatchesDrainedCh
|
||||
}()
|
||||
|
||||
klog.V(1).Info("[graceful-termination] waiting for shutdown to be initiated")
|
||||
@@ -653,7 +735,7 @@ func (s preparedGenericAPIServer) NonBlockingRun(stopCh <-chan struct{}, shutdow
|
||||
}
|
||||
|
||||
// installAPIResources is a private method for installing the REST storage backing each api groupversionresource
|
||||
func (s *GenericAPIServer) installAPIResources(apiPrefix string, apiGroupInfo *APIGroupInfo, openAPIModels openapiproto.Models) error {
|
||||
func (s *GenericAPIServer) installAPIResources(apiPrefix string, apiGroupInfo *APIGroupInfo, typeConverter managedfields.TypeConverter) error {
|
||||
var resourceInfos []*storageversion.ResourceInfo
|
||||
for _, groupVersion := range apiGroupInfo.PrioritizedVersions {
|
||||
if len(apiGroupInfo.VersionedResourcesStorageMap[groupVersion.Version]) == 0 {
|
||||
@@ -668,16 +750,7 @@ func (s *GenericAPIServer) installAPIResources(apiPrefix string, apiGroupInfo *A
|
||||
if apiGroupInfo.OptionsExternalVersion != nil {
|
||||
apiGroupVersion.OptionsExternalVersion = apiGroupInfo.OptionsExternalVersion
|
||||
}
|
||||
apiGroupVersion.OpenAPIModels = openAPIModels
|
||||
|
||||
if openAPIModels != nil {
|
||||
typeConverter, err := fieldmanager.NewTypeConverter(openAPIModels, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
apiGroupVersion.TypeConverter = typeConverter
|
||||
}
|
||||
|
||||
apiGroupVersion.TypeConverter = typeConverter
|
||||
apiGroupVersion.MaxRequestBodyBytes = s.maxRequestBodyBytes
|
||||
|
||||
discoveryAPIResources, r, err := apiGroupVersion.InstallREST(s.Handler.GoRestfulContainer)
|
||||
@@ -693,6 +766,7 @@ func (s *GenericAPIServer) installAPIResources(apiPrefix string, apiGroupInfo *A
|
||||
s.AggregatedDiscoveryGroupManager.AddGroupVersion(
|
||||
groupVersion.Group,
|
||||
apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
Freshness: apidiscoveryv2beta1.DiscoveryFreshnessCurrent,
|
||||
Version: groupVersion.Version,
|
||||
Resources: discoveryAPIResources,
|
||||
},
|
||||
@@ -702,6 +776,7 @@ func (s *GenericAPIServer) installAPIResources(apiPrefix string, apiGroupInfo *A
|
||||
s.AggregatedLegacyDiscoveryGroupManager.AddGroupVersion(
|
||||
groupVersion.Group,
|
||||
apidiscoveryv2beta1.APIVersionDiscovery{
|
||||
Freshness: apidiscoveryv2beta1.DiscoveryFreshnessCurrent,
|
||||
Version: groupVersion.Version,
|
||||
Resources: discoveryAPIResources,
|
||||
},
|
||||
@@ -759,6 +834,9 @@ func (s *GenericAPIServer) InstallLegacyAPIGroup(apiPrefix string, apiGroupInfo
|
||||
// underlying storage will be destroyed on this servers shutdown.
|
||||
func (s *GenericAPIServer) InstallAPIGroups(apiGroupInfos ...*APIGroupInfo) error {
|
||||
for _, apiGroupInfo := range apiGroupInfos {
|
||||
if len(apiGroupInfo.PrioritizedVersions) == 0 {
|
||||
return fmt.Errorf("no version priority set for %#v", *apiGroupInfo)
|
||||
}
|
||||
// Do not register empty group or empty version. Doing so claims /apis/ for the wrong entity to be returned.
|
||||
// Catching these here places the error much closer to its origin
|
||||
if len(apiGroupInfo.PrioritizedVersions[0].Group) == 0 {
|
||||
@@ -831,9 +909,22 @@ func (s *GenericAPIServer) getAPIGroupVersion(apiGroupInfo *APIGroupInfo, groupV
|
||||
}
|
||||
|
||||
func (s *GenericAPIServer) newAPIGroupVersion(apiGroupInfo *APIGroupInfo, groupVersion schema.GroupVersion) *genericapi.APIGroupVersion {
|
||||
|
||||
allServedVersionsByResource := map[string][]string{}
|
||||
for version, resourcesInVersion := range apiGroupInfo.VersionedResourcesStorageMap {
|
||||
for resource := range resourcesInVersion {
|
||||
if len(groupVersion.Group) == 0 {
|
||||
allServedVersionsByResource[resource] = append(allServedVersionsByResource[resource], version)
|
||||
} else {
|
||||
allServedVersionsByResource[resource] = append(allServedVersionsByResource[resource], fmt.Sprintf("%s/%s", groupVersion.Group, version))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &genericapi.APIGroupVersion{
|
||||
GroupVersion: groupVersion,
|
||||
MetaGroupVersion: apiGroupInfo.MetaGroupVersion,
|
||||
GroupVersion: groupVersion,
|
||||
AllServedVersionsByResource: allServedVersionsByResource,
|
||||
MetaGroupVersion: apiGroupInfo.MetaGroupVersion,
|
||||
|
||||
ParameterCodec: apiGroupInfo.ParameterCodec,
|
||||
Serializer: apiGroupInfo.NegotiatedSerializer,
|
||||
@@ -868,11 +959,13 @@ func NewDefaultAPIGroupInfo(group string, scheme *runtime.Scheme, parameterCodec
|
||||
}
|
||||
|
||||
// getOpenAPIModels is a private method for getting the OpenAPI models
|
||||
func (s *GenericAPIServer) getOpenAPIModels(apiPrefix string, apiGroupInfos ...*APIGroupInfo) (openapiproto.Models, error) {
|
||||
if s.openAPIConfig == nil {
|
||||
return nil, nil
|
||||
func (s *GenericAPIServer) getOpenAPIModels(apiPrefix string, apiGroupInfos ...*APIGroupInfo) (managedfields.TypeConverter, error) {
|
||||
if s.openAPIV3Config == nil {
|
||||
// SSA is GA and requires OpenAPI config to be set
|
||||
// to create models.
|
||||
return nil, errors.New("OpenAPIV3 config must not be nil")
|
||||
}
|
||||
pathsToIgnore := openapiutil.NewTrie(s.openAPIConfig.IgnorePrefixes)
|
||||
pathsToIgnore := openapiutil.NewTrie(s.openAPIV3Config.IgnorePrefixes)
|
||||
resourceNames := make([]string, 0)
|
||||
for _, apiGroupInfo := range apiGroupInfos {
|
||||
groupResources, err := getResourceNamesForGroup(apiPrefix, apiGroupInfo, pathsToIgnore)
|
||||
@@ -883,14 +976,20 @@ func (s *GenericAPIServer) getOpenAPIModels(apiPrefix string, apiGroupInfos ...*
|
||||
}
|
||||
|
||||
// Build the openapi definitions for those resources and convert it to proto models
|
||||
openAPISpec, err := openapibuilder2.BuildOpenAPIDefinitionsForResources(s.openAPIConfig, resourceNames...)
|
||||
openAPISpec, err := openapibuilder3.BuildOpenAPIDefinitionsForResources(s.openAPIV3Config, resourceNames...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, apiGroupInfo := range apiGroupInfos {
|
||||
apiGroupInfo.StaticOpenAPISpec = openAPISpec
|
||||
}
|
||||
return utilopenapi.ToProtoModels(openAPISpec)
|
||||
|
||||
typeConverter, err := managedfields.NewTypeConverter(openAPISpec, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return typeConverter, nil
|
||||
}
|
||||
|
||||
// getResourceNamesForGroup is a private method for getting the canonical names for each resource to build in an api group
|
||||
|
||||
Reference in New Issue
Block a user