diff --git a/pkg/cluster/ports/ports.go b/pkg/cluster/ports/ports.go index 01f9f2dbdc4..dd5b9ed0559 100644 --- a/pkg/cluster/ports/ports.go +++ b/pkg/cluster/ports/ports.go @@ -16,10 +16,6 @@ limitations under the License. package ports -import ( - cpoptions "k8s.io/cloud-provider/options" -) - // In this file, we can see all default port of cluster. // It's also an important documentation for us. So don't remove them easily. const ( @@ -49,6 +45,9 @@ const ( CloudControllerManagerPort = 10258 // CloudControllerManagerWebhookPort is the default port for the cloud // controller manager webhook server. May be overridden by a flag at - // startup. - CloudControllerManagerWebhookPort = cpoptions.CloudControllerManagerWebhookPort + // startup. It is a literal, not an alias of the k8s.io/cloud-provider + // constant, because importing cloud-provider/options pulls the generic + // apiserver (and CEL) into every binary that uses this package. + // ports_test.go checks that the two values stay equal. + CloudControllerManagerWebhookPort = 10260 ) diff --git a/pkg/cluster/ports/ports_test.go b/pkg/cluster/ports/ports_test.go new file mode 100644 index 00000000000..c5cc956eaa3 --- /dev/null +++ b/pkg/cluster/ports/ports_test.go @@ -0,0 +1,29 @@ +/* +Copyright 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 ports + +import ( + "testing" + + cpoptions "k8s.io/cloud-provider/options" +) + +func TestCloudControllerManagerWebhookPort(t *testing.T) { + if CloudControllerManagerWebhookPort != cpoptions.CloudControllerManagerWebhookPort { + t.Errorf("CloudControllerManagerWebhookPort = %d, want %d (k8s.io/cloud-provider/options)", CloudControllerManagerWebhookPort, cpoptions.CloudControllerManagerWebhookPort) + } +} diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/writers.go b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/writers.go index 33c4363c551..2c039b2d5a1 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/writers.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/writers.go @@ -37,17 +37,24 @@ import ( "k8s.io/apiserver/pkg/endpoints/handlers/negotiation" "k8s.io/apiserver/pkg/endpoints/metrics" "k8s.io/apiserver/pkg/endpoints/request" - "k8s.io/apiserver/pkg/registry/rest" utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/apiserver/pkg/util/flushwriter" "k8s.io/component-base/tracing" "k8s.io/streaming/pkg/httpstream/wsstream" ) -// StreamObject performs input stream negotiation from a ResourceStreamer and writes that to the response. +// resourceStreamer is the method set of k8s.io/apiserver/pkg/registry/rest.ResourceStreamer. It is +// declared here so that this package does not import registry/rest, which pulls the admission and +// CEL packages into every binary that serves /flagz or /statusz. writers_test.go asserts that the +// two interfaces stay assignable to each other. +type resourceStreamer interface { + InputStream(ctx context.Context, apiVersion, acceptHeader string) (stream io.ReadCloser, flush bool, mimeType string, err error) +} + +// StreamObject performs input stream negotiation from a rest.ResourceStreamer and writes that to the response. // If the client requests a websocket upgrade, negotiate for a websocket reader protocol (because many // browser clients cannot easily handle binary streaming protocols). -func StreamObject(statusCode int, gv schema.GroupVersion, s runtime.NegotiatedSerializer, stream rest.ResourceStreamer, w http.ResponseWriter, req *http.Request) { +func StreamObject(statusCode int, gv schema.GroupVersion, s runtime.NegotiatedSerializer, stream resourceStreamer, w http.ResponseWriter, req *http.Request) { out, flush, contentType, err := stream.InputStream(req.Context(), gv.String(), req.Header.Get("Accept")) if err != nil { ErrorNegotiated(err, s, gv, w, req) @@ -297,7 +304,7 @@ func (w *deferredResponseWriter) Close() (err error) { // WriteObjectNegotiated renders an object in the content type negotiated by the client. func WriteObjectNegotiated(s runtime.NegotiatedSerializer, restrictions negotiation.EndpointRestrictions, gv schema.GroupVersion, w http.ResponseWriter, req *http.Request, statusCode int, object runtime.Object, listGVKInContentType bool) { - stream, ok := object.(rest.ResourceStreamer) + stream, ok := object.(resourceStreamer) if ok { requestInfo, _ := request.RequestInfoFrom(req.Context()) metrics.RecordLongRunning(req, requestInfo, metrics.APIServerComponent, func() { diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/writers_test.go b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/writers_test.go index c5c7532aaa9..6193cb74809 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/writers_test.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/writers_test.go @@ -45,10 +45,18 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/rand" "k8s.io/apiserver/pkg/features" + "k8s.io/apiserver/pkg/registry/rest" utilfeature "k8s.io/apiserver/pkg/util/feature" featuregatetesting "k8s.io/component-base/featuregate/testing" ) +// resourceStreamer must stay identical to rest.ResourceStreamer so that the type assertion in +// WriteObjectNegotiated keeps matching the same objects. Both directions are checked. +var ( + _ resourceStreamer = rest.ResourceStreamer(nil) + _ rest.ResourceStreamer = resourceStreamer(nil) +) + const benchmarkSeed = 100 //go:embed testdata/exemplar_pod.yaml