From dc06278276d6625e9a3c303e375745e79b34b87b Mon Sep 17 00:00:00 2001 From: Clayton Coleman Date: Tue, 16 Apr 2019 23:21:44 -0400 Subject: [PATCH] CRDs should support watch of protobuf PartialObjectMetadata Correctly ensure CRDs can be watched using protobuf when transformed to PartialObjectMetadata. To do this we add a set of serializers allowed to be used for "normal" requests (that return CRDs) while the serializers supported by the infrastructure is broader and includes protobuf. During negotatiation we check for transformation requests and protobuf is excluded from non-transform requests. As part of the change, correct an error message when the server returns a 406 but the client doesn't accept the format to avoid confusing users who set impossible Accept rules for CRDs (the dynamic client doesn't support Protobuf, so if the server responds with a protobuf status the message from the server is lost and the generic error was confusing). Kubernetes-commit: 89e752add07f443248f66e4798d160f2d7529a19 --- .../handlers/negotiation/negotiate.go | 13 ++++++------ pkg/endpoints/handlers/rest.go | 21 ++++++++++++++++++- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/pkg/endpoints/handlers/negotiation/negotiate.go b/pkg/endpoints/handlers/negotiation/negotiate.go index c00d4f3ac..718d61e67 100644 --- a/pkg/endpoints/handlers/negotiation/negotiate.go +++ b/pkg/endpoints/handlers/negotiation/negotiate.go @@ -116,9 +116,10 @@ func isPrettyPrint(req *http.Request) bool { // EndpointRestrictions is an interface that allows content-type negotiation // to verify server support for specific options type EndpointRestrictions interface { - // AllowsConversion should return true if the specified group version kind - // is an allowed target object. - AllowsConversion(target schema.GroupVersionKind, mimeType, mimeSubType string) bool + // AllowsMediaTypeTransform returns true if the endpoint allows either the requested mime type + // or the requested transformation. If false, the caller should ignore this mime type. If the + // target is nil, the client is not requesting a transformation. + AllowsMediaTypeTransform(mimeType, mimeSubType string, target *schema.GroupVersionKind) bool // AllowsServerVersion should return true if the specified version is valid // for the server group. AllowsServerVersion(version string) bool @@ -133,8 +134,8 @@ var DefaultEndpointRestrictions = emptyEndpointRestrictions{} type emptyEndpointRestrictions struct{} -func (emptyEndpointRestrictions) AllowsConversion(schema.GroupVersionKind, string, string) bool { - return false +func (emptyEndpointRestrictions) AllowsMediaTypeTransform(mimeType string, mimeSubType string, gvk *schema.GroupVersionKind) bool { + return gvk == nil } func (emptyEndpointRestrictions) AllowsServerVersion(string) bool { return false } func (emptyEndpointRestrictions) AllowsStreamSchema(s string) bool { return s == "watch" } @@ -225,7 +226,7 @@ func acceptMediaTypeOptions(params map[string]string, accepts *runtime.Serialize } } - if options.Convert != nil && !endpoint.AllowsConversion(*options.Convert, accepts.MediaTypeType, accepts.MediaTypeSubType) { + if !endpoint.AllowsMediaTypeTransform(accepts.MediaTypeType, accepts.MediaTypeSubType, options.Convert) { return MediaTypeOptions{}, false } diff --git a/pkg/endpoints/handlers/rest.go b/pkg/endpoints/handlers/rest.go index 9347b82f9..87afbf9a3 100644 --- a/pkg/endpoints/handlers/rest.go +++ b/pkg/endpoints/handlers/rest.go @@ -50,6 +50,11 @@ type RequestScope struct { Serializer runtime.NegotiatedSerializer runtime.ParameterCodec + // StandardSerializers, if set, restricts which serializers can be used when + // we aren't transforming the output (into Table or PartialObjectMetadata). + // Used only by CRDs which do not yet support Protobuf. + StandardSerializers []runtime.SerializerInfo + Creater runtime.ObjectCreater Convertor runtime.ObjectConvertor Defaulter runtime.ObjectDefaulter @@ -78,7 +83,21 @@ func (scope *RequestScope) err(err error, w http.ResponseWriter, req *http.Reque responsewriters.ErrorNegotiated(err, scope.Serializer, scope.Kind.GroupVersion(), w, req) } -func (scope *RequestScope) AllowsConversion(gvk schema.GroupVersionKind, mimeType, mimeSubType string) bool { +func (scope *RequestScope) AllowsMediaTypeTransform(mimeType, mimeSubType string, gvk *schema.GroupVersionKind) bool { + // some handlers like CRDs can't serve all the mime types that PartialObjectMetadata or Table can - if + // gvk is nil (no conversion) allow StandardSerializers to further restrict the set of mime types. + if gvk == nil { + if len(scope.StandardSerializers) == 0 { + return true + } + for _, info := range scope.StandardSerializers { + if info.MediaTypeType == mimeType && info.MediaTypeSubType == mimeSubType { + return true + } + } + return false + } + // TODO: this is temporary, replace with an abstraction calculated at endpoint installation time if gvk.GroupVersion() == metav1beta1.SchemeGroupVersion || gvk.GroupVersion() == metav1.SchemeGroupVersion { switch gvk.Kind {