Update go dependencies

This commit is contained in:
Manuel de Brito Fontes 2018-04-21 14:10:40 -03:00
parent 293223eea0
commit b7a799bf82
No known key found for this signature in database
GPG key ID: 786136016A8BA02A
432 changed files with 37346 additions and 25783 deletions

View file

@ -13,8 +13,7 @@ go_test(
"config_test.go",
"genericapiserver_test.go",
],
importpath = "k8s.io/apiserver/pkg/server",
library = ":go_default_library",
embed = [":go_default_library"],
deps = [
"//vendor/github.com/stretchr/testify/assert:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
@ -30,14 +29,14 @@ go_test(
"//vendor/k8s.io/apiserver/pkg/authentication/user:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library",
"//vendor/k8s.io/apiserver/pkg/endpoints/discovery:go_default_library",
"//vendor/k8s.io/apiserver/pkg/endpoints/filters:go_default_library",
"//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
"//vendor/k8s.io/apiserver/pkg/registry/rest:go_default_library",
"//vendor/k8s.io/apiserver/pkg/server/filters:go_default_library",
"//vendor/k8s.io/apiserver/pkg/server/healthz:go_default_library",
"//vendor/k8s.io/apiserver/pkg/storage/etcd/testing:go_default_library",
"//vendor/k8s.io/client-go/informers:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
"//vendor/k8s.io/client-go/rest:go_default_library",
"//vendor/k8s.io/kube-openapi/pkg/common:go_default_library",
],
)
@ -54,9 +53,38 @@ go_library(
"plugins.go",
"serve.go",
"signal.go",
"signal_posix.go",
] + select({
"@io_bazel_rules_go//go/platform:windows_amd64": [
"@io_bazel_rules_go//go/platform:android": [
"signal_posix.go",
],
"@io_bazel_rules_go//go/platform:darwin": [
"signal_posix.go",
],
"@io_bazel_rules_go//go/platform:dragonfly": [
"signal_posix.go",
],
"@io_bazel_rules_go//go/platform:freebsd": [
"signal_posix.go",
],
"@io_bazel_rules_go//go/platform:linux": [
"signal_posix.go",
],
"@io_bazel_rules_go//go/platform:nacl": [
"signal_posix.go",
],
"@io_bazel_rules_go//go/platform:netbsd": [
"signal_posix.go",
],
"@io_bazel_rules_go//go/platform:openbsd": [
"signal_posix.go",
],
"@io_bazel_rules_go//go/platform:plan9": [
"signal_posix.go",
],
"@io_bazel_rules_go//go/platform:solaris": [
"signal_posix.go",
],
"@io_bazel_rules_go//go/platform:windows": [
"signal_windows.go",
],
"//conditions:default": [],
@ -69,7 +97,7 @@ go_library(
"//vendor/github.com/go-openapi/spec:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/github.com/pborman/uuid:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
"//vendor/golang.org/x/net/http2:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apimachinery:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apimachinery/registered:go_default_library",
@ -81,11 +109,13 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/waitgroup:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/version:go_default_library",
"//vendor/k8s.io/apiserver/pkg/admission:go_default_library",
"//vendor/k8s.io/apiserver/pkg/admission/plugin/initialization:go_default_library",
"//vendor/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle:go_default_library",
"//vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/webhook:go_default_library",
"//vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating:go_default_library",
"//vendor/k8s.io/apiserver/pkg/admission/plugin/webhook/validating:go_default_library",
"//vendor/k8s.io/apiserver/pkg/apis/apiserver/install:go_default_library",
"//vendor/k8s.io/apiserver/pkg/audit:go_default_library",
"//vendor/k8s.io/apiserver/pkg/audit/policy:go_default_library",
@ -109,6 +139,7 @@ go_library(
"//vendor/k8s.io/apiserver/pkg/server/healthz:go_default_library",
"//vendor/k8s.io/apiserver/pkg/server/mux:go_default_library",
"//vendor/k8s.io/apiserver/pkg/server/routes:go_default_library",
"//vendor/k8s.io/apiserver/pkg/server/storage:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//vendor/k8s.io/client-go/informers:go_default_library",
"//vendor/k8s.io/client-go/rest:go_default_library",
@ -133,6 +164,7 @@ filegroup(
"//staging/src/k8s.io/apiserver/pkg/server/httplog:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/server/mux:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/server/options:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/server/resourceconfig:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/server/routes:all-srcs",
"//staging/src/k8s.io/apiserver/pkg/server/storage:all-srcs",
],

View file

@ -36,6 +36,7 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apimachinery/pkg/util/sets"
utilwaitgroup "k8s.io/apimachinery/pkg/util/waitgroup"
"k8s.io/apimachinery/pkg/version"
"k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/audit"
@ -56,6 +57,7 @@ import (
genericfilters "k8s.io/apiserver/pkg/server/filters"
"k8s.io/apiserver/pkg/server/healthz"
"k8s.io/apiserver/pkg/server/routes"
serverstore "k8s.io/apiserver/pkg/server/storage"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/informers"
restclient "k8s.io/client-go/rest"
@ -77,17 +79,19 @@ const (
// Config is a structure used to configure a GenericAPIServer.
// Its members are sorted roughly in order of importance for composers.
type Config struct {
// SecureServingInfo is required to serve https
SecureServingInfo *SecureServingInfo
// SecureServing is required to serve https
SecureServing *SecureServingInfo
// Authentication is the configuration for authentication
Authentication AuthenticationInfo
// Authorization is the configuration for authorization
Authorization AuthorizationInfo
// LoopbackClientConfig is a config for a privileged loopback connection to the API server
// This is required for proper functioning of the PostStartHooks on a GenericAPIServer
// TODO: move into SecureServing(WithLoopback) as soon as insecure serving is gone
LoopbackClientConfig *restclient.Config
// Authenticator determines which subject is making the request
Authenticator authenticator.Request
// Authorizer determines whether the subject is allowed to make the request based only
// on the RequestURI
Authorizer authorizer.Authorizer
// RuleResolver is required to get the list of rules that apply to a given user
// in a given namespace
RuleResolver authorizer.RuleResolver
@ -114,10 +118,6 @@ type Config struct {
AuditBackend audit.Backend
// AuditPolicyChecker makes the decision of whether and how to audit log a request.
AuditPolicyChecker auditpolicy.Checker
// SupportsBasicAuth indicates that's at least one Authenticator supports basic auth
// If this is true, a basic auth challenge is returned on authentication failure
// TODO(roberthbailey): Remove once the server no longer supports http basic auth.
SupportsBasicAuth bool
// ExternalAddress is the host name to use for external (public internet) facing URLs (e.g. Swagger)
// Will default to a value based on secure serving info and available ipv4 IPs.
ExternalAddress string
@ -128,6 +128,8 @@ type Config struct {
// BuildHandlerChainFunc allows you to build custom handler chains by decorating the apiHandler.
BuildHandlerChainFunc func(apiHandler http.Handler, c *Config) (secure http.Handler)
// HandlerChainWaitGroup allows you to wait for all chain handlers exit after the server shutdown.
HandlerChainWaitGroup *utilwaitgroup.SafeWaitGroup
// DiscoveryAddresses is used to build the IPs pass to discovery. If nil, the ExternalAddress is
// always reported
DiscoveryAddresses discovery.Addresses
@ -172,6 +174,11 @@ type Config struct {
// if the client requests it via Accept-Encoding
EnableAPIResponseCompression bool
// MergedResourceConfig indicates which groupVersion enabled and its resources enabled/disabled.
// This is composed of genericapiserver defaultAPIResourceConfig and those parsed from flags.
// If not specify any in flags, then genericapiserver will only enable defaultAPIResourceConfig.
MergedResourceConfig *serverstore.ResourceConfig
//===========================================================================
// values below here are targets for removal
//===========================================================================
@ -200,20 +207,13 @@ type RecommendedConfig struct {
}
type SecureServingInfo struct {
// BindAddress is the ip:port to serve on
BindAddress string
// BindNetwork is the type of network to bind to - defaults to "tcp", accepts "tcp",
// "tcp4", and "tcp6".
BindNetwork string
// Listener is the secure server network listener.
Listener net.Listener
// Cert is the main server cert which is used if SNI does not match. Cert must be non-nil and is
// allowed to be in SNICerts.
Cert *tls.Certificate
// CACert is an optional certificate authority used for the loopback connection of the Admission controllers.
// If this is nil, the certificate authority is extracted from Cert or a matching SNI certificate.
CACert *tls.Certificate
// SNICerts are the TLS certificates by name used for SNI.
SNICerts map[string]*tls.Certificate
@ -227,6 +227,25 @@ type SecureServingInfo struct {
// CipherSuites optionally overrides the list of allowed cipher suites for the server.
// Values are from tls package constants (https://golang.org/pkg/crypto/tls/#pkg-constants).
CipherSuites []uint16
// HTTP2MaxStreamsPerConnection is the limit that the api server imposes on each client.
// A value of zero means to use the default provided by golang's HTTP/2 support.
HTTP2MaxStreamsPerConnection int
}
type AuthenticationInfo struct {
// Authenticator determines which subject is making the request
Authenticator authenticator.Request
// SupportsBasicAuth indicates that's at least one Authenticator supports basic auth
// If this is true, a basic auth challenge is returned on authentication failure
// TODO(roberthbailey): Remove once the server no longer supports http basic auth.
SupportsBasicAuth bool
}
type AuthorizationInfo struct {
// Authorizer determines whether the subject is allowed to make the request based only
// on the RequestURI
Authorizer authorizer.Authorizer
}
// NewConfig returns a Config struct with the default values
@ -236,6 +255,7 @@ func NewConfig(codecs serializer.CodecFactory) *Config {
ReadWritePort: 443,
RequestContextMapper: apirequest.NewRequestContextMapper(),
BuildHandlerChainFunc: DefaultBuildHandlerChain,
HandlerChainWaitGroup: new(utilwaitgroup.SafeWaitGroup),
LegacyAPIGroupPrefixes: sets.NewString(DefaultLegacyAPIPrefix),
DisabledPostStartHooks: sets.NewString(),
HealthzChecks: []healthz.HealthzChecker{healthz.PingHealthz},
@ -299,23 +319,23 @@ func DefaultSwaggerConfig() *swagger.Config {
}
}
func (c *Config) ApplyClientCert(clientCAFile string) (*Config, error) {
if c.SecureServingInfo != nil {
func (c *AuthenticationInfo) ApplyClientCert(clientCAFile string, servingInfo *SecureServingInfo) error {
if servingInfo != nil {
if len(clientCAFile) > 0 {
clientCAs, err := certutil.CertsFromFile(clientCAFile)
if err != nil {
return nil, fmt.Errorf("unable to load client CA file: %v", err)
return fmt.Errorf("unable to load client CA file: %v", err)
}
if c.SecureServingInfo.ClientCA == nil {
c.SecureServingInfo.ClientCA = x509.NewCertPool()
if servingInfo.ClientCA == nil {
servingInfo.ClientCA = x509.NewCertPool()
}
for _, cert := range clientCAs {
c.SecureServingInfo.ClientCA.AddCert(cert)
servingInfo.ClientCA.AddCert(cert)
}
}
}
return c, nil
return nil
}
type completedConfig struct {
@ -337,13 +357,17 @@ type CompletedConfig struct {
// Complete fills in any fields not set that are required to have valid data and can be derived
// from other fields. If you're going to `ApplyOptions`, do that first. It's mutating the receiver.
func (c *Config) Complete(informers informers.SharedInformerFactory) CompletedConfig {
if len(c.ExternalAddress) == 0 && c.PublicAddress != nil {
hostAndPort := c.PublicAddress.String()
if c.ReadWritePort != 0 {
hostAndPort = net.JoinHostPort(hostAndPort, strconv.Itoa(c.ReadWritePort))
}
c.ExternalAddress = hostAndPort
host := c.ExternalAddress
if host == "" && c.PublicAddress != nil {
host = c.PublicAddress.String()
}
// if there is no port, and we have a ReadWritePort, use that
if _, _, err := net.SplitHostPort(host); err != nil && c.ReadWritePort != 0 {
host = net.JoinHostPort(host, strconv.Itoa(c.ReadWritePort))
}
c.ExternalAddress = host
if c.OpenAPIConfig != nil && c.OpenAPIConfig.SecurityDefinitions != nil {
// Setup OpenAPI security: all APIs will have the same authentication for now.
c.OpenAPIConfig.DefaultSecurity = []map[string][]string{}
@ -378,7 +402,7 @@ func (c *Config) Complete(informers informers.SharedInformerFactory) CompletedCo
}
}
if c.SwaggerConfig != nil && len(c.SwaggerConfig.WebServicesUrl) == 0 {
if c.SecureServingInfo != nil {
if c.SecureServing != nil {
c.SwaggerConfig.WebServicesUrl = "https://" + c.ExternalAddress
} else {
c.SwaggerConfig.WebServicesUrl = "http://" + c.ExternalAddress
@ -390,7 +414,7 @@ func (c *Config) Complete(informers informers.SharedInformerFactory) CompletedCo
// If the loopbackclientconfig is specified AND it has a token for use against the API server
// wrap the authenticator and authorizer in loopback authentication logic
if c.Authenticator != nil && c.Authorizer != nil && c.LoopbackClientConfig != nil && len(c.LoopbackClientConfig.BearerToken) > 0 {
if c.Authentication.Authenticator != nil && c.Authorization.Authorizer != nil && c.LoopbackClientConfig != nil && len(c.LoopbackClientConfig.BearerToken) > 0 {
privilegedLoopbackToken := c.LoopbackClientConfig.BearerToken
var uid = uuid.NewRandom().String()
tokens := make(map[string]*user.DefaultInfo)
@ -401,10 +425,10 @@ func (c *Config) Complete(informers informers.SharedInformerFactory) CompletedCo
}
tokenAuthenticator := authenticatorfactory.NewFromTokens(tokens)
c.Authenticator = authenticatorunion.New(tokenAuthenticator, c.Authenticator)
c.Authentication.Authenticator = authenticatorunion.New(tokenAuthenticator, c.Authentication.Authenticator)
tokenAuthorizer := authorizerfactory.NewPrivilegedGroups(user.SystemPrivilegedGroup)
c.Authorizer = authorizerunion.New(tokenAuthorizer, c.Authorizer)
c.Authorization.Authorizer = authorizerunion.New(tokenAuthorizer, c.Authorization.Authorizer)
}
if c.RequestInfoResolver == nil {
@ -446,10 +470,12 @@ func (c completedConfig) New(name string, delegationTarget DelegationTarget) (*G
Serializer: c.Serializer,
AuditBackend: c.AuditBackend,
delegationTarget: delegationTarget,
HandlerChainWaitGroup: c.HandlerChainWaitGroup,
minRequestTimeout: time.Duration(c.MinRequestTimeout) * time.Second,
ShutdownTimeout: c.RequestTimeout,
SecureServingInfo: c.SecureServingInfo,
SecureServingInfo: c.SecureServing,
ExternalAddress: c.ExternalAddress,
Handler: apiServerHandler,
@ -488,6 +514,7 @@ func (c completedConfig) New(name string, delegationTarget DelegationTarget) (*G
return nil, err
}
}
for _, delegateCheck := range delegationTarget.HealthzChecks() {
skip := false
for _, existingCheck := range c.HealthzChecks {
@ -520,21 +547,22 @@ func (c completedConfig) New(name string, delegationTarget DelegationTarget) (*G
}
func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler {
handler := genericapifilters.WithAuthorization(apiHandler, c.RequestContextMapper, c.Authorizer, c.Serializer)
handler := genericapifilters.WithAuthorization(apiHandler, c.RequestContextMapper, c.Authorization.Authorizer, c.Serializer)
handler = genericfilters.WithMaxInFlightLimit(handler, c.MaxRequestsInFlight, c.MaxMutatingRequestsInFlight, c.RequestContextMapper, c.LongRunningFunc)
handler = genericapifilters.WithImpersonation(handler, c.RequestContextMapper, c.Authorizer, c.Serializer)
handler = genericapifilters.WithImpersonation(handler, c.RequestContextMapper, c.Authorization.Authorizer, c.Serializer)
if utilfeature.DefaultFeatureGate.Enabled(features.AdvancedAuditing) {
handler = genericapifilters.WithAudit(handler, c.RequestContextMapper, c.AuditBackend, c.AuditPolicyChecker, c.LongRunningFunc)
} else {
handler = genericapifilters.WithLegacyAudit(handler, c.RequestContextMapper, c.LegacyAuditWriter)
}
failedHandler := genericapifilters.Unauthorized(c.RequestContextMapper, c.Serializer, c.SupportsBasicAuth)
failedHandler := genericapifilters.Unauthorized(c.RequestContextMapper, c.Serializer, c.Authentication.SupportsBasicAuth)
if utilfeature.DefaultFeatureGate.Enabled(features.AdvancedAuditing) {
failedHandler = genericapifilters.WithFailedAuthenticationAudit(failedHandler, c.RequestContextMapper, c.AuditBackend, c.AuditPolicyChecker)
}
handler = genericapifilters.WithAuthentication(handler, c.RequestContextMapper, c.Authenticator, failedHandler)
handler = genericapifilters.WithAuthentication(handler, c.RequestContextMapper, c.Authentication.Authenticator, failedHandler)
handler = genericfilters.WithCORS(handler, c.CorsAllowedOriginList, nil, nil, nil, "true")
handler = genericfilters.WithTimeoutForNonLongRunningRequests(handler, c.RequestContextMapper, c.LongRunningFunc, c.RequestTimeout)
handler = genericfilters.WithWaitGroup(handler, c.RequestContextMapper, c.LongRunningFunc, c.HandlerChainWaitGroup)
handler = genericapifilters.WithRequestInfo(handler, c.RequestInfoResolver, c.RequestContextMapper)
handler = apirequest.WithRequestContext(handler, c.RequestContextMapper)
handler = genericfilters.WithPanicRecovery(handler)

View file

@ -32,7 +32,7 @@ func (s *SecureServingInfo) NewLoopbackClientConfig(token string, loopbackCert [
return nil, nil
}
host, port, err := LoopbackHostPort(s.BindAddress)
host, port, err := LoopbackHostPort(s.Listener.Addr().String())
if err != nil {
return nil, err
}
@ -64,7 +64,7 @@ func LoopbackHostPort(bindAddress string) (string, string, error) {
}
// Value is expected to be an IP or DNS name, not "0.0.0.0".
if host == "0.0.0.0" {
if host == "0.0.0.0" || host == "::" {
host = "localhost"
// Get ip of local interface, but fall back to "localhost".
// Note that "localhost" is resolved with the external nameserver first with Go's stdlib.

View file

@ -43,4 +43,26 @@ func TestLoopbackHostPort(t *testing.T) {
if port != "443" {
t.Fatalf("expected 443 as port, got %q", port)
}
host, port, err = LoopbackHostPort("[ff06:0:0:0:0:0:0:c3]:443")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if host != "ff06:0:0:0:0:0:0:c3" {
t.Fatalf("expected ff06:0:0:0:0:0:0:c3 as host, got %q", host)
}
if port != "443" {
t.Fatalf("expected 443 as port, got %q", port)
}
host, port, err = LoopbackHostPort("[::]:443")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if ip := net.ParseIP(host); ip == nil || !ip.IsLoopback() {
t.Fatalf("expected host to be loopback, got %q", host)
}
if port != "443" {
t.Fatalf("expected 443 as port, got %q", port)
}
}

View file

@ -45,9 +45,7 @@ func TestNewWithDelegate(t *testing.T) {
t.Fatal("unable to create fake client set")
}
delegateHealthzCalled := false
delegateConfig.HealthzChecks = append(delegateConfig.HealthzChecks, healthz.NamedCheck("delegate-health", func(r *http.Request) error {
delegateHealthzCalled = true
return fmt.Errorf("delegate failed healthcheck")
}))
@ -74,9 +72,7 @@ func TestNewWithDelegate(t *testing.T) {
wrappingConfig.LoopbackClientConfig = &rest.Config{}
wrappingConfig.SwaggerConfig = DefaultSwaggerConfig()
wrappingHealthzCalled := false
wrappingConfig.HealthzChecks = append(wrappingConfig.HealthzChecks, healthz.NamedCheck("wrapping-health", func(r *http.Request) error {
wrappingHealthzCalled = true
return fmt.Errorf("wrapping failed healthcheck")
}))

View file

@ -34,6 +34,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apimachinery/pkg/util/sets"
utilwaitgroup "k8s.io/apimachinery/pkg/util/waitgroup"
"k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/audit"
genericapi "k8s.io/apiserver/pkg/endpoints"
@ -70,12 +71,6 @@ type APIGroupInfo struct {
NegotiatedSerializer runtime.NegotiatedSerializer
// ParameterCodec performs conversions for query parameters passed to API calls
ParameterCodec runtime.ParameterCodec
// SubresourceGroupVersionKind contains the GroupVersionKind overrides for each subresource that is
// accessible from this API group version. The GroupVersionKind is that of the external version of
// the subresource. The key of this map should be the path of the subresource. The keys here should
// match the keys in the Storage map above for subresources.
SubresourceGroupVersionKind map[string]schema.GroupVersionKind
}
// GenericAPIServer contains state for a Kubernetes cluster api server.
@ -89,6 +84,10 @@ type GenericAPIServer struct {
// minRequestTimeout is how short the request timeout can be. This is used to build the RESTHandler
minRequestTimeout time.Duration
// ShutdownTimeout is the timeout used for server shutdown. This specifies the timeout before server
// gracefully shutdown returns.
ShutdownTimeout time.Duration
// legacyAPIGroupPrefixes is used to set up URL parsing for authorization and for validating requests
// to InstallLegacyAPIGroup
legacyAPIGroupPrefixes sets.String
@ -101,9 +100,6 @@ type GenericAPIServer struct {
SecureServingInfo *SecureServingInfo
// numerical ports, set after listening
effectiveSecurePort int
// ExternalAddress is the address (hostname or IP and port) that should be used in
// external (public internet) URLs for this GenericAPIServer.
ExternalAddress string
@ -152,6 +148,9 @@ type GenericAPIServer struct {
// delegationTarget is the next delegate in the chain or nil
delegationTarget DelegationTarget
// HandlerChainWaitGroup allows you to wait for all chain handlers finish after the server shutdown.
HandlerChainWaitGroup *utilwaitgroup.SafeWaitGroup
}
// DelegationTarget is an interface which allows for composition of API servers with top level handling that works
@ -281,16 +280,28 @@ func (s preparedGenericAPIServer) Run(stopCh <-chan struct{}) error {
<-stopCh
return s.RunPreShutdownHooks()
err = s.RunPreShutdownHooks()
if err != nil {
return err
}
// Wait for all requests to finish, which are bounded by the RequestTimeout variable.
s.HandlerChainWaitGroup.Wait()
return nil
}
// NonBlockingRun spawns the secure http server. An error is
// returned if the secure port cannot be listened on.
func (s preparedGenericAPIServer) NonBlockingRun(stopCh <-chan struct{}) error {
// Use an stop channel to allow graceful shutdown without dropping audit events
// after http server shutdown.
auditStopCh := make(chan struct{})
// Start the audit backend before any request comes in. This means we must call Backend.Run
// before http server start serving. Otherwise the Backend.ProcessEvents call might block.
if s.AuditBackend != nil {
if err := s.AuditBackend.Run(stopCh); err != nil {
if err := s.AuditBackend.Run(auditStopCh); err != nil {
return fmt.Errorf("failed to run the audit backend: %v", err)
}
}
@ -299,7 +310,7 @@ func (s preparedGenericAPIServer) NonBlockingRun(stopCh <-chan struct{}) error {
internalStopCh := make(chan struct{})
if s.SecureServingInfo != nil && s.Handler != nil {
if err := s.serveSecurely(internalStopCh); err != nil {
if err := s.SecureServingInfo.Serve(s.Handler, s.ShutdownTimeout, internalStopCh); err != nil {
close(internalStopCh)
return err
}
@ -311,6 +322,8 @@ func (s preparedGenericAPIServer) NonBlockingRun(stopCh <-chan struct{}) error {
go func() {
<-stopCh
close(internalStopCh)
s.HandlerChainWaitGroup.Wait()
close(auditStopCh)
}()
s.RunPostStartHooks(stopCh)
@ -322,11 +335,6 @@ func (s preparedGenericAPIServer) NonBlockingRun(stopCh <-chan struct{}) error {
return nil
}
// EffectiveSecurePort returns the secure port we bound to.
func (s *GenericAPIServer) EffectiveSecurePort() int {
return s.effectiveSecurePort
}
// installAPIResources is a private method for installing the REST storage backing each api groupversionresource
func (s *GenericAPIServer) installAPIResources(apiPrefix string, apiGroupInfo *APIGroupInfo) error {
for _, groupVersion := range apiGroupInfo.GroupMeta.GroupVersions {
@ -435,9 +443,8 @@ func (s *GenericAPIServer) newAPIGroupVersion(apiGroupInfo *APIGroupInfo, groupV
UnsafeConvertor: runtime.UnsafeObjectConvertor(apiGroupInfo.Scheme),
Defaulter: apiGroupInfo.Scheme,
Typer: apiGroupInfo.Scheme,
SubresourceGroupVersionKind: apiGroupInfo.SubresourceGroupVersionKind,
Linker: apiGroupInfo.GroupMeta.SelfLinker,
Mapper: apiGroupInfo.GroupMeta.RESTMapper,
Linker: apiGroupInfo.GroupMeta.SelfLinker,
Mapper: apiGroupInfo.GroupMeta.RESTMapper,
Admit: s.admissionControl,
Context: s.RequestContextMapper(),

View file

@ -25,6 +25,8 @@ import (
"net/http"
"net/http/httptest"
goruntime "runtime"
"strconv"
"sync"
"testing"
"time"
@ -44,13 +46,13 @@ import (
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/apiserver/pkg/endpoints/discovery"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
genericapifilters "k8s.io/apiserver/pkg/endpoints/filters"
apirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/rest"
etcdtesting "k8s.io/apiserver/pkg/storage/etcd/testing"
genericfilters "k8s.io/apiserver/pkg/server/filters"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes/fake"
restclient "k8s.io/client-go/rest"
openapi "k8s.io/kube-openapi/pkg/common"
)
const (
@ -78,17 +80,11 @@ func init() {
examplev1.AddToScheme(scheme)
}
func testGetOpenAPIDefinitions(ref openapi.ReferenceCallback) map[string]openapi.OpenAPIDefinition {
return map[string]openapi.OpenAPIDefinition{}
}
// setUp is a convience function for setting up for (most) tests.
func setUp(t *testing.T) (*etcdtesting.EtcdTestServer, Config, *assert.Assertions) {
etcdServer, _ := etcdtesting.NewUnsecuredEtcd3TestClientServer(t, scheme)
func setUp(t *testing.T) (Config, *assert.Assertions) {
config := NewConfig(codecs)
config.PublicAddress = net.ParseIP("192.168.10.4")
config.RequestContextMapper = genericapirequest.NewRequestContextMapper()
config.RequestContextMapper = apirequest.NewRequestContextMapper()
config.LegacyAPIGroupPrefixes = sets.NewString("/api")
config.LoopbackClientConfig = &restclient.Config{}
@ -109,24 +105,23 @@ func setUp(t *testing.T) (*etcdtesting.EtcdTestServer, Config, *assert.Assertion
sharedInformers := informers.NewSharedInformerFactory(clientset, config.LoopbackClientConfig.Timeout)
config.Complete(sharedInformers)
return etcdServer, *config, assert.New(t)
return *config, assert.New(t)
}
func newMaster(t *testing.T) (*GenericAPIServer, *etcdtesting.EtcdTestServer, Config, *assert.Assertions) {
etcdserver, config, assert := setUp(t)
func newMaster(t *testing.T) (*GenericAPIServer, Config, *assert.Assertions) {
config, assert := setUp(t)
s, err := config.Complete(nil).New("test", EmptyDelegate)
if err != nil {
t.Fatalf("Error in bringing up the server: %v", err)
}
return s, etcdserver, config, assert
return s, config, assert
}
// TestNew verifies that the New function returns a GenericAPIServer
// using the configuration properly.
func TestNew(t *testing.T) {
s, etcdserver, config, assert := newMaster(t)
defer etcdserver.Terminate(t)
s, config, assert := newMaster(t)
// Verify many of the variables match their config counterparts
assert.Equal(s.legacyAPIGroupPrefixes, config.LegacyAPIGroupPrefixes)
@ -141,8 +136,7 @@ func TestNew(t *testing.T) {
// Verifies that AddGroupVersions works as expected.
func TestInstallAPIGroups(t *testing.T) {
etcdserver, config, assert := setUp(t)
defer etcdserver.Terminate(t)
config, assert := setUp(t)
config.LegacyAPIGroupPrefixes = sets.NewString("/apiPrefix")
config.DiscoveryAddresses = discovery.DefaultAddresses{DefaultAddress: "ExternalAddress"}
@ -308,8 +302,7 @@ func TestInstallAPIGroups(t *testing.T) {
}
func TestPrepareRun(t *testing.T) {
s, etcdserver, config, assert := newMaster(t)
defer etcdserver.Terminate(t)
s, config, assert := newMaster(t)
assert.NotNil(config.SwaggerConfig)
@ -336,8 +329,7 @@ func TestPrepareRun(t *testing.T) {
// TestCustomHandlerChain verifies the handler chain with custom handler chain builder functions.
func TestCustomHandlerChain(t *testing.T) {
etcdserver, config, _ := setUp(t)
defer etcdserver.Terminate(t)
config, _ := setUp(t)
var protected, called bool
@ -390,13 +382,12 @@ func TestCustomHandlerChain(t *testing.T) {
// TestNotRestRoutesHaveAuth checks that special non-routes are behind authz/authn.
func TestNotRestRoutesHaveAuth(t *testing.T) {
etcdserver, config, _ := setUp(t)
defer etcdserver.Terminate(t)
config, _ := setUp(t)
authz := mockAuthorizer{}
config.LegacyAPIGroupPrefixes = sets.NewString("/apiPrefix")
config.Authorizer = &authz
config.Authorization.Authorizer = &authz
config.EnableSwaggerUI = true
config.EnableIndex = true
@ -437,9 +428,9 @@ type mockAuthorizer struct {
lastURI string
}
func (authz *mockAuthorizer) Authorize(a authorizer.Attributes) (authorized bool, reason string, err error) {
func (authz *mockAuthorizer) Authorize(a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) {
authz.lastURI = a.GetPath()
return true, "", nil
return authorizer.DecisionAllow, "", nil
}
type mockAuthenticator struct {
@ -479,7 +470,7 @@ func (p *testGetterStorage) New() runtime.Object {
}
}
func (p *testGetterStorage) Get(ctx genericapirequest.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
func (p *testGetterStorage) Get(ctx apirequest.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
return nil, nil
}
@ -509,3 +500,82 @@ func fakeVersion() version.Info {
Platform: fmt.Sprintf("%s/%s", goruntime.GOOS, goruntime.GOARCH),
}
}
// TestGracefulShutdown verifies server shutdown after request handler finish.
func TestGracefulShutdown(t *testing.T) {
config, _ := setUp(t)
var graceShutdown bool
wg := sync.WaitGroup{}
wg.Add(1)
config.BuildHandlerChainFunc = func(apiHandler http.Handler, c *Config) http.Handler {
handler := genericfilters.WithWaitGroup(apiHandler, c.RequestContextMapper, c.LongRunningFunc, c.HandlerChainWaitGroup)
handler = genericapifilters.WithRequestInfo(handler, c.RequestInfoResolver, c.RequestContextMapper)
handler = apirequest.WithRequestContext(handler, c.RequestContextMapper)
return handler
}
handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
wg.Done()
time.Sleep(2 * time.Second)
w.WriteHeader(http.StatusOK)
graceShutdown = true
})
s, err := config.Complete(nil).New("test", EmptyDelegate)
if err != nil {
t.Fatalf("Error in bringing up the server: %v", err)
}
s.Handler.NonGoRestfulMux.Handle("/test", handler)
insecureServer := &http.Server{
Addr: "0.0.0.0:0",
Handler: s.Handler,
}
stopCh := make(chan struct{})
ln, err := net.Listen("tcp", insecureServer.Addr)
if err != nil {
t.Errorf("failed to listen on %v: %v", insecureServer.Addr, err)
}
// get port
serverPort := ln.Addr().(*net.TCPAddr).Port
err = RunServer(insecureServer, ln, 10*time.Second, stopCh)
if err != nil {
t.Errorf("RunServer err: %v", err)
}
graceCh := make(chan struct{})
// mock a client request
go func() {
resp, err := http.Get("http://127.0.0.1:" + strconv.Itoa(serverPort) + "/test")
if err != nil {
t.Errorf("Unexpected http error: %v", err)
}
if resp.StatusCode != http.StatusOK {
t.Errorf("Unexpected http status code: %v", resp.StatusCode)
}
close(graceCh)
}()
// close stopCh after request sent to server to guarantee request handler is running.
wg.Wait()
close(stopCh)
// wait for wait group handler finish
s.HandlerChainWaitGroup.Wait()
// check server all handlers finished.
if !graceShutdown {
t.Errorf("server shutdown not gracefully.")
}
// check client to make sure receive response.
select {
case <-graceCh:
t.Logf("server shutdown gracefully.")
case <-time.After(30 * time.Second):
t.Errorf("Timed out waiting for response.")
}
}

View file

@ -34,7 +34,6 @@ import (
"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
"k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/server/mux"
genericmux "k8s.io/apiserver/pkg/server/mux"
)
// APIServerHandlers holds the different http.Handlers used by the API server.
@ -74,7 +73,7 @@ type APIServerHandler struct {
type HandlerChainBuilderFn func(apiHandler http.Handler) http.Handler
func NewAPIServerHandler(name string, contextMapper request.RequestContextMapper, s runtime.NegotiatedSerializer, handlerChainBuilder HandlerChainBuilderFn, notFoundHandler http.Handler) *APIServerHandler {
nonGoRestfulMux := genericmux.NewPathRecorderMux(name)
nonGoRestfulMux := mux.NewPathRecorderMux(name)
if notFoundHandler != nil {
nonGoRestfulMux.NotFoundHandler(notFoundHandler)
}

View file

@ -9,8 +9,7 @@ load(
go_test(
name = "go_default_test",
srcs = ["healthz_test.go"],
importpath = "k8s.io/apiserver/pkg/server/healthz",
library = ":go_default_library",
embed = [":go_default_library"],
)
go_library(

View file

@ -106,9 +106,10 @@ func handleRootHealthz(checks ...HealthzChecker) http.HandlerFunc {
failed := false
var verboseOut bytes.Buffer
for _, check := range checks {
if check.Check(r) != nil {
if err := check.Check(r); err != nil {
// don't include the error since this endpoint is public. If someone wants more detail
// they should have explicit permission to the detailed checks.
glog.V(6).Infof("healthz check %v failed: %v", check.Name(), err)
fmt.Fprintf(&verboseOut, "[-]%v failed: reason withheld\n", check.Name())
failed = true
} else {

View file

@ -21,12 +21,14 @@ import (
"k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/admission/plugin/initialization"
"k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle"
"k8s.io/apiserver/pkg/admission/plugin/webhook/webhook"
mutatingwebhook "k8s.io/apiserver/pkg/admission/plugin/webhook/mutating"
validatingwebhook "k8s.io/apiserver/pkg/admission/plugin/webhook/validating"
)
// RegisterAllAdmissionPlugins registers all admission plugins
func RegisterAllAdmissionPlugins(plugins *admission.Plugins) {
lifecycle.Register(plugins)
initialization.Register(plugins)
webhook.Register(plugins)
validatingwebhook.Register(plugins)
mutatingwebhook.Register(plugins)
}

View file

@ -17,6 +17,7 @@ limitations under the License.
package server
import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
@ -25,11 +26,11 @@ import (
"strings"
"time"
"github.com/golang/glog"
"golang.org/x/net/http2"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/validation"
"github.com/golang/glog"
"github.com/pkg/errors"
)
const (
@ -39,13 +40,17 @@ const (
// serveSecurely runs the secure http server. It fails only if certificates cannot
// be loaded or the initial listen call fails. The actual server loop (stoppable by closing
// stopCh) runs in a go routine, i.e. serveSecurely does not block.
func (s *GenericAPIServer) serveSecurely(stopCh <-chan struct{}) error {
func (s *SecureServingInfo) Serve(handler http.Handler, shutdownTimeout time.Duration, stopCh <-chan struct{}) error {
if s.Listener == nil {
return fmt.Errorf("listener must not be nil")
}
secureServer := &http.Server{
Addr: s.SecureServingInfo.BindAddress,
Handler: s.Handler,
Addr: s.Listener.Addr().String(),
Handler: handler,
MaxHeaderBytes: 1 << 20,
TLSConfig: &tls.Config{
NameToCertificate: s.SecureServingInfo.SNICerts,
NameToCertificate: s.SNICerts,
// Can't use SSLv3 because of POODLE and BEAST
// Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher
// Can't use TLSv1.1 because of RC4 cipher usage
@ -55,66 +60,63 @@ func (s *GenericAPIServer) serveSecurely(stopCh <-chan struct{}) error {
},
}
if s.SecureServingInfo.MinTLSVersion > 0 {
secureServer.TLSConfig.MinVersion = s.SecureServingInfo.MinTLSVersion
if s.MinTLSVersion > 0 {
secureServer.TLSConfig.MinVersion = s.MinTLSVersion
}
if len(s.SecureServingInfo.CipherSuites) > 0 {
secureServer.TLSConfig.CipherSuites = s.SecureServingInfo.CipherSuites
if len(s.CipherSuites) > 0 {
secureServer.TLSConfig.CipherSuites = s.CipherSuites
}
if s.SecureServingInfo.Cert != nil {
secureServer.TLSConfig.Certificates = []tls.Certificate{*s.SecureServingInfo.Cert}
if s.Cert != nil {
secureServer.TLSConfig.Certificates = []tls.Certificate{*s.Cert}
}
// append all named certs. Otherwise, the go tls stack will think no SNI processing
// is necessary because there is only one cert anyway.
// Moreover, if ServerCert.CertFile/ServerCert.KeyFile are not set, the first SNI
// cert will become the default cert. That's what we expect anyway.
for _, c := range s.SecureServingInfo.SNICerts {
for _, c := range s.SNICerts {
secureServer.TLSConfig.Certificates = append(secureServer.TLSConfig.Certificates, *c)
}
if s.SecureServingInfo.ClientCA != nil {
if s.ClientCA != nil {
// Populate PeerCertificates in requests, but don't reject connections without certificates
// This allows certificates to be validated by authenticators, while still allowing other auth types
secureServer.TLSConfig.ClientAuth = tls.RequestClientCert
// Specify allowed CAs for client certificates
secureServer.TLSConfig.ClientCAs = s.SecureServingInfo.ClientCA
secureServer.TLSConfig.ClientCAs = s.ClientCA
}
glog.Infof("Serving securely on %s", s.SecureServingInfo.BindAddress)
var err error
s.effectiveSecurePort, err = RunServer(secureServer, s.SecureServingInfo.BindNetwork, stopCh)
return err
if s.HTTP2MaxStreamsPerConnection > 0 {
http2.ConfigureServer(secureServer, &http2.Server{
MaxConcurrentStreams: uint32(s.HTTP2MaxStreamsPerConnection),
})
}
glog.Infof("Serving securely on %s", secureServer.Addr)
return RunServer(secureServer, s.Listener, shutdownTimeout, stopCh)
}
// RunServer listens on the given port, then spawns a go-routine continuously serving
// until the stopCh is closed. The port is returned. This function does not block.
func RunServer(server *http.Server, network string, stopCh <-chan struct{}) (int, error) {
if len(server.Addr) == 0 {
return 0, errors.New("address cannot be empty")
// RunServer listens on the given port if listener is not given,
// then spawns a go-routine continuously serving
// until the stopCh is closed. This function does not block.
// TODO: make private when insecure serving is gone from the kube-apiserver
func RunServer(
server *http.Server,
ln net.Listener,
shutDownTimeout time.Duration,
stopCh <-chan struct{},
) error {
if ln == nil {
return fmt.Errorf("listener must not be nil")
}
if len(network) == 0 {
network = "tcp"
}
ln, err := net.Listen(network, server.Addr)
if err != nil {
return 0, fmt.Errorf("failed to listen on %v: %v", server.Addr, err)
}
// get port
tcpAddr, ok := ln.Addr().(*net.TCPAddr)
if !ok {
ln.Close()
return 0, fmt.Errorf("invalid listen address: %q", ln.Addr().String())
}
// Stop the server by closing the listener
// Shutdown server gracefully.
go func() {
<-stopCh
ln.Close()
ctx, cancel := context.WithTimeout(context.Background(), shutDownTimeout)
server.Shutdown(ctx)
cancel()
}()
go func() {
@ -128,7 +130,7 @@ func RunServer(server *http.Server, network string, stopCh <-chan struct{}) (int
err := server.Serve(listener)
msg := fmt.Sprintf("Stopped listening on %s", tcpAddr.String())
msg := fmt.Sprintf("Stopped listening on %s", ln.Addr().String())
select {
case <-stopCh:
glog.Info(msg)
@ -137,7 +139,7 @@ func RunServer(server *http.Server, network string, stopCh <-chan struct{}) (int
}
}()
return tcpAddr.Port, nil
return nil
}
type NamedTLSCert struct {