mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
Make RequestScope be a pointer consistently for better memory use
RequestScope is a large struct and causes stack growth when we pass it by value into multiple stack levels. Avoid the allocations for this read only struct by passing a pointer.
This commit is contained in:
parent
1514bb2141
commit
8fede0b18a
@ -113,13 +113,13 @@ type crdInfo struct {
|
||||
storages map[string]customresource.CustomResourceStorage
|
||||
|
||||
// Request scope per version
|
||||
requestScopes map[string]handlers.RequestScope
|
||||
requestScopes map[string]*handlers.RequestScope
|
||||
|
||||
// Scale scope per version
|
||||
scaleRequestScopes map[string]handlers.RequestScope
|
||||
scaleRequestScopes map[string]*handlers.RequestScope
|
||||
|
||||
// Status scope per version
|
||||
statusRequestScopes map[string]handlers.RequestScope
|
||||
statusRequestScopes map[string]*handlers.RequestScope
|
||||
|
||||
// storageVersion is the CRD version used when storing the object in etcd.
|
||||
storageVersion string
|
||||
@ -444,10 +444,10 @@ func (r *crdHandler) getOrCreateServingInfoFor(crd *apiextensions.CustomResource
|
||||
}
|
||||
|
||||
// Scope/Storages per version.
|
||||
requestScopes := map[string]handlers.RequestScope{}
|
||||
requestScopes := map[string]*handlers.RequestScope{}
|
||||
storages := map[string]customresource.CustomResourceStorage{}
|
||||
statusScopes := map[string]handlers.RequestScope{}
|
||||
scaleScopes := map[string]handlers.RequestScope{}
|
||||
statusScopes := map[string]*handlers.RequestScope{}
|
||||
scaleScopes := map[string]*handlers.RequestScope{}
|
||||
|
||||
for _, v := range crd.Spec.Versions {
|
||||
safeConverter, unsafeConverter, err := r.converterFactory.NewConverter(crd)
|
||||
@ -548,7 +548,7 @@ func (r *crdHandler) getOrCreateServingInfoFor(crd *apiextensions.CustomResource
|
||||
|
||||
clusterScoped := crd.Spec.Scope == apiextensions.ClusterScoped
|
||||
|
||||
requestScopes[v.Name] = handlers.RequestScope{
|
||||
requestScopes[v.Name] = &handlers.RequestScope{
|
||||
Namer: handlers.ContextBasedNaming{
|
||||
SelfLinker: meta.NewAccessor(),
|
||||
ClusterScoped: clusterScoped,
|
||||
@ -576,19 +576,19 @@ func (r *crdHandler) getOrCreateServingInfoFor(crd *apiextensions.CustomResource
|
||||
Authorizer: r.authorizer,
|
||||
}
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.ServerSideApply) {
|
||||
reqScope := requestScopes[v.Name]
|
||||
reqScope := *requestScopes[v.Name]
|
||||
reqScope.FieldManager = fieldmanager.NewCRDFieldManager(
|
||||
reqScope.Convertor,
|
||||
reqScope.Defaulter,
|
||||
reqScope.Kind.GroupVersion(),
|
||||
reqScope.HubGroupVersion,
|
||||
)
|
||||
requestScopes[v.Name] = reqScope
|
||||
requestScopes[v.Name] = &reqScope
|
||||
}
|
||||
|
||||
// override scaleSpec subresource values
|
||||
// shallow copy
|
||||
scaleScope := requestScopes[v.Name]
|
||||
scaleScope := *requestScopes[v.Name]
|
||||
scaleConverter := scale.NewScaleConverter()
|
||||
scaleScope.Subresource = "scale"
|
||||
scaleScope.Serializer = serializer.NewCodecFactory(scaleConverter.Scheme())
|
||||
@ -599,11 +599,11 @@ func (r *crdHandler) getOrCreateServingInfoFor(crd *apiextensions.CustomResource
|
||||
SelfLinkPathPrefix: selfLinkPrefix,
|
||||
SelfLinkPathSuffix: "/scale",
|
||||
}
|
||||
scaleScopes[v.Name] = scaleScope
|
||||
scaleScopes[v.Name] = &scaleScope
|
||||
|
||||
// override status subresource values
|
||||
// shallow copy
|
||||
statusScope := requestScopes[v.Name]
|
||||
statusScope := *requestScopes[v.Name]
|
||||
statusScope.Subresource = "status"
|
||||
statusScope.Namer = handlers.ContextBasedNaming{
|
||||
SelfLinker: meta.NewAccessor(),
|
||||
@ -611,7 +611,7 @@ func (r *crdHandler) getOrCreateServingInfoFor(crd *apiextensions.CustomResource
|
||||
SelfLinkPathPrefix: selfLinkPrefix,
|
||||
SelfLinkPathSuffix: "/status",
|
||||
}
|
||||
statusScopes[v.Name] = statusScope
|
||||
statusScopes[v.Name] = &statusScope
|
||||
}
|
||||
|
||||
ret := &crdInfo{
|
||||
|
@ -43,7 +43,7 @@ import (
|
||||
utiltrace "k8s.io/utils/trace"
|
||||
)
|
||||
|
||||
func createHandler(r rest.NamedCreater, scope RequestScope, admit admission.Interface, includeName bool) http.HandlerFunc {
|
||||
func createHandler(r rest.NamedCreater, scope *RequestScope, admit admission.Interface, includeName bool) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, req *http.Request) {
|
||||
// For performance tracking purposes.
|
||||
trace := utiltrace.New("Create " + req.URL.Path)
|
||||
@ -73,7 +73,7 @@ func createHandler(r rest.NamedCreater, scope RequestScope, admit admission.Inte
|
||||
|
||||
ctx := req.Context()
|
||||
ctx = request.WithNamespace(ctx, namespace)
|
||||
outputMediaType, _, err := negotiation.NegotiateOutputMediaType(req, scope.Serializer, &scope)
|
||||
outputMediaType, _, err := negotiation.NegotiateOutputMediaType(req, scope.Serializer, scope)
|
||||
if err != nil {
|
||||
scope.err(err, w, req)
|
||||
return
|
||||
@ -130,7 +130,7 @@ func createHandler(r rest.NamedCreater, scope RequestScope, admit admission.Inte
|
||||
userInfo, _ := request.UserFrom(ctx)
|
||||
admissionAttributes := admission.NewAttributesRecord(obj, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, dryrun.IsDryRun(options.DryRun), userInfo)
|
||||
if mutatingAdmission, ok := admit.(admission.MutationInterface); ok && mutatingAdmission.Handles(admission.Create) {
|
||||
err = mutatingAdmission.Admit(admissionAttributes, &scope)
|
||||
err = mutatingAdmission.Admit(admissionAttributes, scope)
|
||||
if err != nil {
|
||||
scope.err(err, w, req)
|
||||
return
|
||||
@ -157,7 +157,7 @@ func createHandler(r rest.NamedCreater, scope RequestScope, admit admission.Inte
|
||||
ctx,
|
||||
name,
|
||||
obj,
|
||||
rest.AdmissionToValidateObjectFunc(admit, admissionAttributes, &scope),
|
||||
rest.AdmissionToValidateObjectFunc(admit, admissionAttributes, scope),
|
||||
options,
|
||||
)
|
||||
})
|
||||
@ -173,18 +173,17 @@ func createHandler(r rest.NamedCreater, scope RequestScope, admit admission.Inte
|
||||
status.Code = int32(code)
|
||||
}
|
||||
|
||||
scope.Trace = trace
|
||||
transformResponseObject(ctx, scope, req, w, code, outputMediaType, result)
|
||||
transformResponseObject(ctx, scope, trace, req, w, code, outputMediaType, result)
|
||||
}
|
||||
}
|
||||
|
||||
// CreateNamedResource returns a function that will handle a resource creation with name.
|
||||
func CreateNamedResource(r rest.NamedCreater, scope RequestScope, admission admission.Interface) http.HandlerFunc {
|
||||
func CreateNamedResource(r rest.NamedCreater, scope *RequestScope, admission admission.Interface) http.HandlerFunc {
|
||||
return createHandler(r, scope, admission, true)
|
||||
}
|
||||
|
||||
// CreateResource returns a function that will handle a resource creation.
|
||||
func CreateResource(r rest.Creater, scope RequestScope, admission admission.Interface) http.HandlerFunc {
|
||||
func CreateResource(r rest.Creater, scope *RequestScope, admission admission.Interface) http.HandlerFunc {
|
||||
return createHandler(&namedCreaterAdapter{r}, scope, admission, false)
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ import (
|
||||
|
||||
// DeleteResource returns a function that will handle a resource deletion
|
||||
// TODO admission here becomes solely validating admission
|
||||
func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope RequestScope, admit admission.Interface) http.HandlerFunc {
|
||||
func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope *RequestScope, admit admission.Interface) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, req *http.Request) {
|
||||
// For performance tracking purposes.
|
||||
trace := utiltrace.New("Delete " + req.URL.Path)
|
||||
@ -64,7 +64,7 @@ func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope RequestSco
|
||||
ae := request.AuditEventFrom(ctx)
|
||||
admit = admission.WithAudit(admit, ae)
|
||||
|
||||
outputMediaType, _, err := negotiation.NegotiateOutputMediaType(req, scope.Serializer, &scope)
|
||||
outputMediaType, _, err := negotiation.NegotiateOutputMediaType(req, scope.Serializer, scope)
|
||||
if err != nil {
|
||||
scope.err(err, w, req)
|
||||
return
|
||||
@ -119,13 +119,13 @@ func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope RequestSco
|
||||
userInfo, _ := request.UserFrom(ctx)
|
||||
attrs := admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Delete, dryrun.IsDryRun(options.DryRun), userInfo)
|
||||
if mutatingAdmission, ok := admit.(admission.MutationInterface); ok {
|
||||
if err := mutatingAdmission.Admit(attrs, &scope); err != nil {
|
||||
if err := mutatingAdmission.Admit(attrs, scope); err != nil {
|
||||
scope.err(err, w, req)
|
||||
return
|
||||
}
|
||||
}
|
||||
if validatingAdmission, ok := admit.(admission.ValidationInterface); ok {
|
||||
if err := validatingAdmission.Validate(attrs, &scope); err != nil {
|
||||
if err := validatingAdmission.Validate(attrs, scope); err != nil {
|
||||
scope.err(err, w, req)
|
||||
return
|
||||
}
|
||||
@ -168,13 +168,12 @@ func DeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope RequestSco
|
||||
}
|
||||
}
|
||||
|
||||
scope.Trace = trace
|
||||
transformResponseObject(ctx, scope, req, w, status, outputMediaType, result)
|
||||
transformResponseObject(ctx, scope, trace, req, w, status, outputMediaType, result)
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteCollection returns a function that will handle a collection deletion
|
||||
func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope RequestScope, admit admission.Interface) http.HandlerFunc {
|
||||
func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope *RequestScope, admit admission.Interface) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, req *http.Request) {
|
||||
trace := utiltrace.New("Delete " + req.URL.Path)
|
||||
defer trace.LogIfLong(500 * time.Millisecond)
|
||||
@ -197,7 +196,7 @@ func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope RequestSco
|
||||
ctx = request.WithNamespace(ctx, namespace)
|
||||
ae := request.AuditEventFrom(ctx)
|
||||
|
||||
outputMediaType, _, err := negotiation.NegotiateOutputMediaType(req, scope.Serializer, &scope)
|
||||
outputMediaType, _, err := negotiation.NegotiateOutputMediaType(req, scope.Serializer, scope)
|
||||
if err != nil {
|
||||
scope.err(err, w, req)
|
||||
return
|
||||
@ -269,7 +268,7 @@ func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope RequestSco
|
||||
userInfo, _ := request.UserFrom(ctx)
|
||||
attrs := admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, "", scope.Resource, scope.Subresource, admission.Delete, dryrun.IsDryRun(options.DryRun), userInfo)
|
||||
if mutatingAdmission, ok := admit.(admission.MutationInterface); ok {
|
||||
err = mutatingAdmission.Admit(attrs, &scope)
|
||||
err = mutatingAdmission.Admit(attrs, scope)
|
||||
if err != nil {
|
||||
scope.err(err, w, req)
|
||||
return
|
||||
@ -277,7 +276,7 @@ func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope RequestSco
|
||||
}
|
||||
|
||||
if validatingAdmission, ok := admit.(admission.ValidationInterface); ok {
|
||||
err = validatingAdmission.Validate(attrs, &scope)
|
||||
err = validatingAdmission.Validate(attrs, scope)
|
||||
if err != nil {
|
||||
scope.err(err, w, req)
|
||||
return
|
||||
@ -305,7 +304,6 @@ func DeleteCollection(r rest.CollectionDeleter, checkBody bool, scope RequestSco
|
||||
}
|
||||
}
|
||||
|
||||
scope.Trace = trace
|
||||
transformResponseObject(ctx, scope, req, w, http.StatusOK, outputMediaType, result)
|
||||
transformResponseObject(ctx, scope, trace, req, w, http.StatusOK, outputMediaType, result)
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ type getterFunc func(ctx context.Context, name string, req *http.Request, trace
|
||||
|
||||
// getResourceHandler is an HTTP handler function for get requests. It delegates to the
|
||||
// passed-in getterFunc to perform the actual get.
|
||||
func getResourceHandler(scope RequestScope, getter getterFunc) http.HandlerFunc {
|
||||
func getResourceHandler(scope *RequestScope, getter getterFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, req *http.Request) {
|
||||
trace := utiltrace.New("Get " + req.URL.Path)
|
||||
defer trace.LogIfLong(500 * time.Millisecond)
|
||||
@ -59,7 +59,7 @@ func getResourceHandler(scope RequestScope, getter getterFunc) http.HandlerFunc
|
||||
ctx := req.Context()
|
||||
ctx = request.WithNamespace(ctx, namespace)
|
||||
|
||||
outputMediaType, _, err := negotiation.NegotiateOutputMediaType(req, scope.Serializer, &scope)
|
||||
outputMediaType, _, err := negotiation.NegotiateOutputMediaType(req, scope.Serializer, scope)
|
||||
if err != nil {
|
||||
scope.err(err, w, req)
|
||||
return
|
||||
@ -72,14 +72,13 @@ func getResourceHandler(scope RequestScope, getter getterFunc) http.HandlerFunc
|
||||
}
|
||||
|
||||
trace.Step("About to write a response")
|
||||
scope.Trace = trace
|
||||
transformResponseObject(ctx, scope, req, w, http.StatusOK, outputMediaType, result)
|
||||
transformResponseObject(ctx, scope, trace, req, w, http.StatusOK, outputMediaType, result)
|
||||
trace.Step("Transformed response object")
|
||||
}
|
||||
}
|
||||
|
||||
// GetResource returns a function that handles retrieving a single resource from a rest.Storage object.
|
||||
func GetResource(r rest.Getter, e rest.Exporter, scope RequestScope) http.HandlerFunc {
|
||||
func GetResource(r rest.Getter, e rest.Exporter, scope *RequestScope) http.HandlerFunc {
|
||||
return getResourceHandler(scope,
|
||||
func(ctx context.Context, name string, req *http.Request, trace *utiltrace.Trace) (runtime.Object, error) {
|
||||
// check for export
|
||||
@ -109,7 +108,7 @@ func GetResource(r rest.Getter, e rest.Exporter, scope RequestScope) http.Handle
|
||||
}
|
||||
|
||||
// GetResourceWithOptions returns a function that handles retrieving a single resource from a rest.Storage object.
|
||||
func GetResourceWithOptions(r rest.GetterWithOptions, scope RequestScope, isSubresource bool) http.HandlerFunc {
|
||||
func GetResourceWithOptions(r rest.GetterWithOptions, scope *RequestScope, isSubresource bool) http.HandlerFunc {
|
||||
return getResourceHandler(scope,
|
||||
func(ctx context.Context, name string, req *http.Request, trace *utiltrace.Trace) (runtime.Object, error) {
|
||||
opts, subpath, subpathKey := r.NewGetOptions()
|
||||
@ -126,7 +125,7 @@ func GetResourceWithOptions(r rest.GetterWithOptions, scope RequestScope, isSubr
|
||||
}
|
||||
|
||||
// getRequestOptions parses out options and can include path information. The path information shouldn't include the subresource.
|
||||
func getRequestOptions(req *http.Request, scope RequestScope, into runtime.Object, subpath bool, subpathKey string, isSubresource bool) error {
|
||||
func getRequestOptions(req *http.Request, scope *RequestScope, into runtime.Object, subpath bool, subpathKey string, isSubresource bool) error {
|
||||
if into == nil {
|
||||
return nil
|
||||
}
|
||||
@ -163,7 +162,7 @@ func getRequestOptions(req *http.Request, scope RequestScope, into runtime.Objec
|
||||
return scope.ParameterCodec.DecodeParameters(query, scope.Kind.GroupVersion(), into)
|
||||
}
|
||||
|
||||
func ListResource(r rest.Lister, rw rest.Watcher, scope RequestScope, forceWatch bool, minRequestTimeout time.Duration) http.HandlerFunc {
|
||||
func ListResource(r rest.Lister, rw rest.Watcher, scope *RequestScope, forceWatch bool, minRequestTimeout time.Duration) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, req *http.Request) {
|
||||
// For performance tracking purposes.
|
||||
trace := utiltrace.New("List " + req.URL.Path)
|
||||
@ -185,7 +184,7 @@ func ListResource(r rest.Lister, rw rest.Watcher, scope RequestScope, forceWatch
|
||||
ctx := req.Context()
|
||||
ctx = request.WithNamespace(ctx, namespace)
|
||||
|
||||
outputMediaType, _, err := negotiation.NegotiateOutputMediaType(req, scope.Serializer, &scope)
|
||||
outputMediaType, _, err := negotiation.NegotiateOutputMediaType(req, scope.Serializer, scope)
|
||||
if err != nil {
|
||||
scope.err(err, w, req)
|
||||
return
|
||||
@ -272,8 +271,7 @@ func ListResource(r rest.Lister, rw rest.Watcher, scope RequestScope, forceWatch
|
||||
}
|
||||
trace.Step("Listing from storage done")
|
||||
|
||||
scope.Trace = trace
|
||||
transformResponseObject(ctx, scope, req, w, http.StatusOK, outputMediaType, result)
|
||||
transformResponseObject(ctx, scope, trace, req, w, http.StatusOK, outputMediaType, result)
|
||||
trace.Step(fmt.Sprintf("Writing http response done (%d items)", meta.LenList(result)))
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ const (
|
||||
)
|
||||
|
||||
// PatchResource returns a function that will handle a resource patch.
|
||||
func PatchResource(r rest.Patcher, scope RequestScope, admit admission.Interface, patchTypes []string) http.HandlerFunc {
|
||||
func PatchResource(r rest.Patcher, scope *RequestScope, admit admission.Interface, patchTypes []string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, req *http.Request) {
|
||||
// For performance tracking purposes.
|
||||
trace := utiltrace.New("Patch " + req.URL.Path)
|
||||
@ -95,7 +95,7 @@ func PatchResource(r rest.Patcher, scope RequestScope, admit admission.Interface
|
||||
ctx := req.Context()
|
||||
ctx = request.WithNamespace(ctx, namespace)
|
||||
|
||||
outputMediaType, _, err := negotiation.NegotiateOutputMediaType(req, scope.Serializer, &scope)
|
||||
outputMediaType, _, err := negotiation.NegotiateOutputMediaType(req, scope.Serializer, scope)
|
||||
if err != nil {
|
||||
scope.err(err, w, req)
|
||||
return
|
||||
@ -191,12 +191,12 @@ func PatchResource(r rest.Patcher, scope RequestScope, admit admission.Interface
|
||||
subresource: scope.Subresource,
|
||||
dryRun: dryrun.IsDryRun(options.DryRun),
|
||||
|
||||
objectInterfaces: &scope,
|
||||
objectInterfaces: scope,
|
||||
|
||||
hubGroupVersion: scope.HubGroupVersion,
|
||||
|
||||
createValidation: withAuthorization(rest.AdmissionToValidateObjectFunc(admit, staticCreateAttributes, &scope), scope.Authorizer, createAuthorizerAttributes),
|
||||
updateValidation: rest.AdmissionToValidateObjectUpdateFunc(admit, staticUpdateAttributes, &scope),
|
||||
createValidation: withAuthorization(rest.AdmissionToValidateObjectFunc(admit, staticCreateAttributes, scope), scope.Authorizer, createAuthorizerAttributes),
|
||||
updateValidation: rest.AdmissionToValidateObjectUpdateFunc(admit, staticUpdateAttributes, scope),
|
||||
admissionCheck: mutatingAdmission,
|
||||
|
||||
codec: codec,
|
||||
@ -235,8 +235,7 @@ func PatchResource(r rest.Patcher, scope RequestScope, admit admission.Interface
|
||||
if wasCreated {
|
||||
status = http.StatusCreated
|
||||
}
|
||||
scope.Trace = trace
|
||||
transformResponseObject(ctx, scope, req, w, status, outputMediaType, result)
|
||||
transformResponseObject(ctx, scope, trace, req, w, status, outputMediaType, result)
|
||||
}
|
||||
}
|
||||
|
||||
@ -517,7 +516,7 @@ func (p *patcher) applyAdmission(ctx context.Context, patchedObject runtime.Obje
|
||||
}
|
||||
|
||||
// patchResource divides PatchResource for easier unit testing
|
||||
func (p *patcher) patchResource(ctx context.Context, scope RequestScope) (runtime.Object, bool, error) {
|
||||
func (p *patcher) patchResource(ctx context.Context, scope *RequestScope) (runtime.Object, bool, error) {
|
||||
p.namespace = request.NamespaceValue(ctx)
|
||||
switch p.patchType {
|
||||
case types.JSONPatchType, types.MergePatchType:
|
||||
|
@ -31,12 +31,13 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apiserver/pkg/endpoints/handlers/negotiation"
|
||||
"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
|
||||
utiltrace "k8s.io/utils/trace"
|
||||
)
|
||||
|
||||
// transformObject takes the object as returned by storage and ensures it is in
|
||||
// the client's desired form, as well as ensuring any API level fields like self-link
|
||||
// are properly set.
|
||||
func transformObject(ctx context.Context, obj runtime.Object, opts interface{}, mediaType negotiation.MediaTypeOptions, scope RequestScope, req *http.Request) (runtime.Object, error) {
|
||||
func transformObject(ctx context.Context, obj runtime.Object, opts interface{}, mediaType negotiation.MediaTypeOptions, scope *RequestScope, req *http.Request) (runtime.Object, error) {
|
||||
if _, ok := obj.(*metav1.Status); ok {
|
||||
return obj, nil
|
||||
}
|
||||
@ -104,7 +105,7 @@ func targetEncodingForTransform(scope *RequestScope, mediaType negotiation.Media
|
||||
|
||||
// transformResponseObject takes an object loaded from storage and performs any necessary transformations.
|
||||
// Will write the complete response object.
|
||||
func transformResponseObject(ctx context.Context, scope RequestScope, req *http.Request, w http.ResponseWriter, statusCode int, mediaType negotiation.MediaTypeOptions, result runtime.Object) {
|
||||
func transformResponseObject(ctx context.Context, scope *RequestScope, trace *utiltrace.Trace, req *http.Request, w http.ResponseWriter, statusCode int, mediaType negotiation.MediaTypeOptions, result runtime.Object) {
|
||||
options, err := optionsForTransform(mediaType, req)
|
||||
if err != nil {
|
||||
scope.err(err, w, req)
|
||||
@ -115,8 +116,8 @@ func transformResponseObject(ctx context.Context, scope RequestScope, req *http.
|
||||
scope.err(err, w, req)
|
||||
return
|
||||
}
|
||||
kind, serializer, _ := targetEncodingForTransform(&scope, mediaType, req)
|
||||
responsewriters.WriteObjectNegotiated(serializer, &scope, kind.GroupVersion(), w, req, statusCode, obj)
|
||||
kind, serializer, _ := targetEncodingForTransform(scope, mediaType, req)
|
||||
responsewriters.WriteObjectNegotiated(serializer, scope, kind.GroupVersion(), w, req, statusCode, obj)
|
||||
}
|
||||
|
||||
// errNotAcceptable indicates Accept negotiation has failed
|
||||
@ -141,7 +142,7 @@ func (e errNotAcceptable) Status() metav1.Status {
|
||||
}
|
||||
}
|
||||
|
||||
func asV1Beta1Table(ctx context.Context, result runtime.Object, opts *metav1beta1.TableOptions, scope RequestScope) (runtime.Object, error) {
|
||||
func asV1Beta1Table(ctx context.Context, result runtime.Object, opts *metav1beta1.TableOptions, scope *RequestScope) (runtime.Object, error) {
|
||||
table, err := scope.TableConvertor.ConvertToTable(ctx, result, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -42,7 +42,6 @@ import (
|
||||
"k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
"k8s.io/klog"
|
||||
utiltrace "k8s.io/utils/trace"
|
||||
)
|
||||
|
||||
// RequestScope encapsulates common fields across all RESTful handler methods.
|
||||
@ -58,7 +57,6 @@ type RequestScope struct {
|
||||
Typer runtime.ObjectTyper
|
||||
UnsafeConvertor runtime.ObjectConvertor
|
||||
Authorizer authorizer.Authorizer
|
||||
Trace *utiltrace.Trace
|
||||
|
||||
TableConvertor rest.TableConvertor
|
||||
FieldManager *fieldmanager.FieldManager
|
||||
@ -113,7 +111,7 @@ func (r *RequestScope) GetObjectDefaulter() runtime.ObjectDefaulter { return r.D
|
||||
func (r *RequestScope) GetObjectConvertor() runtime.ObjectConvertor { return r.Convertor }
|
||||
|
||||
// ConnectResource returns a function that handles a connect request on a rest.Storage object.
|
||||
func ConnectResource(connecter rest.Connecter, scope RequestScope, admit admission.Interface, restPath string, isSubresource bool) http.HandlerFunc {
|
||||
func ConnectResource(connecter rest.Connecter, scope *RequestScope, admit admission.Interface, restPath string, isSubresource bool) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, req *http.Request) {
|
||||
if isDryRun(req.URL) {
|
||||
scope.err(errors.NewBadRequest("dryRun is not supported"), w, req)
|
||||
@ -140,14 +138,14 @@ func ConnectResource(connecter rest.Connecter, scope RequestScope, admit admissi
|
||||
userInfo, _ := request.UserFrom(ctx)
|
||||
// TODO: remove the mutating admission here as soon as we have ported all plugin that handle CONNECT
|
||||
if mutatingAdmission, ok := admit.(admission.MutationInterface); ok {
|
||||
err = mutatingAdmission.Admit(admission.NewAttributesRecord(opts, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, false, userInfo), &scope)
|
||||
err = mutatingAdmission.Admit(admission.NewAttributesRecord(opts, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, false, userInfo), scope)
|
||||
if err != nil {
|
||||
scope.err(err, w, req)
|
||||
return
|
||||
}
|
||||
}
|
||||
if validatingAdmission, ok := admit.(admission.ValidationInterface); ok {
|
||||
err = validatingAdmission.Validate(admission.NewAttributesRecord(opts, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, false, userInfo), &scope)
|
||||
err = validatingAdmission.Validate(admission.NewAttributesRecord(opts, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Connect, false, userInfo), scope)
|
||||
if err != nil {
|
||||
scope.err(err, w, req)
|
||||
return
|
||||
@ -168,13 +166,13 @@ func ConnectResource(connecter rest.Connecter, scope RequestScope, admit admissi
|
||||
|
||||
// responder implements rest.Responder for assisting a connector in writing objects or errors.
|
||||
type responder struct {
|
||||
scope RequestScope
|
||||
scope *RequestScope
|
||||
req *http.Request
|
||||
w http.ResponseWriter
|
||||
}
|
||||
|
||||
func (r *responder) Object(statusCode int, obj runtime.Object) {
|
||||
responsewriters.WriteObjectNegotiated(r.scope.Serializer, &r.scope, r.scope.Kind.GroupVersion(), r.w, r.req, statusCode, obj)
|
||||
responsewriters.WriteObjectNegotiated(r.scope.Serializer, r.scope, r.scope.Kind.GroupVersion(), r.w, r.req, statusCode, obj)
|
||||
}
|
||||
|
||||
func (r *responder) Error(err error) {
|
||||
|
@ -462,7 +462,7 @@ func (tc *patchTestCase) Run(t *testing.T) {
|
||||
trace: utiltrace.New("Patch" + name),
|
||||
}
|
||||
|
||||
resultObj, _, err := p.patchResource(ctx, RequestScope{})
|
||||
resultObj, _, err := p.patchResource(ctx, &RequestScope{})
|
||||
if len(tc.expectedError) != 0 {
|
||||
if err == nil || err.Error() != tc.expectedError {
|
||||
t.Errorf("%s: expected error %v, but got %v", tc.name, tc.expectedError, err)
|
||||
|
@ -42,7 +42,7 @@ import (
|
||||
)
|
||||
|
||||
// UpdateResource returns a function that will handle a resource update
|
||||
func UpdateResource(r rest.Updater, scope RequestScope, admit admission.Interface) http.HandlerFunc {
|
||||
func UpdateResource(r rest.Updater, scope *RequestScope, admit admission.Interface) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, req *http.Request) {
|
||||
// For performance tracking purposes.
|
||||
trace := utiltrace.New("Update " + req.URL.Path)
|
||||
@ -64,7 +64,7 @@ func UpdateResource(r rest.Updater, scope RequestScope, admit admission.Interfac
|
||||
ctx := req.Context()
|
||||
ctx = request.WithNamespace(ctx, namespace)
|
||||
|
||||
outputMediaType, _, err := negotiation.NegotiateOutputMediaType(req, scope.Serializer, &scope)
|
||||
outputMediaType, _, err := negotiation.NegotiateOutputMediaType(req, scope.Serializer, scope)
|
||||
if err != nil {
|
||||
scope.err(err, w, req)
|
||||
return
|
||||
@ -138,11 +138,11 @@ func UpdateResource(r rest.Updater, scope RequestScope, admit admission.Interfac
|
||||
return nil, fmt.Errorf("unexpected error when extracting UID from oldObj: %v", err.Error())
|
||||
} else if !isNotZeroObject {
|
||||
if mutatingAdmission.Handles(admission.Create) {
|
||||
return newObj, mutatingAdmission.Admit(admission.NewAttributesRecord(newObj, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, dryrun.IsDryRun(options.DryRun), userInfo), &scope)
|
||||
return newObj, mutatingAdmission.Admit(admission.NewAttributesRecord(newObj, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, dryrun.IsDryRun(options.DryRun), userInfo), scope)
|
||||
}
|
||||
} else {
|
||||
if mutatingAdmission.Handles(admission.Update) {
|
||||
return newObj, mutatingAdmission.Admit(admission.NewAttributesRecord(newObj, oldObj, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, dryrun.IsDryRun(options.DryRun), userInfo), &scope)
|
||||
return newObj, mutatingAdmission.Admit(admission.NewAttributesRecord(newObj, oldObj, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, dryrun.IsDryRun(options.DryRun), userInfo), scope)
|
||||
}
|
||||
}
|
||||
return newObj, nil
|
||||
@ -172,11 +172,11 @@ func UpdateResource(r rest.Updater, scope RequestScope, admit admission.Interfac
|
||||
rest.DefaultUpdatedObjectInfo(obj, transformers...),
|
||||
withAuthorization(rest.AdmissionToValidateObjectFunc(
|
||||
admit,
|
||||
admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, dryrun.IsDryRun(options.DryRun), userInfo), &scope),
|
||||
admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, dryrun.IsDryRun(options.DryRun), userInfo), scope),
|
||||
scope.Authorizer, createAuthorizerAttributes),
|
||||
rest.AdmissionToValidateObjectUpdateFunc(
|
||||
admit,
|
||||
admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, dryrun.IsDryRun(options.DryRun), userInfo), &scope),
|
||||
admission.NewAttributesRecord(nil, nil, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, dryrun.IsDryRun(options.DryRun), userInfo), scope),
|
||||
false,
|
||||
options,
|
||||
)
|
||||
@ -194,8 +194,7 @@ func UpdateResource(r rest.Updater, scope RequestScope, admit admission.Interfac
|
||||
status = http.StatusCreated
|
||||
}
|
||||
|
||||
scope.Trace = trace
|
||||
transformResponseObject(ctx, scope, req, w, status, outputMediaType, result)
|
||||
transformResponseObject(ctx, scope, trace, req, w, status, outputMediaType, result)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ func (w *realTimeoutFactory) TimeoutCh() (<-chan time.Time, func() bool) {
|
||||
|
||||
// serveWatch will serve a watch response.
|
||||
// TODO: the functionality in this method and in WatchServer.Serve is not cleanly decoupled.
|
||||
func serveWatch(watcher watch.Interface, scope RequestScope, mediaTypeOptions negotiation.MediaTypeOptions, req *http.Request, w http.ResponseWriter, timeout time.Duration) {
|
||||
func serveWatch(watcher watch.Interface, scope *RequestScope, mediaTypeOptions negotiation.MediaTypeOptions, req *http.Request, w http.ResponseWriter, timeout time.Duration) {
|
||||
options, err := optionsForTransform(mediaTypeOptions, req)
|
||||
if err != nil {
|
||||
scope.err(err, w, req)
|
||||
@ -71,7 +71,7 @@ func serveWatch(watcher watch.Interface, scope RequestScope, mediaTypeOptions ne
|
||||
}
|
||||
|
||||
// negotiate for the stream serializer from the scope's serializer
|
||||
serializer, err := negotiation.NegotiateOutputMediaTypeStream(req, scope.Serializer, &scope)
|
||||
serializer, err := negotiation.NegotiateOutputMediaTypeStream(req, scope.Serializer, scope)
|
||||
if err != nil {
|
||||
scope.err(err, w, req)
|
||||
return
|
||||
@ -92,7 +92,7 @@ func serveWatch(watcher watch.Interface, scope RequestScope, mediaTypeOptions ne
|
||||
|
||||
// locate the appropriate embedded encoder based on the transform
|
||||
var embeddedEncoder runtime.Encoder
|
||||
contentKind, contentSerializer, transform := targetEncodingForTransform(&scope, mediaTypeOptions, req)
|
||||
contentKind, contentSerializer, transform := targetEncodingForTransform(scope, mediaTypeOptions, req)
|
||||
if transform {
|
||||
var embedded runtime.Serializer
|
||||
for _, supported := range contentSerializer.SupportedMediaTypes() {
|
||||
@ -145,7 +145,7 @@ func serveWatch(watcher watch.Interface, scope RequestScope, mediaTypeOptions ne
|
||||
// WatchServer serves a watch.Interface over a websocket or vanilla HTTP.
|
||||
type WatchServer struct {
|
||||
Watching watch.Interface
|
||||
Scope RequestScope
|
||||
Scope *RequestScope
|
||||
|
||||
// true if websocket messages should use text framing (as opposed to binary framing)
|
||||
UseTextFraming bool
|
||||
|
@ -1076,60 +1076,60 @@ func isVowel(c rune) bool {
|
||||
|
||||
func restfulListResource(r rest.Lister, rw rest.Watcher, scope handlers.RequestScope, forceWatch bool, minRequestTimeout time.Duration) restful.RouteFunction {
|
||||
return func(req *restful.Request, res *restful.Response) {
|
||||
handlers.ListResource(r, rw, scope, forceWatch, minRequestTimeout)(res.ResponseWriter, req.Request)
|
||||
handlers.ListResource(r, rw, &scope, forceWatch, minRequestTimeout)(res.ResponseWriter, req.Request)
|
||||
}
|
||||
}
|
||||
|
||||
func restfulCreateNamedResource(r rest.NamedCreater, scope handlers.RequestScope, admit admission.Interface) restful.RouteFunction {
|
||||
return func(req *restful.Request, res *restful.Response) {
|
||||
handlers.CreateNamedResource(r, scope, admit)(res.ResponseWriter, req.Request)
|
||||
handlers.CreateNamedResource(r, &scope, admit)(res.ResponseWriter, req.Request)
|
||||
}
|
||||
}
|
||||
|
||||
func restfulCreateResource(r rest.Creater, scope handlers.RequestScope, admit admission.Interface) restful.RouteFunction {
|
||||
return func(req *restful.Request, res *restful.Response) {
|
||||
handlers.CreateResource(r, scope, admit)(res.ResponseWriter, req.Request)
|
||||
handlers.CreateResource(r, &scope, admit)(res.ResponseWriter, req.Request)
|
||||
}
|
||||
}
|
||||
|
||||
func restfulDeleteResource(r rest.GracefulDeleter, allowsOptions bool, scope handlers.RequestScope, admit admission.Interface) restful.RouteFunction {
|
||||
return func(req *restful.Request, res *restful.Response) {
|
||||
handlers.DeleteResource(r, allowsOptions, scope, admit)(res.ResponseWriter, req.Request)
|
||||
handlers.DeleteResource(r, allowsOptions, &scope, admit)(res.ResponseWriter, req.Request)
|
||||
}
|
||||
}
|
||||
|
||||
func restfulDeleteCollection(r rest.CollectionDeleter, checkBody bool, scope handlers.RequestScope, admit admission.Interface) restful.RouteFunction {
|
||||
return func(req *restful.Request, res *restful.Response) {
|
||||
handlers.DeleteCollection(r, checkBody, scope, admit)(res.ResponseWriter, req.Request)
|
||||
handlers.DeleteCollection(r, checkBody, &scope, admit)(res.ResponseWriter, req.Request)
|
||||
}
|
||||
}
|
||||
|
||||
func restfulUpdateResource(r rest.Updater, scope handlers.RequestScope, admit admission.Interface) restful.RouteFunction {
|
||||
return func(req *restful.Request, res *restful.Response) {
|
||||
handlers.UpdateResource(r, scope, admit)(res.ResponseWriter, req.Request)
|
||||
handlers.UpdateResource(r, &scope, admit)(res.ResponseWriter, req.Request)
|
||||
}
|
||||
}
|
||||
|
||||
func restfulPatchResource(r rest.Patcher, scope handlers.RequestScope, admit admission.Interface, supportedTypes []string) restful.RouteFunction {
|
||||
return func(req *restful.Request, res *restful.Response) {
|
||||
handlers.PatchResource(r, scope, admit, supportedTypes)(res.ResponseWriter, req.Request)
|
||||
handlers.PatchResource(r, &scope, admit, supportedTypes)(res.ResponseWriter, req.Request)
|
||||
}
|
||||
}
|
||||
|
||||
func restfulGetResource(r rest.Getter, e rest.Exporter, scope handlers.RequestScope) restful.RouteFunction {
|
||||
return func(req *restful.Request, res *restful.Response) {
|
||||
handlers.GetResource(r, e, scope)(res.ResponseWriter, req.Request)
|
||||
handlers.GetResource(r, e, &scope)(res.ResponseWriter, req.Request)
|
||||
}
|
||||
}
|
||||
|
||||
func restfulGetResourceWithOptions(r rest.GetterWithOptions, scope handlers.RequestScope, isSubresource bool) restful.RouteFunction {
|
||||
return func(req *restful.Request, res *restful.Response) {
|
||||
handlers.GetResourceWithOptions(r, scope, isSubresource)(res.ResponseWriter, req.Request)
|
||||
handlers.GetResourceWithOptions(r, &scope, isSubresource)(res.ResponseWriter, req.Request)
|
||||
}
|
||||
}
|
||||
|
||||
func restfulConnectResource(connecter rest.Connecter, scope handlers.RequestScope, admit admission.Interface, restPath string, isSubresource bool) restful.RouteFunction {
|
||||
return func(req *restful.Request, res *restful.Response) {
|
||||
handlers.ConnectResource(connecter, scope, admit, restPath, isSubresource)(res.ResponseWriter, req.Request)
|
||||
handlers.ConnectResource(connecter, &scope, admit, restPath, isSubresource)(res.ResponseWriter, req.Request)
|
||||
}
|
||||
}
|
||||
|
@ -579,6 +579,7 @@ func TestWatchHTTPErrors(t *testing.T) {
|
||||
|
||||
// Setup a new watchserver
|
||||
watchServer := &handlers.WatchServer{
|
||||
Scope: &handlers.RequestScope{},
|
||||
Watching: watcher,
|
||||
|
||||
MediaType: "testcase/json",
|
||||
@ -639,6 +640,7 @@ func TestWatchHTTPDynamicClientErrors(t *testing.T) {
|
||||
|
||||
// Setup a new watchserver
|
||||
watchServer := &handlers.WatchServer{
|
||||
Scope: &handlers.RequestScope{},
|
||||
Watching: watcher,
|
||||
|
||||
MediaType: "testcase/json",
|
||||
@ -701,6 +703,7 @@ func TestWatchHTTPTimeout(t *testing.T) {
|
||||
|
||||
// Setup a new watchserver
|
||||
watchServer := &handlers.WatchServer{
|
||||
Scope: &handlers.RequestScope{},
|
||||
Watching: watcher,
|
||||
|
||||
MediaType: "testcase/json",
|
||||
|
Loading…
Reference in New Issue
Block a user