diff --git a/cmd/kube-controller-manager/app/core.go b/cmd/kube-controller-manager/app/core.go index 41ea747071557..5e710cdc55945 100644 --- a/cmd/kube-controller-manager/app/core.go +++ b/cmd/kube-controller-manager/app/core.go @@ -36,6 +36,7 @@ import ( utilfeature "k8s.io/apiserver/pkg/util/feature" clientset "k8s.io/client-go/kubernetes" "k8s.io/client-go/metadata" + "k8s.io/client-go/rest" restclient "k8s.io/client-go/rest" cloudnodelifecyclecontroller "k8s.io/cloud-provider/controllers/nodelifecycle" routecontroller "k8s.io/cloud-provider/controllers/route" @@ -589,7 +590,12 @@ func startNamespaceController(ctx context.Context, controllerContext ControllerC nsKubeconfig := controllerContext.ClientBuilder.ConfigOrDie("namespace-controller") nsKubeconfig.QPS *= 20 nsKubeconfig.Burst *= 100 - namespaceKubeClient := clientset.NewForConfigOrDie(nsKubeconfig) + + // Use protobuf + config := rest.CopyConfig(nsKubeconfig) + config.AcceptContentTypes = "application/vnd.kubernetes.protobuf,application/json" + config.ContentType = "application/vnd.kubernetes.protobuf" + namespaceKubeClient := clientset.NewForConfigOrDie(config) return startModifiedNamespaceController(ctx, controllerContext, namespaceKubeClient, nsKubeconfig) } diff --git a/cmd/kube-controller-manager/app/options/options.go b/cmd/kube-controller-manager/app/options/options.go index 51b2e1220b348..4cff93e1cb6af 100644 --- a/cmd/kube-controller-manager/app/options/options.go +++ b/cmd/kube-controller-manager/app/options/options.go @@ -481,7 +481,10 @@ func (s KubeControllerManagerOptions) Config(allControllers []string, disabledBy kubeconfig.Wrap(customOpenShiftRoundTripper) } - client, err := clientset.NewForConfig(restclient.AddUserAgent(kubeconfig, KubeControllerManagerUserAgent)) + protobufConfig := restclient.CopyConfig(kubeconfig) + protobufConfig.AcceptContentTypes = "application/vnd.kubernetes.protobuf,application/json" + protobufConfig.ContentType = "application/vnd.kubernetes.protobuf" + client, err := clientset.NewForConfig(restclient.AddUserAgent(protobufConfig, KubeControllerManagerUserAgent)) if err != nil { return nil, err } diff --git a/cmd/kube-controller-manager/app/patch_informers_openshift.go b/cmd/kube-controller-manager/app/patch_informers_openshift.go index 0c032dec30483..7c74682d3fd18 100644 --- a/cmd/kube-controller-manager/app/patch_informers_openshift.go +++ b/cmd/kube-controller-manager/app/patch_informers_openshift.go @@ -118,7 +118,11 @@ type combinedInformers struct { } func newInformerFactory(clientConfig *rest.Config) (informers.SharedInformerFactory, error) { - kubeClient, err := kubernetes.NewForConfig(clientConfig) + protobufConfig := rest.CopyConfig(clientConfig) + protobufConfig.AcceptContentTypes = "application/vnd.kubernetes.protobuf,application/json" + protobufConfig.ContentType = "application/vnd.kubernetes.protobuf" + + kubeClient, err := kubernetes.NewForConfig(protobufConfig) if err != nil { return nil, err } diff --git a/cmd/kube-scheduler/app/options/options.go b/cmd/kube-scheduler/app/options/options.go index 45e1d97b11f17..dace3cf6726cf 100644 --- a/cmd/kube-scheduler/app/options/options.go +++ b/cmd/kube-scheduler/app/options/options.go @@ -398,12 +398,15 @@ func createKubeConfig(config componentbaseconfig.ClientConnectionConfiguration, // createClients creates a kube client and an event client from the given kubeConfig func createClients(kubeConfig *restclient.Config) (clientset.Interface, clientset.Interface, error) { - client, err := clientset.NewForConfig(restclient.AddUserAgent(kubeConfig, "scheduler")) + protobufConfig := restclient.CopyConfig(kubeConfig) + protobufConfig.AcceptContentTypes = "application/vnd.kubernetes.protobuf,application/json" + protobufConfig.ContentType = "application/vnd.kubernetes.protobuf" + client, err := clientset.NewForConfig(restclient.AddUserAgent(protobufConfig, "scheduler")) if err != nil { return nil, nil, err } - eventClient, err := clientset.NewForConfig(kubeConfig) + eventClient, err := clientset.NewForConfig(protobufConfig) if err != nil { return nil, nil, err } diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/filters/audit.go b/staging/src/k8s.io/apiserver/pkg/endpoints/filters/audit.go index 6f850f728bfdb..9fd929e96999f 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/filters/audit.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/filters/audit.go @@ -23,6 +23,7 @@ import ( "fmt" "net" "net/http" + "strings" "sync" "time" @@ -242,9 +243,26 @@ func (a *auditResponseWriter) processCode(code int) { }) } +func (a *auditResponseWriter) Header() http.Header { + for name, value := range a.ResponseWriter.Header() { + switch { + case name == "Content-Type": + a.event.Annotations["openshift.io/response-header-content-type"] = strings.Join(value, ",") + case name == "Content-Encoding": + a.event.Annotations["openshift.io/response-header-content-encoding"] = strings.Join(value, ",") + case name == "Content-Length": + a.event.Annotations["openshift.io/response-header-content-length"] = strings.Join(value, ",") + } + } + return a.ResponseWriter.Header() +} + func (a *auditResponseWriter) Write(bs []byte) (int, error) { // the Go library calls WriteHeader internally if no code was written yet. But this will go unnoticed for us a.processCode(http.StatusOK) + if _, ok := a.event.Annotations["openshift.io/response-header-content-length"]; !ok { + a.event.Annotations["openshift.io/response-header-content-length"] = fmt.Sprintf("%d", len(bs)) + } return a.ResponseWriter.Write(bs) } diff --git a/staging/src/k8s.io/apiserver/pkg/server/config.go b/staging/src/k8s.io/apiserver/pkg/server/config.go index adca901631baa..047867a4deb8c 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/config.go +++ b/staging/src/k8s.io/apiserver/pkg/server/config.go @@ -1104,6 +1104,7 @@ func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler { handler = genericfilters.WithWaitGroup(handler, c.LongRunningFunc, c.NonLongRunningRequestWaitGroup) handler = WithNonReadyRequestLogging(handler, c.lifecycleSignals.HasBeenReady) handler = WithLateConnectionFilter(handler) + handler = WithRequestHeaders(handler) if c.ShutdownWatchTerminationGracePeriod > 0 { handler = genericfilters.WithWatchTerminationDuringShutdown(handler, c.lifecycleSignals, c.WatchRequestWaitGroup) } diff --git a/staging/src/k8s.io/apiserver/pkg/server/patch_genericapiserver.go b/staging/src/k8s.io/apiserver/pkg/server/patch_genericapiserver.go index a84494b1982db..60e03cbd83997 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/patch_genericapiserver.go +++ b/staging/src/k8s.io/apiserver/pkg/server/patch_genericapiserver.go @@ -197,10 +197,10 @@ func WithLateConnectionFilter(handler http.Handler) http.Handler { if late { if pth := "/" + strings.TrimLeft(r.URL.Path, "/"); pth != "/readyz" && pth != "/healthz" && pth != "/livez" { if isLocal(r) { - audit.AddAuditAnnotation(r.Context(), "openshift.io/during-graceful", fmt.Sprintf("loopback=true,%v,readyz=false", r.URL.Host)) + audit.AddAuditAnnotation(r.Context(), "openshift.io/during-graceful", fmt.Sprintf("loopback=true,%v,readyz=false", r.Host)) klog.V(4).Infof("Loopback request to %q (user agent %q) through connection created very late in the graceful termination process (more than 80%% has passed). This client probably does not watch /readyz and might get failures when termination is over.", r.URL.Path, r.UserAgent()) } else { - audit.AddAuditAnnotation(r.Context(), "openshift.io/during-graceful", fmt.Sprintf("loopback=false,%v,readyz=false", r.URL.Host)) + audit.AddAuditAnnotation(r.Context(), "openshift.io/during-graceful", fmt.Sprintf("loopback=false,%v,readyz=false", r.Host)) klog.Warningf("Request to %q (source IP %s, user agent %q) through a connection created very late in the graceful termination process (more than 80%% has passed), possibly a sign for a broken load balancer setup.", r.URL.Path, r.RemoteAddr, r.UserAgent()) // create only one event to avoid event spam. @@ -217,6 +217,24 @@ func WithLateConnectionFilter(handler http.Handler) http.Handler { }) } +// WithRequestHeaders logs every non-probe request and logs interesting request headers. +func WithRequestHeaders(handler http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if pth := "/" + strings.TrimLeft(r.URL.Path, "/"); pth != "/readyz" && pth != "/healthz" && pth != "/livez" { + if accept, ok := r.Header["Accept"]; ok { + audit.AddAuditAnnotation(r.Context(), "openshift.io/request-header-accept", strings.Join(accept, ",")) + } + if accept_encoding, ok := r.Header["Accept-Encoding"]; ok { + audit.AddAuditAnnotation(r.Context(), "openshift.io/request-header-accept-encoding", strings.Join(accept_encoding, ",")) + } + if content_length, ok := r.Header["Content-Length"]; ok { + audit.AddAuditAnnotation(r.Context(), "openshift.io/request-header-content-length", strings.Join(content_length, ",")) + } + } + handler.ServeHTTP(w, r) + }) +} + // WithNonReadyRequestLogging rejects the request until the process has been ready once. func WithNonReadyRequestLogging(handler http.Handler, hasBeenReadySignal lifecycleSignal) http.Handler { if hasBeenReadySignal == nil {