mirror of
https://github.com/kubernetes-sigs/prometheus-adapter.git
synced 2026-04-07 02:07:58 +00:00
Update custom-metrics-apiserver and metrics-server
This commit is contained in:
parent
4c673534f2
commit
b480e45a67
915 changed files with 63694 additions and 106514 deletions
35
vendor/k8s.io/apiserver/pkg/server/config.go
generated
vendored
35
vendor/k8s.io/apiserver/pkg/server/config.go
generated
vendored
|
|
@ -60,6 +60,7 @@ import (
|
|||
"k8s.io/apiserver/pkg/server/healthz"
|
||||
"k8s.io/apiserver/pkg/server/routes"
|
||||
serverstore "k8s.io/apiserver/pkg/server/storage"
|
||||
utilflowcontrol "k8s.io/apiserver/pkg/util/flowcontrol"
|
||||
"k8s.io/client-go/informers"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/component-base/logs"
|
||||
|
|
@ -107,6 +108,9 @@ type Config struct {
|
|||
AdmissionControl admission.Interface
|
||||
CorsAllowedOriginList []string
|
||||
|
||||
// FlowControl, if not nil, gives priority and fairness to request handling
|
||||
FlowControl utilflowcontrol.Interface
|
||||
|
||||
EnableIndex bool
|
||||
EnableProfiling bool
|
||||
EnableDiscovery bool
|
||||
|
|
@ -193,6 +197,12 @@ type Config struct {
|
|||
// Predicate which is true for paths of long-running http requests
|
||||
LongRunningFunc apirequest.LongRunningRequestCheck
|
||||
|
||||
// GoawayChance is the probability that send a GOAWAY to HTTP/2 clients. When client received
|
||||
// GOAWAY, the in-flight requests will not be affected and new requests will use
|
||||
// a new TCP connection to triggering re-balancing to another server behind the load balance.
|
||||
// Default to 0, means never send GOAWAY. Max is 0.02 to prevent break the apiserver.
|
||||
GoawayChance float64
|
||||
|
||||
// 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.
|
||||
|
|
@ -606,6 +616,21 @@ func (c completedConfig) New(name string, delegationTarget DelegationTarget) (*G
|
|||
}
|
||||
}
|
||||
|
||||
const priorityAndFairnessConfigConsumerHookName = "priority-and-fairness-config-consumer"
|
||||
if s.isPostStartHookRegistered(priorityAndFairnessConfigConsumerHookName) {
|
||||
} else if c.FlowControl != nil {
|
||||
err := s.AddPostStartHook(priorityAndFairnessConfigConsumerHookName, func(context PostStartHookContext) error {
|
||||
go c.FlowControl.Run(context.StopCh)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// TODO(yue9944882): plumb pre-shutdown-hook for request-management system?
|
||||
} else {
|
||||
klog.V(3).Infof("Not requested to run hook %s", priorityAndFairnessConfigConsumerHookName)
|
||||
}
|
||||
|
||||
for _, delegateCheck := range delegationTarget.HealthzChecks() {
|
||||
skip := false
|
||||
for _, existingCheck := range c.HealthzChecks {
|
||||
|
|
@ -638,7 +663,11 @@ func (c completedConfig) New(name string, delegationTarget DelegationTarget) (*G
|
|||
|
||||
func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler {
|
||||
handler := genericapifilters.WithAuthorization(apiHandler, c.Authorization.Authorizer, c.Serializer)
|
||||
handler = genericfilters.WithMaxInFlightLimit(handler, c.MaxRequestsInFlight, c.MaxMutatingRequestsInFlight, c.LongRunningFunc)
|
||||
if c.FlowControl != nil {
|
||||
handler = genericfilters.WithPriorityAndFairness(handler, c.LongRunningFunc, c.FlowControl)
|
||||
} else {
|
||||
handler = genericfilters.WithMaxInFlightLimit(handler, c.MaxRequestsInFlight, c.MaxMutatingRequestsInFlight, c.LongRunningFunc)
|
||||
}
|
||||
handler = genericapifilters.WithImpersonation(handler, c.Authorization.Authorizer, c.Serializer)
|
||||
handler = genericapifilters.WithAudit(handler, c.AuditBackend, c.AuditPolicyChecker, c.LongRunningFunc)
|
||||
failedHandler := genericapifilters.Unauthorized(c.Serializer, c.Authentication.SupportsBasicAuth)
|
||||
|
|
@ -648,6 +677,10 @@ func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler {
|
|||
handler = genericfilters.WithTimeoutForNonLongRunningRequests(handler, c.LongRunningFunc, c.RequestTimeout)
|
||||
handler = genericfilters.WithWaitGroup(handler, c.LongRunningFunc, c.HandlerChainWaitGroup)
|
||||
handler = genericapifilters.WithRequestInfo(handler, c.RequestInfoResolver)
|
||||
if c.SecureServing != nil && !c.SecureServing.DisableHTTP2 && c.GoawayChance > 0 {
|
||||
handler = genericfilters.WithProbabilisticGoaway(handler, c.GoawayChance)
|
||||
}
|
||||
handler = genericapifilters.WithCacheControl(handler)
|
||||
handler = genericfilters.WithPanicRecovery(handler)
|
||||
return handler
|
||||
}
|
||||
|
|
|
|||
7
vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/configmap_cafile_content.go
generated
vendored
7
vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/configmap_cafile_content.go
generated
vendored
|
|
@ -97,10 +97,7 @@ func NewDynamicCAFromConfigMapController(purpose, namespace, name, key string, k
|
|||
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), fmt.Sprintf("DynamicConfigMapCABundle-%s", purpose)),
|
||||
preRunCaches: []cache.InformerSynced{uncastConfigmapInformer.HasSynced},
|
||||
}
|
||||
if err := c.loadCABundle(); err != nil {
|
||||
// don't fail, but do print out a message
|
||||
klog.Warningf("unable to load initial CA bundle for: %q due to: %s", c.name, err)
|
||||
}
|
||||
|
||||
uncastConfigmapInformer.AddEventHandler(cache.FilteringResourceEventHandler{
|
||||
FilterFunc: func(obj interface{}) bool {
|
||||
if cast, ok := obj.(*corev1.ConfigMap); ok {
|
||||
|
|
@ -217,7 +214,7 @@ func (c *ConfigMapCAController) Run(workers int, stopCh <-chan struct{}) {
|
|||
go wait.Until(c.runWorker, time.Second, stopCh)
|
||||
|
||||
// start timer that rechecks every minute, just in case. this also serves to prime the controller quickly.
|
||||
_ = wait.PollImmediateUntil(FileRefreshDuration, func() (bool, error) {
|
||||
go wait.PollImmediateUntil(FileRefreshDuration, func() (bool, error) {
|
||||
c.queue.Add(workItemKey)
|
||||
return false, nil
|
||||
}, stopCh)
|
||||
|
|
|
|||
3
vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/dynamic_cafile_content.go
generated
vendored
3
vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/dynamic_cafile_content.go
generated
vendored
|
|
@ -126,6 +126,7 @@ func (c *DynamicFileCAContent) loadCABundle() error {
|
|||
return err
|
||||
}
|
||||
c.caBundle.Store(caBundleAndVerifier)
|
||||
klog.V(2).Infof("Loaded a new CA Bundle and Verifier for %q", c.Name())
|
||||
|
||||
for _, listener := range c.listeners {
|
||||
listener.Enqueue()
|
||||
|
|
@ -170,7 +171,7 @@ func (c *DynamicFileCAContent) Run(workers int, stopCh <-chan struct{}) {
|
|||
go wait.Until(c.runWorker, time.Second, stopCh)
|
||||
|
||||
// start timer that rechecks every minute, just in case. this also serves to prime the controller quickly.
|
||||
_ = wait.PollImmediateUntil(FileRefreshDuration, func() (bool, error) {
|
||||
go wait.PollImmediateUntil(FileRefreshDuration, func() (bool, error) {
|
||||
c.queue.Add(workItemKey)
|
||||
return false, nil
|
||||
}, stopCh)
|
||||
|
|
|
|||
49
vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/dynamic_serving_content.go
generated
vendored
49
vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/dynamic_serving_content.go
generated
vendored
|
|
@ -29,8 +29,8 @@ import (
|
|||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
// DynamicFileServingContent provides a CertKeyContentProvider that can dynamically react to new file content
|
||||
type DynamicFileServingContent struct {
|
||||
// DynamicCertKeyPairContent provides a CertKeyContentProvider that can dynamically react to new file content
|
||||
type DynamicCertKeyPairContent struct {
|
||||
name string
|
||||
|
||||
// certFile is the name of the certificate file to read.
|
||||
|
|
@ -39,7 +39,7 @@ type DynamicFileServingContent struct {
|
|||
keyFile string
|
||||
|
||||
// servingCert is a certKeyContent that contains the last read, non-zero length content of the key and cert
|
||||
servingCert atomic.Value
|
||||
certKeyPair atomic.Value
|
||||
|
||||
listeners []Listener
|
||||
|
||||
|
|
@ -47,24 +47,24 @@ type DynamicFileServingContent struct {
|
|||
queue workqueue.RateLimitingInterface
|
||||
}
|
||||
|
||||
var _ Notifier = &DynamicFileServingContent{}
|
||||
var _ CertKeyContentProvider = &DynamicFileServingContent{}
|
||||
var _ ControllerRunner = &DynamicFileServingContent{}
|
||||
var _ Notifier = &DynamicCertKeyPairContent{}
|
||||
var _ CertKeyContentProvider = &DynamicCertKeyPairContent{}
|
||||
var _ ControllerRunner = &DynamicCertKeyPairContent{}
|
||||
|
||||
// NewDynamicServingContentFromFiles returns a dynamic CertKeyContentProvider based on a cert and key filename
|
||||
func NewDynamicServingContentFromFiles(purpose, certFile, keyFile string) (*DynamicFileServingContent, error) {
|
||||
func NewDynamicServingContentFromFiles(purpose, certFile, keyFile string) (*DynamicCertKeyPairContent, error) {
|
||||
if len(certFile) == 0 || len(keyFile) == 0 {
|
||||
return nil, fmt.Errorf("missing filename for serving cert")
|
||||
}
|
||||
name := fmt.Sprintf("%s::%s::%s", purpose, certFile, keyFile)
|
||||
|
||||
ret := &DynamicFileServingContent{
|
||||
ret := &DynamicCertKeyPairContent{
|
||||
name: name,
|
||||
certFile: certFile,
|
||||
keyFile: keyFile,
|
||||
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), fmt.Sprintf("DynamicCABundle-%s", purpose)),
|
||||
}
|
||||
if err := ret.loadServingCert(); err != nil {
|
||||
if err := ret.loadCertKeyPair(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
@ -72,12 +72,12 @@ func NewDynamicServingContentFromFiles(purpose, certFile, keyFile string) (*Dyna
|
|||
}
|
||||
|
||||
// AddListener adds a listener to be notified when the serving cert content changes.
|
||||
func (c *DynamicFileServingContent) AddListener(listener Listener) {
|
||||
func (c *DynamicCertKeyPairContent) AddListener(listener Listener) {
|
||||
c.listeners = append(c.listeners, listener)
|
||||
}
|
||||
|
||||
// loadServingCert determines the next set of content for the file.
|
||||
func (c *DynamicFileServingContent) loadServingCert() error {
|
||||
func (c *DynamicCertKeyPairContent) loadCertKeyPair() error {
|
||||
cert, err := ioutil.ReadFile(c.certFile)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -102,12 +102,13 @@ func (c *DynamicFileServingContent) loadServingCert() error {
|
|||
}
|
||||
|
||||
// check to see if we have a change. If the values are the same, do nothing.
|
||||
existing, ok := c.servingCert.Load().(*certKeyContent)
|
||||
existing, ok := c.certKeyPair.Load().(*certKeyContent)
|
||||
if ok && existing != nil && existing.Equal(newCertKey) {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.servingCert.Store(newCertKey)
|
||||
c.certKeyPair.Store(newCertKey)
|
||||
klog.V(2).Infof("Loaded a new cert/key pair for %q", c.Name())
|
||||
|
||||
for _, listener := range c.listeners {
|
||||
listener.Enqueue()
|
||||
|
|
@ -117,12 +118,12 @@ func (c *DynamicFileServingContent) loadServingCert() error {
|
|||
}
|
||||
|
||||
// RunOnce runs a single sync loop
|
||||
func (c *DynamicFileServingContent) RunOnce() error {
|
||||
return c.loadServingCert()
|
||||
func (c *DynamicCertKeyPairContent) RunOnce() error {
|
||||
return c.loadCertKeyPair()
|
||||
}
|
||||
|
||||
// Run starts the controller and blocks until stopCh is closed.
|
||||
func (c *DynamicFileServingContent) Run(workers int, stopCh <-chan struct{}) {
|
||||
func (c *DynamicCertKeyPairContent) Run(workers int, stopCh <-chan struct{}) {
|
||||
defer utilruntime.HandleCrash()
|
||||
defer c.queue.ShutDown()
|
||||
|
||||
|
|
@ -133,7 +134,7 @@ func (c *DynamicFileServingContent) Run(workers int, stopCh <-chan struct{}) {
|
|||
go wait.Until(c.runWorker, time.Second, stopCh)
|
||||
|
||||
// start timer that rechecks every minute, just in case. this also serves to prime the controller quickly.
|
||||
_ = wait.PollImmediateUntil(FileRefreshDuration, func() (bool, error) {
|
||||
go wait.PollImmediateUntil(FileRefreshDuration, func() (bool, error) {
|
||||
c.queue.Add(workItemKey)
|
||||
return false, nil
|
||||
}, stopCh)
|
||||
|
|
@ -143,19 +144,19 @@ func (c *DynamicFileServingContent) Run(workers int, stopCh <-chan struct{}) {
|
|||
<-stopCh
|
||||
}
|
||||
|
||||
func (c *DynamicFileServingContent) runWorker() {
|
||||
func (c *DynamicCertKeyPairContent) runWorker() {
|
||||
for c.processNextWorkItem() {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *DynamicFileServingContent) processNextWorkItem() bool {
|
||||
func (c *DynamicCertKeyPairContent) processNextWorkItem() bool {
|
||||
dsKey, quit := c.queue.Get()
|
||||
if quit {
|
||||
return false
|
||||
}
|
||||
defer c.queue.Done(dsKey)
|
||||
|
||||
err := c.loadServingCert()
|
||||
err := c.loadCertKeyPair()
|
||||
if err == nil {
|
||||
c.queue.Forget(dsKey)
|
||||
return true
|
||||
|
|
@ -168,12 +169,12 @@ func (c *DynamicFileServingContent) processNextWorkItem() bool {
|
|||
}
|
||||
|
||||
// Name is just an identifier
|
||||
func (c *DynamicFileServingContent) Name() string {
|
||||
func (c *DynamicCertKeyPairContent) Name() string {
|
||||
return c.name
|
||||
}
|
||||
|
||||
// CurrentCertKeyContent provides serving cert byte content
|
||||
func (c *DynamicFileServingContent) CurrentCertKeyContent() ([]byte, []byte) {
|
||||
certKeyContent := c.servingCert.Load().(*certKeyContent)
|
||||
// CurrentCertKeyContent provides cert and key byte content
|
||||
func (c *DynamicCertKeyPairContent) CurrentCertKeyContent() ([]byte, []byte) {
|
||||
certKeyContent := c.certKeyPair.Load().(*certKeyContent)
|
||||
return certKeyContent.cert, certKeyContent.key
|
||||
}
|
||||
|
|
|
|||
6
vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/dynamic_sni_content.go
generated
vendored
6
vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/dynamic_sni_content.go
generated
vendored
|
|
@ -18,7 +18,7 @@ package dynamiccertificates
|
|||
|
||||
// DynamicFileSNIContent provides a SNICertKeyContentProvider that can dynamically react to new file content
|
||||
type DynamicFileSNIContent struct {
|
||||
*DynamicFileServingContent
|
||||
*DynamicCertKeyPairContent
|
||||
sniNames []string
|
||||
}
|
||||
|
||||
|
|
@ -34,10 +34,10 @@ func NewDynamicSNIContentFromFiles(purpose, certFile, keyFile string, sniNames .
|
|||
}
|
||||
|
||||
ret := &DynamicFileSNIContent{
|
||||
DynamicFileServingContent: servingContent,
|
||||
DynamicCertKeyPairContent: servingContent,
|
||||
sniNames: sniNames,
|
||||
}
|
||||
if err := ret.loadServingCert(); err != nil {
|
||||
if err := ret.loadCertKeyPair(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
|
|||
10
vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/named_certificates.go
generated
vendored
10
vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/named_certificates.go
generated
vendored
|
|
@ -20,9 +20,10 @@ import (
|
|||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
|
@ -51,7 +52,7 @@ func (c *DynamicServingCertificateController) BuildNamedCertificates(sniCerts []
|
|||
|
||||
klog.V(2).Infof("loaded SNI cert [%d/%q]: %s", i, c.sniCerts[i].Name(), GetHumanCertDetail(x509Cert))
|
||||
if c.eventRecorder != nil {
|
||||
c.eventRecorder.Eventf(nil, nil, v1.EventTypeWarning, "TLSConfigChanged", "SNICertificateReload", "loaded SNI cert [%d/%q]: %s with explicit names %v", i, c.sniCerts[i].Name(), GetHumanCertDetail(x509Cert), names)
|
||||
c.eventRecorder.Eventf(&corev1.ObjectReference{Name: c.sniCerts[i].Name()}, nil, corev1.EventTypeWarning, "TLSConfigChanged", "SNICertificateReload", "loaded SNI cert [%d/%q]: %s with explicit names %v", i, c.sniCerts[i].Name(), GetHumanCertDetail(x509Cert), names)
|
||||
}
|
||||
|
||||
if len(names) == 0 {
|
||||
|
|
@ -76,7 +77,10 @@ func getCertificateNames(cert *x509.Certificate) []string {
|
|||
var names []string
|
||||
|
||||
cn := cert.Subject.CommonName
|
||||
if cn == "*" || len(validation.IsDNS1123Subdomain(strings.TrimPrefix(cn, "*."))) == 0 {
|
||||
cnIsIP := net.ParseIP(cn) != nil
|
||||
cnIsValidDomain := cn == "*" || len(validation.IsDNS1123Subdomain(strings.TrimPrefix(cn, "*."))) == 0
|
||||
// don't use the CN if it is a valid IP because our IP serving detection may unexpectedly use it to terminate the connection.
|
||||
if !cnIsIP && cnIsValidDomain {
|
||||
names = append(names, cn)
|
||||
}
|
||||
for _, san := range cert.DNSNames {
|
||||
|
|
|
|||
57
vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/static_content.go
generated
vendored
57
vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/static_content.go
generated
vendored
|
|
@ -19,8 +19,6 @@ package dynamiccertificates
|
|||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
type staticCAContent struct {
|
||||
|
|
@ -30,19 +28,6 @@ type staticCAContent struct {
|
|||
|
||||
var _ CAContentProvider = &staticCAContent{}
|
||||
|
||||
// NewStaticCAContentFromFile returns a CAContentProvider based on a filename
|
||||
func NewStaticCAContentFromFile(filename string) (CAContentProvider, error) {
|
||||
if len(filename) == 0 {
|
||||
return nil, fmt.Errorf("missing filename for ca bundle")
|
||||
}
|
||||
|
||||
caBundle, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewStaticCAContent(filename, caBundle)
|
||||
}
|
||||
|
||||
// NewStaticCAContent returns a CAContentProvider that always returns the same value
|
||||
func NewStaticCAContent(name string, caBundle []byte) (CAContentProvider, error) {
|
||||
caBundleAndVerifier, err := newCABundleAndVerifier(name, caBundle)
|
||||
|
|
@ -81,48 +66,6 @@ type staticSNICertKeyContent struct {
|
|||
sniNames []string
|
||||
}
|
||||
|
||||
// NewStaticCertKeyContentFromFiles returns a CertKeyContentProvider based on a filename
|
||||
func NewStaticCertKeyContentFromFiles(certFile, keyFile string) (CertKeyContentProvider, error) {
|
||||
if len(certFile) == 0 {
|
||||
return nil, fmt.Errorf("missing filename for certificate")
|
||||
}
|
||||
if len(keyFile) == 0 {
|
||||
return nil, fmt.Errorf("missing filename for key")
|
||||
}
|
||||
|
||||
certPEMBlock, err := ioutil.ReadFile(certFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keyPEMBlock, err := ioutil.ReadFile(keyFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewStaticCertKeyContent(fmt.Sprintf("cert: %s, key: %s", certFile, keyFile), certPEMBlock, keyPEMBlock)
|
||||
}
|
||||
|
||||
// NewStaticSNICertKeyContentFromFiles returns a SNICertKeyContentProvider based on a filename
|
||||
func NewStaticSNICertKeyContentFromFiles(certFile, keyFile string, sniNames ...string) (SNICertKeyContentProvider, error) {
|
||||
if len(certFile) == 0 {
|
||||
return nil, fmt.Errorf("missing filename for certificate")
|
||||
}
|
||||
if len(keyFile) == 0 {
|
||||
return nil, fmt.Errorf("missing filename for key")
|
||||
}
|
||||
|
||||
certPEMBlock, err := ioutil.ReadFile(certFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keyPEMBlock, err := ioutil.ReadFile(keyFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewStaticSNICertKeyContent(fmt.Sprintf("cert: %s, key: %s", certFile, keyFile), certPEMBlock, keyPEMBlock, sniNames...)
|
||||
}
|
||||
|
||||
// NewStaticCertKeyContent returns a CertKeyContentProvider that always returns the same value
|
||||
func NewStaticCertKeyContent(name string, cert, key []byte) (CertKeyContentProvider, error) {
|
||||
// Ensure that the key matches the cert and both are valid
|
||||
|
|
|
|||
35
vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/tlsconfig.go
generated
vendored
35
vendor/k8s.io/apiserver/pkg/server/dynamiccertificates/tlsconfig.go
generated
vendored
|
|
@ -21,11 +21,11 @@ import (
|
|||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/tools/events"
|
||||
|
|
@ -40,7 +40,7 @@ const workItemKey = "key"
|
|||
type DynamicServingCertificateController struct {
|
||||
// baseTLSConfig is the static portion of the tlsConfig for serving to clients. It is copied and the copy is mutated
|
||||
// based on the dynamic cert state.
|
||||
baseTLSConfig tls.Config
|
||||
baseTLSConfig *tls.Config
|
||||
|
||||
// clientCA provides the very latest content of the ca bundle
|
||||
clientCA CAContentProvider
|
||||
|
|
@ -64,7 +64,7 @@ var _ Listener = &DynamicServingCertificateController{}
|
|||
|
||||
// NewDynamicServingCertificateController returns a controller that can be used to keep a TLSConfig up to date.
|
||||
func NewDynamicServingCertificateController(
|
||||
baseTLSConfig tls.Config,
|
||||
baseTLSConfig *tls.Config,
|
||||
clientCA CAContentProvider,
|
||||
servingCert CertKeyContentProvider,
|
||||
sniCerts []SNICertKeyContentProvider,
|
||||
|
|
@ -94,7 +94,28 @@ func (c *DynamicServingCertificateController) GetConfigForClient(clientHello *tl
|
|||
return nil, errors.New("dynamiccertificates: unexpected config type")
|
||||
}
|
||||
|
||||
return tlsConfig.Clone(), nil
|
||||
tlsConfigCopy := tlsConfig.Clone()
|
||||
|
||||
// if the client set SNI information, just use our "normal" SNI flow
|
||||
if len(clientHello.ServerName) > 0 {
|
||||
return tlsConfigCopy, nil
|
||||
}
|
||||
|
||||
// if the client didn't set SNI, then we need to inspect the requested IP so that we can choose
|
||||
// a certificate from our list if we specifically handle that IP. This can happen when an IP is specifically mapped by name.
|
||||
host, _, err := net.SplitHostPort(clientHello.Conn.LocalAddr().String())
|
||||
if err != nil {
|
||||
return tlsConfigCopy, nil
|
||||
}
|
||||
|
||||
ipCert, ok := tlsConfigCopy.NameToCertificate[host]
|
||||
if !ok {
|
||||
return tlsConfigCopy, nil
|
||||
}
|
||||
tlsConfigCopy.Certificates = []tls.Certificate{*ipCert}
|
||||
tlsConfigCopy.NameToCertificate = nil
|
||||
|
||||
return tlsConfigCopy, nil
|
||||
}
|
||||
|
||||
// newTLSContent determines the next set of content for overriding the baseTLSConfig.
|
||||
|
|
@ -156,7 +177,7 @@ func (c *DynamicServingCertificateController) syncCerts() error {
|
|||
for i, cert := range newClientCAs {
|
||||
klog.V(2).Infof("loaded client CA [%d/%q]: %s", i, c.clientCA.Name(), GetHumanCertDetail(cert))
|
||||
if c.eventRecorder != nil {
|
||||
c.eventRecorder.Eventf(nil, nil, v1.EventTypeWarning, "TLSConfigChanged", "CACertificateReload", "loaded client CA [%d/%q]: %s", i, c.clientCA.Name(), GetHumanCertDetail(cert))
|
||||
c.eventRecorder.Eventf(&corev1.ObjectReference{Name: c.clientCA.Name()}, nil, corev1.EventTypeWarning, "TLSConfigChanged", "CACertificateReload", "loaded client CA [%d/%q]: %s", i, c.clientCA.Name(), GetHumanCertDetail(cert))
|
||||
}
|
||||
|
||||
newClientCAPool.AddCert(cert)
|
||||
|
|
@ -178,7 +199,7 @@ func (c *DynamicServingCertificateController) syncCerts() error {
|
|||
|
||||
klog.V(2).Infof("loaded serving cert [%q]: %s", c.servingCert.Name(), GetHumanCertDetail(x509Cert))
|
||||
if c.eventRecorder != nil {
|
||||
c.eventRecorder.Eventf(nil, nil, v1.EventTypeWarning, "TLSConfigChanged", "ServingCertificateReload", "loaded serving cert [%q]: %s", c.clientCA.Name(), GetHumanCertDetail(x509Cert))
|
||||
c.eventRecorder.Eventf(&corev1.ObjectReference{Name: c.servingCert.Name()}, nil, corev1.EventTypeWarning, "TLSConfigChanged", "ServingCertificateReload", "loaded serving cert [%q]: %s", c.servingCert.Name(), GetHumanCertDetail(x509Cert))
|
||||
}
|
||||
|
||||
newTLSConfigCopy.Certificates = []tls.Certificate{cert}
|
||||
|
|
|
|||
196
vendor/k8s.io/apiserver/pkg/server/egressselector/config.go
generated
vendored
196
vendor/k8s.io/apiserver/pkg/server/egressselector/config.go
generated
vendored
|
|
@ -25,7 +25,7 @@ import (
|
|||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/apiserver/pkg/apis/apiserver"
|
||||
"k8s.io/apiserver/pkg/apis/apiserver/install"
|
||||
"k8s.io/apiserver/pkg/apis/apiserver/v1alpha1"
|
||||
"k8s.io/apiserver/pkg/apis/apiserver/v1beta1"
|
||||
"k8s.io/utils/path"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
|
@ -51,7 +51,7 @@ func ReadEgressSelectorConfiguration(configFilePath string) (*apiserver.EgressSe
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to read egress selector configuration from %q [%v]", configFilePath, err)
|
||||
}
|
||||
var decodedConfig v1alpha1.EgressSelectorConfiguration
|
||||
var decodedConfig v1beta1.EgressSelectorConfiguration
|
||||
err = yaml.Unmarshal(data, &decodedConfig)
|
||||
if err != nil {
|
||||
// we got an error where the decode wasn't related to a missing type
|
||||
|
|
@ -78,99 +78,155 @@ func ValidateEgressSelectorConfiguration(config *apiserver.EgressSelectorConfigu
|
|||
return allErrs // Treating a nil configuration as valid
|
||||
}
|
||||
for _, service := range config.EgressSelections {
|
||||
base := field.NewPath("service", "connection")
|
||||
switch service.Connection.Type {
|
||||
case "direct":
|
||||
allErrs = append(allErrs, validateDirectConnection(service.Connection, base)...)
|
||||
case "http-connect":
|
||||
allErrs = append(allErrs, validateHTTPConnection(service.Connection, base)...)
|
||||
fldPath := field.NewPath("service", "connection")
|
||||
switch service.Connection.ProxyProtocol {
|
||||
case apiserver.ProtocolDirect:
|
||||
allErrs = append(allErrs, validateDirectConnection(service.Connection, fldPath)...)
|
||||
case apiserver.ProtocolHTTPConnect:
|
||||
allErrs = append(allErrs, validateHTTPConnectTransport(service.Connection.Transport, fldPath)...)
|
||||
case apiserver.ProtocolGRPC:
|
||||
allErrs = append(allErrs, validateGRPCTransport(service.Connection.Transport, fldPath)...)
|
||||
default:
|
||||
allErrs = append(allErrs, field.NotSupported(
|
||||
base.Child("type"),
|
||||
service.Connection.Type,
|
||||
[]string{"direct", "http-connect"}))
|
||||
fldPath.Child("protocol"),
|
||||
service.Connection.ProxyProtocol,
|
||||
[]string{
|
||||
string(apiserver.ProtocolDirect),
|
||||
string(apiserver.ProtocolHTTPConnect),
|
||||
string(apiserver.ProtocolGRPC),
|
||||
}))
|
||||
}
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateHTTPConnectTransport(transport *apiserver.Transport, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if transport == nil {
|
||||
allErrs = append(allErrs, field.Required(
|
||||
fldPath.Child("transport"),
|
||||
"transport must be set for HTTPConnect"))
|
||||
return allErrs
|
||||
}
|
||||
|
||||
if transport.TCP != nil && transport.UDS != nil {
|
||||
allErrs = append(allErrs, field.Invalid(
|
||||
fldPath.Child("tcp"),
|
||||
transport.TCP,
|
||||
"TCP and UDS cannot both be set"))
|
||||
} else if transport.TCP == nil && transport.UDS == nil {
|
||||
allErrs = append(allErrs, field.Required(
|
||||
fldPath.Child("tcp"),
|
||||
"One of TCP or UDS must be set"))
|
||||
} else if transport.TCP != nil {
|
||||
allErrs = append(allErrs, validateTCPConnection(transport.TCP, fldPath)...)
|
||||
} else if transport.UDS != nil {
|
||||
allErrs = append(allErrs, validateUDSConnection(transport.UDS, fldPath)...)
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateGRPCTransport(transport *apiserver.Transport, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if transport == nil {
|
||||
allErrs = append(allErrs, field.Required(
|
||||
fldPath.Child("transport"),
|
||||
"transport must be set for GRPC"))
|
||||
return allErrs
|
||||
}
|
||||
|
||||
if transport.UDS != nil {
|
||||
allErrs = append(allErrs, validateUDSConnection(transport.UDS, fldPath)...)
|
||||
} else {
|
||||
allErrs = append(allErrs, field.Required(
|
||||
fldPath.Child("uds"),
|
||||
"UDS must be set with GRPC"))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateDirectConnection(connection apiserver.Connection, fldPath *field.Path) field.ErrorList {
|
||||
if connection.HTTPConnect != nil {
|
||||
if connection.Transport != nil {
|
||||
return field.ErrorList{field.Invalid(
|
||||
fldPath.Child("httpConnect"),
|
||||
fldPath.Child("transport"),
|
||||
"direct",
|
||||
"httpConnect config should be absent for direct connect"),
|
||||
"Transport config should be absent for direct connect"),
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateHTTPConnection(connection apiserver.Connection, fldPath *field.Path) field.ErrorList {
|
||||
func validateUDSConnection(udsConfig *apiserver.UDSTransport, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if connection.HTTPConnect == nil {
|
||||
if udsConfig.UDSName == "" {
|
||||
allErrs = append(allErrs, field.Invalid(
|
||||
fldPath.Child("httpConnect"),
|
||||
fldPath.Child("udsName"),
|
||||
"nil",
|
||||
"httpConnect config should be present for http-connect"))
|
||||
} else if strings.HasPrefix(connection.HTTPConnect.URL, "https://") {
|
||||
if connection.HTTPConnect.CABundle == "" {
|
||||
"UDSName should be present for UDS connections"))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateTCPConnection(tcpConfig *apiserver.TCPTransport, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
if strings.HasPrefix(tcpConfig.URL, "http://") {
|
||||
if tcpConfig.TLSConfig != nil {
|
||||
allErrs = append(allErrs, field.Invalid(
|
||||
fldPath.Child("httpConnect", "caBundle"),
|
||||
fldPath.Child("tlsConfig"),
|
||||
"nil",
|
||||
"http-connect via https requires caBundle"))
|
||||
} else if exists, err := path.Exists(path.CheckFollowSymlink, connection.HTTPConnect.CABundle); exists == false || err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(
|
||||
fldPath.Child("httpConnect", "caBundle"),
|
||||
connection.HTTPConnect.CABundle,
|
||||
"http-connect ca bundle does not exist"))
|
||||
}
|
||||
if connection.HTTPConnect.ClientCert == "" {
|
||||
allErrs = append(allErrs, field.Invalid(
|
||||
fldPath.Child("httpConnect", "clientCert"),
|
||||
"nil",
|
||||
"http-connect via https requires clientCert"))
|
||||
} else if exists, err := path.Exists(path.CheckFollowSymlink, connection.HTTPConnect.ClientCert); exists == false || err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(
|
||||
fldPath.Child("httpConnect", "clientCert"),
|
||||
connection.HTTPConnect.ClientCert,
|
||||
"http-connect client cert does not exist"))
|
||||
}
|
||||
if connection.HTTPConnect.ClientKey == "" {
|
||||
allErrs = append(allErrs, field.Invalid(
|
||||
fldPath.Child("httpConnect", "clientKey"),
|
||||
"nil",
|
||||
"http-connect via https requires clientKey"))
|
||||
} else if exists, err := path.Exists(path.CheckFollowSymlink, connection.HTTPConnect.ClientKey); exists == false || err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(
|
||||
fldPath.Child("httpConnect", "clientKey"),
|
||||
connection.HTTPConnect.ClientKey,
|
||||
"http-connect client key does not exist"))
|
||||
}
|
||||
} else if strings.HasPrefix(connection.HTTPConnect.URL, "http://") {
|
||||
if connection.HTTPConnect.CABundle != "" {
|
||||
allErrs = append(allErrs, field.Invalid(
|
||||
fldPath.Child("httpConnect", "caBundle"),
|
||||
connection.HTTPConnect.CABundle,
|
||||
"http-connect via http does not support caBundle"))
|
||||
}
|
||||
if connection.HTTPConnect.ClientCert != "" {
|
||||
allErrs = append(allErrs, field.Invalid(
|
||||
fldPath.Child("httpConnect", "clientCert"),
|
||||
connection.HTTPConnect.ClientCert,
|
||||
"http-connect via http does not support clientCert"))
|
||||
}
|
||||
if connection.HTTPConnect.ClientKey != "" {
|
||||
allErrs = append(allErrs, field.Invalid(
|
||||
fldPath.Child("httpConnect", "clientKey"),
|
||||
connection.HTTPConnect.ClientKey,
|
||||
"http-connect via http does not support clientKey"))
|
||||
"TLSConfig config should not be present when using HTTP"))
|
||||
}
|
||||
} else if strings.HasPrefix(tcpConfig.URL, "https://") {
|
||||
return validateTLSConfig(tcpConfig.TLSConfig, fldPath)
|
||||
} else {
|
||||
allErrs = append(allErrs, field.Invalid(
|
||||
fldPath.Child("httpConnect", "url"),
|
||||
connection.HTTPConnect.URL,
|
||||
fldPath.Child("url"),
|
||||
tcpConfig.URL,
|
||||
"supported connection protocols are http:// and https://"))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateTLSConfig(tlsConfig *apiserver.TLSConfig, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
if tlsConfig == nil {
|
||||
allErrs = append(allErrs, field.Required(
|
||||
fldPath.Child("tlsConfig"),
|
||||
"TLSConfig must be present when using HTTPS"))
|
||||
return allErrs
|
||||
}
|
||||
if tlsConfig.CABundle != "" {
|
||||
if exists, err := path.Exists(path.CheckFollowSymlink, tlsConfig.CABundle); exists == false || err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(
|
||||
fldPath.Child("tlsConfig", "caBundle"),
|
||||
tlsConfig.CABundle,
|
||||
"TLS config ca bundle does not exist"))
|
||||
}
|
||||
}
|
||||
if tlsConfig.ClientCert == "" {
|
||||
allErrs = append(allErrs, field.Invalid(
|
||||
fldPath.Child("tlsConfig", "clientCert"),
|
||||
"nil",
|
||||
"Using TLS requires clientCert"))
|
||||
} else if exists, err := path.Exists(path.CheckFollowSymlink, tlsConfig.ClientCert); exists == false || err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(
|
||||
fldPath.Child("tlsConfig", "clientCert"),
|
||||
tlsConfig.ClientCert,
|
||||
"TLS client cert does not exist"))
|
||||
}
|
||||
if tlsConfig.ClientKey == "" {
|
||||
allErrs = append(allErrs, field.Invalid(
|
||||
fldPath.Child("tlsConfig", "clientKey"),
|
||||
"nil",
|
||||
"Using TLS requires requires clientKey"))
|
||||
} else if exists, err := path.Exists(path.CheckFollowSymlink, tlsConfig.ClientKey); exists == false || err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(
|
||||
fldPath.Child("tlsConfig", "clientKey"),
|
||||
tlsConfig.ClientKey,
|
||||
"TLS client key does not exist"))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
|
|
|||
293
vendor/k8s.io/apiserver/pkg/server/egressselector/egress_selector.go
generated
vendored
293
vendor/k8s.io/apiserver/pkg/server/egressselector/egress_selector.go
generated
vendored
|
|
@ -23,13 +23,20 @@ import (
|
|||
"crypto/x509"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
"k8s.io/apiserver/pkg/apis/apiserver"
|
||||
"k8s.io/klog"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
"k8s.io/apiserver/pkg/apis/apiserver"
|
||||
egressmetrics "k8s.io/apiserver/pkg/server/egressselector/metrics"
|
||||
"k8s.io/klog"
|
||||
utiltrace "k8s.io/utils/trace"
|
||||
client "sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client"
|
||||
)
|
||||
|
||||
var directDialer utilnet.DialFunc = http.DefaultTransport.(*http.Transport).DialContext
|
||||
|
|
@ -94,67 +101,236 @@ func lookupServiceName(name string) (EgressType, error) {
|
|||
return -1, fmt.Errorf("unrecognized service name %s", name)
|
||||
}
|
||||
|
||||
func createConnectDialer(connectConfig *apiserver.HTTPConnectConfig) (utilnet.DialFunc, error) {
|
||||
clientCert := connectConfig.ClientCert
|
||||
clientKey := connectConfig.ClientKey
|
||||
caCert := connectConfig.CABundle
|
||||
proxyURL, err := url.Parse(connectConfig.URL)
|
||||
func tunnelHTTPConnect(proxyConn net.Conn, proxyAddress, addr string) (net.Conn, error) {
|
||||
fmt.Fprintf(proxyConn, "CONNECT %s HTTP/1.1\r\nHost: %s\r\n\r\n", addr, "127.0.0.1")
|
||||
br := bufio.NewReader(proxyConn)
|
||||
res, err := http.ReadResponse(br, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid proxy server url %q: %v", connectConfig.URL, err)
|
||||
proxyConn.Close()
|
||||
return nil, fmt.Errorf("reading HTTP response from CONNECT to %s via proxy %s failed: %v",
|
||||
addr, proxyAddress, err)
|
||||
}
|
||||
if res.StatusCode != 200 {
|
||||
proxyConn.Close()
|
||||
return nil, fmt.Errorf("proxy error from %s while dialing %s, code %d: %v",
|
||||
proxyAddress, addr, res.StatusCode, res.Status)
|
||||
}
|
||||
proxyAddress := proxyURL.Host
|
||||
|
||||
// It's safe to discard the bufio.Reader here and return the
|
||||
// original TCP conn directly because we only use this for
|
||||
// TLS, and in TLS the client speaks first, so we know there's
|
||||
// no unbuffered data. But we can double-check.
|
||||
if br.Buffered() > 0 {
|
||||
proxyConn.Close()
|
||||
return nil, fmt.Errorf("unexpected %d bytes of buffered data from CONNECT proxy %q",
|
||||
br.Buffered(), proxyAddress)
|
||||
}
|
||||
return proxyConn, nil
|
||||
}
|
||||
|
||||
type proxier interface {
|
||||
// proxy returns a connection to addr.
|
||||
proxy(addr string) (net.Conn, error)
|
||||
}
|
||||
|
||||
var _ proxier = &httpConnectProxier{}
|
||||
|
||||
type httpConnectProxier struct {
|
||||
conn net.Conn
|
||||
proxyAddress string
|
||||
}
|
||||
|
||||
func (t *httpConnectProxier) proxy(addr string) (net.Conn, error) {
|
||||
return tunnelHTTPConnect(t.conn, t.proxyAddress, addr)
|
||||
}
|
||||
|
||||
var _ proxier = &grpcProxier{}
|
||||
|
||||
type grpcProxier struct {
|
||||
tunnel client.Tunnel
|
||||
}
|
||||
|
||||
func (g *grpcProxier) proxy(addr string) (net.Conn, error) {
|
||||
return g.tunnel.Dial("tcp", addr)
|
||||
}
|
||||
|
||||
type proxyServerConnector interface {
|
||||
// connect establishes connection to the proxy server, and returns a
|
||||
// proxier based on the connection.
|
||||
connect() (proxier, error)
|
||||
}
|
||||
|
||||
type tcpHTTPConnectConnector struct {
|
||||
proxyAddress string
|
||||
tlsConfig *tls.Config
|
||||
}
|
||||
|
||||
func (t *tcpHTTPConnectConnector) connect() (proxier, error) {
|
||||
conn, err := tls.Dial("tcp", t.proxyAddress, t.tlsConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &httpConnectProxier{conn: conn, proxyAddress: t.proxyAddress}, nil
|
||||
}
|
||||
|
||||
type udsHTTPConnectConnector struct {
|
||||
udsName string
|
||||
}
|
||||
|
||||
func (u *udsHTTPConnectConnector) connect() (proxier, error) {
|
||||
conn, err := net.Dial("unix", u.udsName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &httpConnectProxier{conn: conn, proxyAddress: u.udsName}, nil
|
||||
}
|
||||
|
||||
type udsGRPCConnector struct {
|
||||
udsName string
|
||||
}
|
||||
|
||||
func (u *udsGRPCConnector) connect() (proxier, error) {
|
||||
udsName := u.udsName
|
||||
dialOption := grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) {
|
||||
c, err := net.Dial("unix", udsName)
|
||||
if err != nil {
|
||||
klog.Errorf("failed to create connection to uds name %s, error: %v", udsName, err)
|
||||
}
|
||||
return c, err
|
||||
})
|
||||
|
||||
tunnel, err := client.CreateGrpcTunnel(udsName, dialOption, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &grpcProxier{tunnel: tunnel}, nil
|
||||
}
|
||||
|
||||
type dialerCreator struct {
|
||||
connector proxyServerConnector
|
||||
direct bool
|
||||
options metricsOptions
|
||||
}
|
||||
|
||||
type metricsOptions struct {
|
||||
transport string
|
||||
protocol string
|
||||
}
|
||||
|
||||
func (d *dialerCreator) createDialer() utilnet.DialFunc {
|
||||
if d.direct {
|
||||
return directDialer
|
||||
}
|
||||
return func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
trace := utiltrace.New(fmt.Sprintf("Proxy via HTTP Connect over %s", d.options.transport), utiltrace.Field{Key: "address", Value: addr})
|
||||
defer trace.LogIfLong(500 * time.Millisecond)
|
||||
start := egressmetrics.Metrics.Clock().Now()
|
||||
proxier, err := d.connector.connect()
|
||||
if err != nil {
|
||||
egressmetrics.Metrics.ObserveDialFailure(d.options.protocol, d.options.transport, egressmetrics.StageConnect)
|
||||
return nil, err
|
||||
}
|
||||
conn, err := proxier.proxy(addr)
|
||||
if err != nil {
|
||||
egressmetrics.Metrics.ObserveDialFailure(d.options.protocol, d.options.transport, egressmetrics.StageProxy)
|
||||
return nil, err
|
||||
}
|
||||
egressmetrics.Metrics.ObserveDialLatency(egressmetrics.Metrics.Clock().Now().Sub(start), d.options.protocol, d.options.transport)
|
||||
return conn, nil
|
||||
}
|
||||
}
|
||||
|
||||
func getTLSConfig(t *apiserver.TLSConfig) (*tls.Config, error) {
|
||||
clientCert := t.ClientCert
|
||||
clientKey := t.ClientKey
|
||||
caCert := t.CABundle
|
||||
clientCerts, err := tls.LoadX509KeyPair(clientCert, clientKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read key pair %s & %s, got %v", clientCert, clientKey, err)
|
||||
}
|
||||
certPool := x509.NewCertPool()
|
||||
certBytes, err := ioutil.ReadFile(caCert)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read cert file %s, got %v", caCert, err)
|
||||
}
|
||||
ok := certPool.AppendCertsFromPEM(certBytes)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to append CA cert to the cert pool")
|
||||
}
|
||||
contextDialer := func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
klog.V(4).Infof("Sending request to %q.", addr)
|
||||
proxyConn, err := tls.Dial("tcp", proxyAddress,
|
||||
&tls.Config{
|
||||
Certificates: []tls.Certificate{clientCerts},
|
||||
RootCAs: certPool,
|
||||
},
|
||||
)
|
||||
if caCert != "" {
|
||||
certBytes, err := ioutil.ReadFile(caCert)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("dialing proxy %q failed: %v", proxyAddress, err)
|
||||
return nil, fmt.Errorf("failed to read cert file %s, got %v", caCert, err)
|
||||
}
|
||||
fmt.Fprintf(proxyConn, "CONNECT %s HTTP/1.1\r\nHost: %s\r\n\r\n", addr, "127.0.0.1")
|
||||
br := bufio.NewReader(proxyConn)
|
||||
res, err := http.ReadResponse(br, nil)
|
||||
if err != nil {
|
||||
proxyConn.Close()
|
||||
return nil, fmt.Errorf("reading HTTP response from CONNECT to %s via proxy %s failed: %v",
|
||||
addr, proxyAddress, err)
|
||||
}
|
||||
if res.StatusCode != 200 {
|
||||
proxyConn.Close()
|
||||
return nil, fmt.Errorf("proxy error from %s while dialing %s, code %d: %v",
|
||||
proxyAddress, addr, res.StatusCode, res.Status)
|
||||
ok := certPool.AppendCertsFromPEM(certBytes)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to append CA cert to the cert pool")
|
||||
}
|
||||
} else {
|
||||
// Use host's root CA set instead of providing our own
|
||||
certPool = nil
|
||||
}
|
||||
return &tls.Config{
|
||||
Certificates: []tls.Certificate{clientCerts},
|
||||
RootCAs: certPool,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// It's safe to discard the bufio.Reader here and return the
|
||||
// original TCP conn directly because we only use this for
|
||||
// TLS, and in TLS the client speaks first, so we know there's
|
||||
// no unbuffered data. But we can double-check.
|
||||
if br.Buffered() > 0 {
|
||||
proxyConn.Close()
|
||||
return nil, fmt.Errorf("unexpected %d bytes of buffered data from CONNECT proxy %q",
|
||||
br.Buffered(), proxyAddress)
|
||||
}
|
||||
klog.V(4).Infof("About to proxy request to %s over %s.", addr, proxyAddress)
|
||||
return proxyConn, nil
|
||||
func getProxyAddress(urlString string) (string, error) {
|
||||
proxyURL, err := url.Parse(urlString)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("invalid proxy server url %q: %v", urlString, err)
|
||||
}
|
||||
return contextDialer, nil
|
||||
return proxyURL.Host, nil
|
||||
}
|
||||
|
||||
func connectionToDialerCreator(c apiserver.Connection) (*dialerCreator, error) {
|
||||
switch c.ProxyProtocol {
|
||||
|
||||
case apiserver.ProtocolHTTPConnect:
|
||||
if c.Transport.UDS != nil {
|
||||
return &dialerCreator{
|
||||
connector: &udsHTTPConnectConnector{
|
||||
udsName: c.Transport.UDS.UDSName,
|
||||
},
|
||||
options: metricsOptions{
|
||||
transport: egressmetrics.TransportUDS,
|
||||
protocol: egressmetrics.ProtocolHTTPConnect,
|
||||
},
|
||||
}, nil
|
||||
} else if c.Transport.TCP != nil {
|
||||
tlsConfig, err := getTLSConfig(c.Transport.TCP.TLSConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
proxyAddress, err := getProxyAddress(c.Transport.TCP.URL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &dialerCreator{
|
||||
connector: &tcpHTTPConnectConnector{
|
||||
tlsConfig: tlsConfig,
|
||||
proxyAddress: proxyAddress,
|
||||
},
|
||||
options: metricsOptions{
|
||||
transport: egressmetrics.TransportTCP,
|
||||
protocol: egressmetrics.ProtocolHTTPConnect,
|
||||
},
|
||||
}, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("Either a TCP or UDS transport must be specified")
|
||||
}
|
||||
case apiserver.ProtocolGRPC:
|
||||
if c.Transport.UDS != nil {
|
||||
return &dialerCreator{
|
||||
connector: &udsGRPCConnector{
|
||||
udsName: c.Transport.UDS.UDSName,
|
||||
},
|
||||
options: metricsOptions{
|
||||
transport: egressmetrics.TransportUDS,
|
||||
protocol: egressmetrics.ProtocolGRPC,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("UDS transport must be specified for GRPC")
|
||||
case apiserver.ProtocolDirect:
|
||||
return &dialerCreator{direct: true}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unrecognized service connection protocol %q", c.ProxyProtocol)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// NewEgressSelector configures lookup mechanism for Lookup.
|
||||
|
|
@ -172,18 +348,11 @@ func NewEgressSelector(config *apiserver.EgressSelectorConfiguration) (*EgressSe
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch service.Connection.Type {
|
||||
case "http-connect":
|
||||
contextDialer, err := createConnectDialer(service.Connection.HTTPConnect)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create http-connect dialer: %v", err)
|
||||
}
|
||||
cs.egressToDialer[name] = contextDialer
|
||||
case "direct":
|
||||
cs.egressToDialer[name] = directDialer
|
||||
default:
|
||||
return nil, fmt.Errorf("unrecognized service connection type %q", service.Connection.Type)
|
||||
dialerCreator, err := connectionToDialerCreator(service.Connection)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create dialer for egressSelection %q: %v", name, err)
|
||||
}
|
||||
cs.egressToDialer[name] = dialerCreator.createDialer()
|
||||
}
|
||||
return cs, nil
|
||||
}
|
||||
|
|
|
|||
114
vendor/k8s.io/apiserver/pkg/server/egressselector/metrics/metrics.go
generated
vendored
Normal file
114
vendor/k8s.io/apiserver/pkg/server/egressselector/metrics/metrics.go
generated
vendored
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
Copyright 2017 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 metrics
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
"k8s.io/component-base/metrics"
|
||||
"k8s.io/component-base/metrics/legacyregistry"
|
||||
)
|
||||
|
||||
const (
|
||||
namespace = "apiserver"
|
||||
subsystem = "egress_dialer"
|
||||
|
||||
// ProtocolHTTPConnect means that the proxy protocol is http-connect.
|
||||
ProtocolHTTPConnect = "http_connect"
|
||||
// ProtocolGRPC means that the proxy protocol is the GRPC protocol.
|
||||
ProtocolGRPC = "grpc"
|
||||
// TransportTCP means that the transport is TCP.
|
||||
TransportTCP = "tcp"
|
||||
// TransportUDS means that the transport is UDS.
|
||||
TransportUDS = "uds"
|
||||
// StageConnect indicates that the dial failed at establishing connection to the proxy server.
|
||||
StageConnect = "connect"
|
||||
// StageProxy indicates that the dial failed at requesting the proxy server to proxy.
|
||||
StageProxy = "proxy"
|
||||
)
|
||||
|
||||
var (
|
||||
// Use buckets ranging from 5 ms to 12.5 seconds.
|
||||
latencyBuckets = []float64{0.005, 0.025, 0.1, 0.5, 2.5, 12.5}
|
||||
|
||||
// Metrics provides access to all dial metrics.
|
||||
Metrics = newDialMetrics()
|
||||
)
|
||||
|
||||
// DialMetrics instruments dials to proxy server with prometheus metrics.
|
||||
type DialMetrics struct {
|
||||
clock clock.Clock
|
||||
latencies *metrics.HistogramVec
|
||||
failures *metrics.CounterVec
|
||||
}
|
||||
|
||||
// newDialMetrics create a new DialMetrics, configured with default metric names.
|
||||
func newDialMetrics() *DialMetrics {
|
||||
latencies := metrics.NewHistogramVec(
|
||||
&metrics.HistogramOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "dial_duration_seconds",
|
||||
Help: "Dial latency histogram in seconds, labeled by the protocol (http-connect or grpc), transport (tcp or uds)",
|
||||
Buckets: latencyBuckets,
|
||||
StabilityLevel: metrics.ALPHA,
|
||||
},
|
||||
[]string{"protocol", "transport"},
|
||||
)
|
||||
|
||||
failures := metrics.NewCounterVec(
|
||||
&metrics.CounterOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "dial_failure_count",
|
||||
Help: "Dial failure count, labeled by the protocol (http-connect or grpc), transport (tcp or uds), and stage (connect or proxy). The stage indicates at which stage the dial failed",
|
||||
StabilityLevel: metrics.ALPHA,
|
||||
},
|
||||
[]string{"protocol", "transport", "stage"},
|
||||
)
|
||||
|
||||
legacyregistry.MustRegister(latencies)
|
||||
legacyregistry.MustRegister(failures)
|
||||
return &DialMetrics{latencies: latencies, failures: failures, clock: clock.RealClock{}}
|
||||
}
|
||||
|
||||
// Clock returns the clock.
|
||||
func (m *DialMetrics) Clock() clock.Clock {
|
||||
return m.clock
|
||||
}
|
||||
|
||||
// SetClock sets the clock.
|
||||
func (m *DialMetrics) SetClock(c clock.Clock) {
|
||||
m.clock = c
|
||||
}
|
||||
|
||||
// Reset resets the metrics.
|
||||
func (m *DialMetrics) Reset() {
|
||||
m.latencies.Reset()
|
||||
m.failures.Reset()
|
||||
}
|
||||
|
||||
// ObserveDialLatency records the latency of a dial, labeled by protocol, transport.
|
||||
func (m *DialMetrics) ObserveDialLatency(elapsed time.Duration, protocol, transport string) {
|
||||
m.latencies.WithLabelValues(protocol, transport).Observe(elapsed.Seconds())
|
||||
}
|
||||
|
||||
// ObserveDialFailure records a failed dial, labeled by protocol, transport, and the stage the dial failed at.
|
||||
func (m *DialMetrics) ObserveDialFailure(protocol, transport, stage string) {
|
||||
m.failures.WithLabelValues(protocol, transport, stage).Inc()
|
||||
}
|
||||
88
vendor/k8s.io/apiserver/pkg/server/filters/goaway.go
generated
vendored
Normal file
88
vendor/k8s.io/apiserver/pkg/server/filters/goaway.go
generated
vendored
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
Copyright 2020 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 filters
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// GoawayDecider decides if server should send a GOAWAY
|
||||
type GoawayDecider interface {
|
||||
Goaway(r *http.Request) bool
|
||||
}
|
||||
|
||||
var (
|
||||
// randPool used to get a rand.Rand and generate a random number thread-safely,
|
||||
// which improve the performance of using rand.Rand with a locker
|
||||
randPool = &sync.Pool{
|
||||
New: func() interface{} {
|
||||
return rand.New(rand.NewSource(rand.Int63()))
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// WithProbabilisticGoaway returns an http.Handler that send GOAWAY probabilistically
|
||||
// according to the given chance for HTTP2 requests. After client receive GOAWAY,
|
||||
// the in-flight long-running requests will not be influenced, and the new requests
|
||||
// will use a new TCP connection to re-balancing to another server behind the load balance.
|
||||
func WithProbabilisticGoaway(inner http.Handler, chance float64) http.Handler {
|
||||
return &goaway{
|
||||
handler: inner,
|
||||
decider: &probabilisticGoawayDecider{
|
||||
chance: chance,
|
||||
next: func() float64 {
|
||||
rnd := randPool.Get().(*rand.Rand)
|
||||
ret := rnd.Float64()
|
||||
randPool.Put(rnd)
|
||||
return ret
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// goaway send a GOAWAY to client according to decider for HTTP2 requests
|
||||
type goaway struct {
|
||||
handler http.Handler
|
||||
decider GoawayDecider
|
||||
}
|
||||
|
||||
// ServeHTTP implement HTTP handler
|
||||
func (h *goaway) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Proto == "HTTP/2.0" && h.decider.Goaway(r) {
|
||||
// Send a GOAWAY and tear down the TCP connection when idle.
|
||||
w.Header().Set("Connection", "close")
|
||||
}
|
||||
|
||||
h.handler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// probabilisticGoawayDecider send GOAWAY probabilistically according to chance
|
||||
type probabilisticGoawayDecider struct {
|
||||
chance float64
|
||||
next func() float64
|
||||
}
|
||||
|
||||
// Goaway implement GoawayDecider
|
||||
func (p *probabilisticGoawayDecider) Goaway(r *http.Request) bool {
|
||||
if p.next() < p.chance {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
14
vendor/k8s.io/apiserver/pkg/server/filters/maxinflight.go
generated
vendored
14
vendor/k8s.io/apiserver/pkg/server/filters/maxinflight.go
generated
vendored
|
|
@ -160,14 +160,6 @@ func WithMaxInFlightLimit(
|
|||
handler.ServeHTTP(w, r)
|
||||
|
||||
default:
|
||||
// We need to split this data between buckets used for throttling.
|
||||
if isMutatingRequest {
|
||||
metrics.DroppedRequests.WithLabelValues(metrics.MutatingKind).Inc()
|
||||
metrics.DeprecatedDroppedRequests.WithLabelValues(metrics.MutatingKind).Inc()
|
||||
} else {
|
||||
metrics.DroppedRequests.WithLabelValues(metrics.ReadOnlyKind).Inc()
|
||||
metrics.DeprecatedDroppedRequests.WithLabelValues(metrics.ReadOnlyKind).Inc()
|
||||
}
|
||||
// at this point we're about to return a 429, BUT not all actors should be rate limited. A system:master is so powerful
|
||||
// that they should always get an answer. It's a super-admin or a loopback connection.
|
||||
if currUser, ok := apirequest.UserFrom(ctx); ok {
|
||||
|
|
@ -178,6 +170,12 @@ func WithMaxInFlightLimit(
|
|||
}
|
||||
}
|
||||
}
|
||||
// We need to split this data between buckets used for throttling.
|
||||
if isMutatingRequest {
|
||||
metrics.DroppedRequests.WithLabelValues(metrics.MutatingKind).Inc()
|
||||
} else {
|
||||
metrics.DroppedRequests.WithLabelValues(metrics.ReadOnlyKind).Inc()
|
||||
}
|
||||
metrics.RecordRequestTermination(r, requestInfo, metrics.APIServerComponent, http.StatusTooManyRequests)
|
||||
tooManyRequests(r, w)
|
||||
}
|
||||
|
|
|
|||
132
vendor/k8s.io/apiserver/pkg/server/filters/priority-and-fairness.go
generated
vendored
Normal file
132
vendor/k8s.io/apiserver/pkg/server/filters/priority-and-fairness.go
generated
vendored
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
Copyright 2019 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 filters
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sync/atomic"
|
||||
|
||||
fcv1a1 "k8s.io/api/flowcontrol/v1alpha1"
|
||||
apitypes "k8s.io/apimachinery/pkg/types"
|
||||
apirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
utilflowcontrol "k8s.io/apiserver/pkg/util/flowcontrol"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
type priorityAndFairnessKeyType int
|
||||
|
||||
const priorityAndFairnessKey priorityAndFairnessKeyType = iota
|
||||
|
||||
const (
|
||||
responseHeaderMatchedPriorityLevelConfigurationUID = "X-Kubernetes-PF-PriorityLevel-UID"
|
||||
responseHeaderMatchedFlowSchemaUID = "X-Kubernetes-PF-FlowSchema-UID"
|
||||
)
|
||||
|
||||
// PriorityAndFairnessClassification identifies the results of
|
||||
// classification for API Priority and Fairness
|
||||
type PriorityAndFairnessClassification struct {
|
||||
FlowSchemaName string
|
||||
FlowSchemaUID apitypes.UID
|
||||
PriorityLevelName string
|
||||
PriorityLevelUID apitypes.UID
|
||||
}
|
||||
|
||||
// GetClassification returns the classification associated with the
|
||||
// given context, if any, otherwise nil
|
||||
func GetClassification(ctx context.Context) *PriorityAndFairnessClassification {
|
||||
return ctx.Value(priorityAndFairnessKey).(*PriorityAndFairnessClassification)
|
||||
}
|
||||
|
||||
var atomicMutatingLen, atomicNonMutatingLen int32
|
||||
|
||||
// WithPriorityAndFairness limits the number of in-flight
|
||||
// requests in a fine-grained way.
|
||||
func WithPriorityAndFairness(
|
||||
handler http.Handler,
|
||||
longRunningRequestCheck apirequest.LongRunningRequestCheck,
|
||||
fcIfc utilflowcontrol.Interface,
|
||||
) http.Handler {
|
||||
if fcIfc == nil {
|
||||
klog.Warningf("priority and fairness support not found, skipping")
|
||||
return handler
|
||||
}
|
||||
startOnce.Do(startRecordingUsage)
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
requestInfo, ok := apirequest.RequestInfoFrom(ctx)
|
||||
if !ok {
|
||||
handleError(w, r, fmt.Errorf("no RequestInfo found in context"))
|
||||
return
|
||||
}
|
||||
user, ok := apirequest.UserFrom(ctx)
|
||||
if !ok {
|
||||
handleError(w, r, fmt.Errorf("no User found in context"))
|
||||
return
|
||||
}
|
||||
|
||||
// Skip tracking long running requests.
|
||||
if longRunningRequestCheck != nil && longRunningRequestCheck(r, requestInfo) {
|
||||
klog.V(6).Infof("Serving RequestInfo=%#+v, user.Info=%#+v as longrunning\n", requestInfo, user)
|
||||
handler.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
var classification *PriorityAndFairnessClassification
|
||||
note := func(fs *fcv1a1.FlowSchema, pl *fcv1a1.PriorityLevelConfiguration) {
|
||||
classification = &PriorityAndFairnessClassification{
|
||||
FlowSchemaName: fs.Name,
|
||||
FlowSchemaUID: fs.UID,
|
||||
PriorityLevelName: pl.Name,
|
||||
PriorityLevelUID: pl.UID}
|
||||
}
|
||||
|
||||
var served bool
|
||||
isMutatingRequest := !nonMutatingRequestVerbs.Has(requestInfo.Verb)
|
||||
execute := func() {
|
||||
var mutatingLen, readOnlyLen int
|
||||
if isMutatingRequest {
|
||||
mutatingLen = int(atomic.AddInt32(&atomicMutatingLen, 1))
|
||||
} else {
|
||||
readOnlyLen = int(atomic.AddInt32(&atomicNonMutatingLen, 1))
|
||||
}
|
||||
defer func() {
|
||||
if isMutatingRequest {
|
||||
atomic.AddInt32(&atomicMutatingLen, -11)
|
||||
watermark.recordMutating(mutatingLen)
|
||||
} else {
|
||||
atomic.AddInt32(&atomicNonMutatingLen, -1)
|
||||
watermark.recordReadOnly(readOnlyLen)
|
||||
}
|
||||
}()
|
||||
served = true
|
||||
innerCtx := context.WithValue(ctx, priorityAndFairnessKey, classification)
|
||||
innerReq := r.Clone(innerCtx)
|
||||
w.Header().Set(responseHeaderMatchedPriorityLevelConfigurationUID, string(classification.PriorityLevelUID))
|
||||
w.Header().Set(responseHeaderMatchedFlowSchemaUID, string(classification.FlowSchemaUID))
|
||||
handler.ServeHTTP(w, innerReq)
|
||||
}
|
||||
digest := utilflowcontrol.RequestDigest{requestInfo, user}
|
||||
fcIfc.Handle(ctx, digest, note, execute)
|
||||
if !served {
|
||||
tooManyRequests(r, w)
|
||||
return
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
14
vendor/k8s.io/apiserver/pkg/server/filters/waitgroup.go
generated
vendored
14
vendor/k8s.io/apiserver/pkg/server/filters/waitgroup.go
generated
vendored
|
|
@ -18,11 +18,16 @@ package filters
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
utilwaitgroup "k8s.io/apimachinery/pkg/util/waitgroup"
|
||||
"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
|
||||
apirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
)
|
||||
|
||||
// WithWaitGroup adds all non long-running requests to wait group, which is used for graceful shutdown.
|
||||
|
|
@ -38,7 +43,14 @@ func WithWaitGroup(handler http.Handler, longRunning apirequest.LongRunningReque
|
|||
|
||||
if !longRunning(req, requestInfo) {
|
||||
if err := wg.Add(1); err != nil {
|
||||
http.Error(w, "apiserver is shutting down.", http.StatusInternalServerError)
|
||||
// When apiserver is shutting down, signal clients to retry
|
||||
// There is a good chance the client hit a different server, so a tight retry is good for client responsiveness.
|
||||
w.Header().Add("Retry-After", "1")
|
||||
w.Header().Set("Content-Type", runtime.ContentTypeJSON)
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
statusErr := apierrors.NewServiceUnavailable("apiserver is shutting down").Status()
|
||||
w.WriteHeader(int(statusErr.Code))
|
||||
fmt.Fprintln(w, runtime.EncodeOrDie(scheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &statusErr))
|
||||
return
|
||||
}
|
||||
defer wg.Done()
|
||||
|
|
|
|||
7
vendor/k8s.io/apiserver/pkg/server/genericapiserver.go
generated
vendored
7
vendor/k8s.io/apiserver/pkg/server/genericapiserver.go
generated
vendored
|
|
@ -318,8 +318,14 @@ func (s preparedGenericAPIServer) Run(stopCh <-chan struct{}) error {
|
|||
|
||||
go func() {
|
||||
defer close(delayedStopCh)
|
||||
|
||||
<-stopCh
|
||||
|
||||
// As soon as shutdown is initiated, /readyz should start returning failure.
|
||||
// This gives the load balancer a window defined by ShutdownDelayDuration to detect that /readyz is red
|
||||
// and stop sending traffic to this server.
|
||||
close(s.readinessStopCh)
|
||||
|
||||
time.Sleep(s.ShutdownDelayDuration)
|
||||
}()
|
||||
|
||||
|
|
@ -379,7 +385,6 @@ func (s preparedGenericAPIServer) NonBlockingRun(stopCh <-chan struct{}) error {
|
|||
// ensure cleanup.
|
||||
go func() {
|
||||
<-stopCh
|
||||
close(s.readinessStopCh)
|
||||
close(internalStopCh)
|
||||
if stoppedCh != nil {
|
||||
<-stoppedCh
|
||||
|
|
|
|||
11
vendor/k8s.io/apiserver/pkg/server/healthz/healthz.go
generated
vendored
11
vendor/k8s.io/apiserver/pkg/server/healthz/healthz.go
generated
vendored
|
|
@ -27,6 +27,7 @@ import (
|
|||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apiserver/pkg/endpoints/metrics"
|
||||
"k8s.io/apiserver/pkg/server/httplog"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
|
@ -122,7 +123,15 @@ func InstallPathHandler(mux mux, path string, checks ...HealthChecker) {
|
|||
|
||||
klog.V(5).Infof("Installing health checkers for (%v): %v", path, formatQuoted(checkerNames(checks...)...))
|
||||
|
||||
mux.Handle(path, handleRootHealthz(checks...))
|
||||
mux.Handle(path,
|
||||
metrics.InstrumentHandlerFunc("GET",
|
||||
/* group = */ "",
|
||||
/* version = */ "",
|
||||
/* resource = */ "",
|
||||
/* subresource = */ path,
|
||||
/* scope = */ "",
|
||||
/* component = */ "",
|
||||
handleRootHealthz(checks...)))
|
||||
for _, check := range checks {
|
||||
mux.Handle(fmt.Sprintf("%s/%v", path, check.Name()), adaptCheckToHandler(check.Check))
|
||||
}
|
||||
|
|
|
|||
12
vendor/k8s.io/apiserver/pkg/server/httplog/httplog.go
generated
vendored
12
vendor/k8s.io/apiserver/pkg/server/httplog/httplog.go
generated
vendored
|
|
@ -158,9 +158,17 @@ func (rl *respLogger) Log() {
|
|||
latency := time.Since(rl.startTime)
|
||||
if klog.V(3) {
|
||||
if !rl.hijacked {
|
||||
klog.InfoDepth(1, fmt.Sprintf("%s %s: (%v) %v%v%v [%s %s]", rl.req.Method, rl.req.RequestURI, latency, rl.status, rl.statusStack, rl.addedInfo, rl.req.UserAgent(), rl.req.RemoteAddr))
|
||||
klog.InfoDepth(1, fmt.Sprintf("verb=%q URI=%q latency=%v resp=%v UserAgent=%q srcIP=%q: %v%v",
|
||||
rl.req.Method, rl.req.RequestURI,
|
||||
latency, rl.status,
|
||||
rl.req.UserAgent(), rl.req.RemoteAddr,
|
||||
rl.statusStack, rl.addedInfo,
|
||||
))
|
||||
} else {
|
||||
klog.InfoDepth(1, fmt.Sprintf("%s %s: (%v) hijacked [%s %s]", rl.req.Method, rl.req.RequestURI, latency, rl.req.UserAgent(), rl.req.RemoteAddr))
|
||||
klog.InfoDepth(1, fmt.Sprintf("verb=%q URI=%q latency=%v UserAgent=%q srcIP=%q: hijacked",
|
||||
rl.req.Method, rl.req.RequestURI,
|
||||
latency, rl.req.UserAgent(), rl.req.RemoteAddr,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
vendor/k8s.io/apiserver/pkg/server/options/admission.go
generated
vendored
2
vendor/k8s.io/apiserver/pkg/server/options/admission.go
generated
vendored
|
|
@ -112,7 +112,7 @@ func (a *AdmissionOptions) AddFlags(fs *pflag.FlagSet) {
|
|||
}
|
||||
|
||||
// ApplyTo adds the admission chain to the server configuration.
|
||||
// In case admission plugin names were not provided by a custer-admin they will be prepared from the recommended/default values.
|
||||
// In case admission plugin names were not provided by a cluster-admin they will be prepared from the recommended/default values.
|
||||
// In addition the method lazily initializes a generic plugin that is appended to the list of pluginInitializers
|
||||
// note this method uses:
|
||||
// genericconfig.Authorizer
|
||||
|
|
|
|||
16
vendor/k8s.io/apiserver/pkg/server/options/audit.go
generated
vendored
16
vendor/k8s.io/apiserver/pkg/server/options/audit.go
generated
vendored
|
|
@ -29,6 +29,7 @@ import (
|
|||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
||||
auditv1 "k8s.io/apiserver/pkg/apis/audit/v1"
|
||||
auditv1alpha1 "k8s.io/apiserver/pkg/apis/audit/v1alpha1"
|
||||
|
|
@ -37,6 +38,7 @@ import (
|
|||
"k8s.io/apiserver/pkg/audit/policy"
|
||||
"k8s.io/apiserver/pkg/features"
|
||||
"k8s.io/apiserver/pkg/server"
|
||||
"k8s.io/apiserver/pkg/server/egressselector"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
pluginbuffered "k8s.io/apiserver/plugin/pkg/audit/buffered"
|
||||
plugindynamic "k8s.io/apiserver/plugin/pkg/audit/dynamic"
|
||||
|
|
@ -323,7 +325,15 @@ func (o *AuditOptions) ApplyTo(
|
|||
if checker == nil {
|
||||
klog.V(2).Info("No audit policy file provided, no events will be recorded for webhook backend")
|
||||
} else {
|
||||
webhookBackend, err = o.WebhookOptions.newUntruncatedBackend()
|
||||
if c.EgressSelector != nil {
|
||||
egressDialer, err := c.EgressSelector.Lookup(egressselector.Master.AsNetworkContext())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
webhookBackend, err = o.WebhookOptions.newUntruncatedBackend(egressDialer)
|
||||
} else {
|
||||
webhookBackend, err = o.WebhookOptions.newUntruncatedBackend(nil)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -590,9 +600,9 @@ func (o *AuditWebhookOptions) enabled() bool {
|
|||
|
||||
// newUntruncatedBackend returns a webhook backend without the truncate options applied
|
||||
// this is done so that the same trucate backend can wrap both the webhook and dynamic backends
|
||||
func (o *AuditWebhookOptions) newUntruncatedBackend() (audit.Backend, error) {
|
||||
func (o *AuditWebhookOptions) newUntruncatedBackend(customDial utilnet.DialFunc) (audit.Backend, error) {
|
||||
groupVersion, _ := schema.ParseGroupVersion(o.GroupVersionString)
|
||||
webhook, err := pluginwebhook.NewBackend(o.ConfigFile, groupVersion, o.InitialBackoff)
|
||||
webhook, err := pluginwebhook.NewBackend(o.ConfigFile, groupVersion, o.InitialBackoff, customDial)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("initializing audit webhook: %v", err)
|
||||
}
|
||||
|
|
|
|||
5
vendor/k8s.io/apiserver/pkg/server/options/authentication.go
generated
vendored
5
vendor/k8s.io/apiserver/pkg/server/options/authentication.go
generated
vendored
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||
package options
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
|
@ -212,7 +213,7 @@ func (s *DelegatingAuthenticationOptions) AddFlags(fs *pflag.FlagSet) {
|
|||
}
|
||||
fs.StringVar(&s.RemoteKubeConfigFile, "authentication-kubeconfig", s.RemoteKubeConfigFile, ""+
|
||||
"kubeconfig file pointing at the 'core' kubernetes server with enough rights to create "+
|
||||
"tokenaccessreviews.authentication.k8s.io."+optionalKubeConfigSentence)
|
||||
"tokenreviews.authentication.k8s.io."+optionalKubeConfigSentence)
|
||||
|
||||
fs.DurationVar(&s.CacheTTL, "authentication-token-webhook-cache-ttl", s.CacheTTL,
|
||||
"The duration to cache responses from the webhook token authenticator.")
|
||||
|
|
@ -339,7 +340,7 @@ func (s *DelegatingAuthenticationOptions) createRequestHeaderConfig(client kuber
|
|||
return nil, fmt.Errorf("unable to create request header authentication config: %v", err)
|
||||
}
|
||||
|
||||
authConfigMap, err := client.CoreV1().ConfigMaps(authenticationConfigMapNamespace).Get(authenticationConfigMapName, metav1.GetOptions{})
|
||||
authConfigMap, err := client.CoreV1().ConfigMaps(authenticationConfigMapNamespace).Get(context.TODO(), authenticationConfigMapName, metav1.GetOptions{})
|
||||
switch {
|
||||
case errors.IsNotFound(err):
|
||||
// ignore, authConfigMap is nil now
|
||||
|
|
|
|||
106
vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go
generated
vendored
106
vendor/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go
generated
vendored
|
|
@ -20,6 +20,7 @@ import (
|
|||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
|
@ -33,6 +34,7 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
apiserverconfig "k8s.io/apiserver/pkg/apis/config"
|
||||
apiserverconfigv1 "k8s.io/apiserver/pkg/apis/config/v1"
|
||||
"k8s.io/apiserver/pkg/apis/config/validation"
|
||||
"k8s.io/apiserver/pkg/server/healthz"
|
||||
"k8s.io/apiserver/pkg/storage/value"
|
||||
aestransformer "k8s.io/apiserver/pkg/storage/value/encrypt/aes"
|
||||
|
|
@ -46,8 +48,8 @@ const (
|
|||
aesGCMTransformerPrefixV1 = "k8s:enc:aesgcm:v1:"
|
||||
secretboxTransformerPrefixV1 = "k8s:enc:secretbox:v1:"
|
||||
kmsTransformerPrefixV1 = "k8s:enc:kms:v1:"
|
||||
kmsPluginConnectionTimeout = 3 * time.Second
|
||||
kmsPluginHealthzTTL = 3 * time.Second
|
||||
kmsPluginHealthzNegativeTTL = 3 * time.Second
|
||||
kmsPluginHealthzPositiveTTL = 20 * time.Second
|
||||
)
|
||||
|
||||
type kmsPluginHealthzResponse struct {
|
||||
|
|
@ -57,6 +59,7 @@ type kmsPluginHealthzResponse struct {
|
|||
|
||||
type kmsPluginProbe struct {
|
||||
name string
|
||||
ttl time.Duration
|
||||
envelope.Service
|
||||
lastResponse *kmsPluginHealthzResponse
|
||||
l *sync.Mutex
|
||||
|
|
@ -104,21 +107,14 @@ func getKMSPluginProbes(reader io.Reader) ([]*kmsPluginProbe, error) {
|
|||
for _, r := range config.Resources {
|
||||
for _, p := range r.Providers {
|
||||
if p.KMS != nil {
|
||||
timeout := kmsPluginConnectionTimeout
|
||||
if p.KMS.Timeout != nil {
|
||||
if p.KMS.Timeout.Duration <= 0 {
|
||||
return nil, fmt.Errorf("could not configure KMS-Plugin's probe %q, timeout should be a positive value", p.KMS.Name)
|
||||
}
|
||||
timeout = p.KMS.Timeout.Duration
|
||||
}
|
||||
|
||||
s, err := envelope.NewGRPCService(p.KMS.Endpoint, timeout)
|
||||
s, err := envelope.NewGRPCService(p.KMS.Endpoint, p.KMS.Timeout.Duration)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not configure KMS-Plugin's probe %q, error: %v", p.KMS.Name, err)
|
||||
}
|
||||
|
||||
result = append(result, &kmsPluginProbe{
|
||||
name: p.KMS.Name,
|
||||
ttl: kmsPluginHealthzNegativeTTL,
|
||||
Service: s,
|
||||
l: &sync.Mutex{},
|
||||
lastResponse: &kmsPluginHealthzResponse{},
|
||||
|
|
@ -135,22 +131,25 @@ func (h *kmsPluginProbe) Check() error {
|
|||
h.l.Lock()
|
||||
defer h.l.Unlock()
|
||||
|
||||
if (time.Since(h.lastResponse.received)) < kmsPluginHealthzTTL {
|
||||
if (time.Since(h.lastResponse.received)) < h.ttl {
|
||||
return h.lastResponse.err
|
||||
}
|
||||
|
||||
p, err := h.Service.Encrypt([]byte("ping"))
|
||||
if err != nil {
|
||||
h.lastResponse = &kmsPluginHealthzResponse{err: err, received: time.Now()}
|
||||
h.ttl = kmsPluginHealthzNegativeTTL
|
||||
return fmt.Errorf("failed to perform encrypt section of the healthz check for KMS Provider %s, error: %v", h.name, err)
|
||||
}
|
||||
|
||||
if _, err := h.Service.Decrypt(p); err != nil {
|
||||
h.lastResponse = &kmsPluginHealthzResponse{err: err, received: time.Now()}
|
||||
h.ttl = kmsPluginHealthzNegativeTTL
|
||||
return fmt.Errorf("failed to perform decrypt section of the healthz check for KMS Provider %s, error: %v", h.name, err)
|
||||
}
|
||||
|
||||
h.lastResponse = &kmsPluginHealthzResponse{err: nil, received: time.Now()}
|
||||
h.ttl = kmsPluginHealthzPositiveTTL
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -221,7 +220,8 @@ func loadConfig(data []byte) (*apiserverconfig.EncryptionConfiguration, error) {
|
|||
if !ok {
|
||||
return nil, fmt.Errorf("got unexpected config type: %v", gvk)
|
||||
}
|
||||
return config, nil
|
||||
|
||||
return config, validation.ValidateEncryptionConfiguration(config).ToAggregate()
|
||||
}
|
||||
|
||||
// The factory to create kms service. This is to make writing test easier.
|
||||
|
|
@ -231,82 +231,38 @@ var envelopeServiceFactory = envelope.NewGRPCService
|
|||
func GetPrefixTransformers(config *apiserverconfig.ResourceConfiguration) ([]value.PrefixTransformer, error) {
|
||||
var result []value.PrefixTransformer
|
||||
for _, provider := range config.Providers {
|
||||
found := false
|
||||
var (
|
||||
transformer value.PrefixTransformer
|
||||
err error
|
||||
)
|
||||
|
||||
var transformer value.PrefixTransformer
|
||||
var err error
|
||||
|
||||
if provider.AESGCM != nil {
|
||||
switch {
|
||||
case provider.AESGCM != nil:
|
||||
transformer, err = GetAESPrefixTransformer(provider.AESGCM, aestransformer.NewGCMTransformer, aesGCMTransformerPrefixV1)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
found = true
|
||||
}
|
||||
|
||||
if provider.AESCBC != nil {
|
||||
if found == true {
|
||||
return result, fmt.Errorf("more than one provider specified in a single element, should split into different list elements")
|
||||
}
|
||||
case provider.AESCBC != nil:
|
||||
transformer, err = GetAESPrefixTransformer(provider.AESCBC, aestransformer.NewCBCTransformer, aesCBCTransformerPrefixV1)
|
||||
found = true
|
||||
}
|
||||
|
||||
if provider.Secretbox != nil {
|
||||
if found == true {
|
||||
return result, fmt.Errorf("more than one provider specified in a single element, should split into different list elements")
|
||||
}
|
||||
case provider.Secretbox != nil:
|
||||
transformer, err = GetSecretboxPrefixTransformer(provider.Secretbox)
|
||||
found = true
|
||||
}
|
||||
|
||||
if provider.Identity != nil {
|
||||
if found == true {
|
||||
return result, fmt.Errorf("more than one provider specified in a single element, should split into different list elements")
|
||||
}
|
||||
transformer = value.PrefixTransformer{
|
||||
Transformer: identity.NewEncryptCheckTransformer(),
|
||||
Prefix: []byte{},
|
||||
}
|
||||
found = true
|
||||
}
|
||||
|
||||
if provider.KMS != nil {
|
||||
if found == true {
|
||||
return nil, fmt.Errorf("more than one provider specified in a single element, should split into different list elements")
|
||||
}
|
||||
|
||||
// Ensure the endpoint is provided.
|
||||
if len(provider.KMS.Endpoint) == 0 {
|
||||
return nil, fmt.Errorf("remote KMS provider can't use empty string as endpoint")
|
||||
}
|
||||
|
||||
timeout := kmsPluginConnectionTimeout
|
||||
if provider.KMS.Timeout != nil {
|
||||
if provider.KMS.Timeout.Duration <= 0 {
|
||||
return nil, fmt.Errorf("could not configure KMS plugin %q, timeout should be a positive value", provider.KMS.Name)
|
||||
}
|
||||
timeout = provider.KMS.Timeout.Duration
|
||||
}
|
||||
|
||||
// Get gRPC client service with endpoint.
|
||||
envelopeService, err := envelopeServiceFactory(provider.KMS.Endpoint, timeout)
|
||||
case provider.KMS != nil:
|
||||
envelopeService, err := envelopeServiceFactory(provider.KMS.Endpoint, provider.KMS.Timeout.Duration)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not configure KMS plugin %q, error: %v", provider.KMS.Name, err)
|
||||
}
|
||||
|
||||
transformer, err = getEnvelopePrefixTransformer(provider.KMS, envelopeService, kmsTransformerPrefixV1)
|
||||
found = true
|
||||
case provider.Identity != nil:
|
||||
transformer = value.PrefixTransformer{
|
||||
Transformer: identity.NewEncryptCheckTransformer(),
|
||||
Prefix: []byte{},
|
||||
}
|
||||
default:
|
||||
return nil, errors.New("provider does not contain any of the expected providers: KMS, AESGCM, AESCBC, Secretbox, Identity")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
result = append(result, transformer)
|
||||
|
||||
if found == false {
|
||||
return result, fmt.Errorf("invalid provider configuration: at least one provider must be specified")
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
|
@ -417,7 +373,7 @@ func GetSecretboxPrefixTransformer(config *apiserverconfig.SecretboxConfiguratio
|
|||
// getEnvelopePrefixTransformer returns a prefix transformer from the provided config.
|
||||
// envelopeService is used as the root of trust.
|
||||
func getEnvelopePrefixTransformer(config *apiserverconfig.KMSConfiguration, envelopeService envelope.Service, prefix string) (value.PrefixTransformer, error) {
|
||||
envelopeTransformer, err := envelope.NewEnvelopeTransformer(envelopeService, int(config.CacheSize), aestransformer.NewCBCTransformer)
|
||||
envelopeTransformer, err := envelope.NewEnvelopeTransformer(envelopeService, int(*config.CacheSize), aestransformer.NewCBCTransformer)
|
||||
if err != nil {
|
||||
return value.PrefixTransformer{}, err
|
||||
}
|
||||
|
|
|
|||
14
vendor/k8s.io/apiserver/pkg/server/options/recommended.go
generated
vendored
14
vendor/k8s.io/apiserver/pkg/server/options/recommended.go
generated
vendored
|
|
@ -18,12 +18,15 @@ package options
|
|||
|
||||
import (
|
||||
"github.com/spf13/pflag"
|
||||
"k8s.io/apiserver/pkg/util/feature"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
"k8s.io/apiserver/pkg/features"
|
||||
"k8s.io/apiserver/pkg/server"
|
||||
"k8s.io/apiserver/pkg/storage/storagebackend"
|
||||
"k8s.io/apiserver/pkg/util/feature"
|
||||
utilflowcontrol "k8s.io/apiserver/pkg/util/flowcontrol"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/component-base/featuregate"
|
||||
)
|
||||
|
||||
|
|
@ -125,7 +128,14 @@ func (o *RecommendedOptions) ApplyTo(config *server.RecommendedConfig) error {
|
|||
if err := o.EgressSelector.ApplyTo(&config.Config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if feature.DefaultFeatureGate.Enabled(features.APIPriorityAndFairness) {
|
||||
config.FlowControl = utilflowcontrol.New(
|
||||
config.SharedInformerFactory,
|
||||
kubernetes.NewForConfigOrDie(config.ClientConfig).FlowcontrolV1alpha1(),
|
||||
config.MaxRequestsInFlight+config.MaxMutatingRequestsInFlight,
|
||||
config.RequestTimeout/4,
|
||||
)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
55
vendor/k8s.io/apiserver/pkg/server/options/server_run_options.go
generated
vendored
55
vendor/k8s.io/apiserver/pkg/server/options/server_run_options.go
generated
vendored
|
|
@ -26,9 +26,6 @@ import (
|
|||
"k8s.io/apiserver/pkg/server"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
|
||||
// add the generic feature gates
|
||||
"k8s.io/apiserver/pkg/features"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
|
|
@ -41,6 +38,7 @@ type ServerRunOptions struct {
|
|||
MaxRequestsInFlight int
|
||||
MaxMutatingRequestsInFlight int
|
||||
RequestTimeout time.Duration
|
||||
GoawayChance float64
|
||||
LivezGracePeriod time.Duration
|
||||
MinRequestTimeout int
|
||||
ShutdownDelayDuration time.Duration
|
||||
|
|
@ -51,9 +49,9 @@ type ServerRunOptions struct {
|
|||
// decoded in a write request. 0 means no limit.
|
||||
// We intentionally did not add a flag for this option. Users of the
|
||||
// apiserver library can wire it to a flag.
|
||||
MaxRequestBodyBytes int64
|
||||
TargetRAMMB int
|
||||
EnableInflightQuotaHandler bool
|
||||
MaxRequestBodyBytes int64
|
||||
TargetRAMMB int
|
||||
EnablePriorityAndFairness bool
|
||||
}
|
||||
|
||||
func NewServerRunOptions() *ServerRunOptions {
|
||||
|
|
@ -67,6 +65,7 @@ func NewServerRunOptions() *ServerRunOptions {
|
|||
ShutdownDelayDuration: defaults.ShutdownDelayDuration,
|
||||
JSONPatchMaxCopyBytes: defaults.JSONPatchMaxCopyBytes,
|
||||
MaxRequestBodyBytes: defaults.MaxRequestBodyBytes,
|
||||
EnablePriorityAndFairness: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -78,6 +77,7 @@ func (s *ServerRunOptions) ApplyTo(c *server.Config) error {
|
|||
c.MaxMutatingRequestsInFlight = s.MaxMutatingRequestsInFlight
|
||||
c.LivezGracePeriod = s.LivezGracePeriod
|
||||
c.RequestTimeout = s.RequestTimeout
|
||||
c.GoawayChance = s.GoawayChance
|
||||
c.MinRequestTimeout = s.MinRequestTimeout
|
||||
c.ShutdownDelayDuration = s.ShutdownDelayDuration
|
||||
c.JSONPatchMaxCopyBytes = s.JSONPatchMaxCopyBytes
|
||||
|
|
@ -116,32 +116,21 @@ func (s *ServerRunOptions) Validate() []error {
|
|||
errors = append(errors, fmt.Errorf("--livez-grace-period can not be a negative value"))
|
||||
}
|
||||
|
||||
if s.EnableInflightQuotaHandler {
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.APIPriorityAndFairness) {
|
||||
errors = append(errors, fmt.Errorf("--enable-inflight-quota-handler can not be set if feature "+
|
||||
"gate APIPriorityAndFairness is disabled"))
|
||||
}
|
||||
if s.MaxMutatingRequestsInFlight != 0 {
|
||||
errors = append(errors, fmt.Errorf("--max-mutating-requests-inflight=%v "+
|
||||
"can not be set if enabled inflight quota handler", s.MaxMutatingRequestsInFlight))
|
||||
}
|
||||
if s.MaxRequestsInFlight != 0 {
|
||||
errors = append(errors, fmt.Errorf("--max-requests-inflight=%v "+
|
||||
"can not be set if enabled inflight quota handler", s.MaxRequestsInFlight))
|
||||
}
|
||||
} else {
|
||||
if s.MaxRequestsInFlight < 0 {
|
||||
errors = append(errors, fmt.Errorf("--max-requests-inflight can not be negative value"))
|
||||
}
|
||||
if s.MaxMutatingRequestsInFlight < 0 {
|
||||
errors = append(errors, fmt.Errorf("--max-mutating-requests-inflight can not be negative value"))
|
||||
}
|
||||
if s.MaxRequestsInFlight < 0 {
|
||||
errors = append(errors, fmt.Errorf("--max-requests-inflight can not be negative value"))
|
||||
}
|
||||
if s.MaxMutatingRequestsInFlight < 0 {
|
||||
errors = append(errors, fmt.Errorf("--max-mutating-requests-inflight can not be negative value"))
|
||||
}
|
||||
|
||||
if s.RequestTimeout.Nanoseconds() < 0 {
|
||||
errors = append(errors, fmt.Errorf("--request-timeout can not be negative value"))
|
||||
}
|
||||
|
||||
if s.GoawayChance < 0 || s.GoawayChance > 0.02 {
|
||||
errors = append(errors, fmt.Errorf("--goaway-chance can not be less than 0 or greater than 0.02"))
|
||||
}
|
||||
|
||||
if s.MinRequestTimeout < 0 {
|
||||
errors = append(errors, fmt.Errorf("--min-request-timeout can not be negative value"))
|
||||
}
|
||||
|
|
@ -180,11 +169,11 @@ func (s *ServerRunOptions) AddUniversalFlags(fs *pflag.FlagSet) {
|
|||
"Memory limit for apiserver in MB (used to configure sizes of caches, etc.)")
|
||||
|
||||
fs.StringVar(&s.ExternalHost, "external-hostname", s.ExternalHost,
|
||||
"The hostname to use when generating externalized URLs for this master (e.g. Swagger API Docs).")
|
||||
"The hostname to use when generating externalized URLs for this master (e.g. Swagger API Docs or OpenID Discovery).")
|
||||
|
||||
deprecatedMasterServiceNamespace := metav1.NamespaceDefault
|
||||
fs.StringVar(&deprecatedMasterServiceNamespace, "master-service-namespace", deprecatedMasterServiceNamespace, ""+
|
||||
"DEPRECATED: the namespace from which the kubernetes master services should be injected into pods.")
|
||||
"DEPRECATED: the namespace from which the Kubernetes master services should be injected into pods.")
|
||||
|
||||
fs.IntVar(&s.MaxRequestsInFlight, "max-requests-inflight", s.MaxRequestsInFlight, ""+
|
||||
"The maximum number of non-mutating requests in flight at a given time. When the server exceeds this, "+
|
||||
|
|
@ -199,6 +188,12 @@ func (s *ServerRunOptions) AddUniversalFlags(fs *pflag.FlagSet) {
|
|||
"it out. This is the default request timeout for requests but may be overridden by flags such as "+
|
||||
"--min-request-timeout for specific types of requests.")
|
||||
|
||||
fs.Float64Var(&s.GoawayChance, "goaway-chance", s.GoawayChance, ""+
|
||||
"To prevent HTTP/2 clients from getting stuck on a single apiserver, randomly close a connection (GOAWAY). "+
|
||||
"The client's other in-flight requests won't be affected, and the client will reconnect, likely landing on a different apiserver after going through the load balancer again. "+
|
||||
"This argument sets the fraction of requests that will be sent a GOAWAY. Clusters with single apiservers, or which don't use a load balancer, should NOT enable this. "+
|
||||
"Min is 0 (off), Max is .02 (1/50 requests); .001 (1/1000) is a recommended starting point.")
|
||||
|
||||
fs.DurationVar(&s.LivezGracePeriod, "livez-grace-period", s.LivezGracePeriod, ""+
|
||||
"This option represents the maximum amount of time it should take for apiserver to complete its startup sequence "+
|
||||
"and become live. From apiserver's start time to when this amount of time has elapsed, /livez will assume "+
|
||||
|
|
@ -210,8 +205,8 @@ func (s *ServerRunOptions) AddUniversalFlags(fs *pflag.FlagSet) {
|
|||
"handler, which picks a randomized value above this number as the connection timeout, "+
|
||||
"to spread out load.")
|
||||
|
||||
fs.BoolVar(&s.EnableInflightQuotaHandler, "enable-inflight-quota-handler", s.EnableInflightQuotaHandler, ""+
|
||||
"If true, replace the max-in-flight handler with an enhanced one that queues and dispatches with priority and fairness")
|
||||
fs.BoolVar(&s.EnablePriorityAndFairness, "enable-priority-and-fairness", s.EnablePriorityAndFairness, ""+
|
||||
"If true and the APIPriorityAndFairness feature gate is enabled, replace the max-in-flight handler with an enhanced one that queues and dispatches with priority and fairness")
|
||||
|
||||
fs.DurationVar(&s.ShutdownDelayDuration, "shutdown-delay-duration", s.ShutdownDelayDuration, ""+
|
||||
"Time to delay the termination. During that time the server keeps serving requests normally and /healthz "+
|
||||
|
|
|
|||
13
vendor/k8s.io/apiserver/pkg/server/options/serving.go
generated
vendored
13
vendor/k8s.io/apiserver/pkg/server/options/serving.go
generated
vendored
|
|
@ -143,13 +143,13 @@ func (s *SecureServingOptions) AddFlags(fs *pflag.FlagSet) {
|
|||
fs.IPVar(&s.BindAddress, "bind-address", s.BindAddress, ""+
|
||||
"The IP address on which to listen for the --secure-port port. The "+
|
||||
"associated interface(s) must be reachable by the rest of the cluster, and by CLI/web "+
|
||||
"clients. If blank, all interfaces will be used (0.0.0.0 for all IPv4 interfaces and :: for all IPv6 interfaces).")
|
||||
"clients. If blank or an unspecified address (0.0.0.0 or ::), all interfaces will be used.")
|
||||
|
||||
desc := "The port on which to serve HTTPS with authentication and authorization."
|
||||
if s.Required {
|
||||
desc += "It cannot be switched off with 0."
|
||||
desc += " It cannot be switched off with 0."
|
||||
} else {
|
||||
desc += "If 0, don't serve HTTPS at all."
|
||||
desc += " If 0, don't serve HTTPS at all."
|
||||
}
|
||||
fs.IntVar(&s.BindPort, "secure-port", s.BindPort, desc)
|
||||
|
||||
|
|
@ -180,7 +180,9 @@ func (s *SecureServingOptions) AddFlags(fs *pflag.FlagSet) {
|
|||
fs.Var(cliflag.NewNamedCertKeyArray(&s.SNICertKeys), "tls-sni-cert-key", ""+
|
||||
"A pair of x509 certificate and private key file paths, optionally suffixed with a list of "+
|
||||
"domain patterns which are fully qualified domain names, possibly with prefixed wildcard "+
|
||||
"segments. If no domain patterns are provided, the names of the certificate are "+
|
||||
"segments. The domain patterns also allow IP addresses, but IPs should only be used if "+
|
||||
"the apiserver has visibility to the IP address requested by a client. "+
|
||||
"If no domain patterns are provided, the names of the certificate are "+
|
||||
"extracted. Non-wildcard matches trump over wildcard matches, explicit domain patterns "+
|
||||
"trump over extracted names. For multiple key/certificate pairs, use the "+
|
||||
"--tls-sni-cert-key multiple times. "+
|
||||
|
|
@ -287,8 +289,7 @@ func (s *SecureServingOptions) MaybeDefaultWithSelfSignedCerts(publicAddress str
|
|||
|
||||
if !canReadCertAndKey {
|
||||
// add either the bind address or localhost to the valid alternates
|
||||
bindIP := s.BindAddress.String()
|
||||
if bindIP == "0.0.0.0" {
|
||||
if s.BindAddress.IsUnspecified() {
|
||||
alternateDNS = append(alternateDNS, "localhost")
|
||||
} else {
|
||||
alternateIPs = append(alternateIPs, s.BindAddress)
|
||||
|
|
|
|||
2
vendor/k8s.io/apiserver/pkg/server/routes/metrics.go
generated
vendored
2
vendor/k8s.io/apiserver/pkg/server/routes/metrics.go
generated
vendored
|
|
@ -23,6 +23,7 @@ import (
|
|||
apimetrics "k8s.io/apiserver/pkg/endpoints/metrics"
|
||||
"k8s.io/apiserver/pkg/server/mux"
|
||||
etcd3metrics "k8s.io/apiserver/pkg/storage/etcd3/metrics"
|
||||
flowcontrolmetrics "k8s.io/apiserver/pkg/util/flowcontrol/metrics"
|
||||
"k8s.io/component-base/metrics/legacyregistry"
|
||||
)
|
||||
|
||||
|
|
@ -58,4 +59,5 @@ func (m MetricsWithReset) Install(c *mux.PathRecorderMux) {
|
|||
func register() {
|
||||
apimetrics.Register()
|
||||
etcd3metrics.Register()
|
||||
flowcontrolmetrics.Register()
|
||||
}
|
||||
|
|
|
|||
2
vendor/k8s.io/apiserver/pkg/server/secure_serving.go
generated
vendored
2
vendor/k8s.io/apiserver/pkg/server/secure_serving.go
generated
vendored
|
|
@ -66,7 +66,7 @@ func (s *SecureServingInfo) tlsConfig(stopCh <-chan struct{}) (*tls.Config, erro
|
|||
|
||||
if s.ClientCA != nil || s.Cert != nil || len(s.SNICerts) > 0 {
|
||||
dynamicCertificateController := dynamiccertificates.NewDynamicServingCertificateController(
|
||||
*tlsConfig,
|
||||
tlsConfig,
|
||||
s.ClientCA,
|
||||
s.Cert,
|
||||
s.SNICerts,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue