k8s.io/apiserver@v0.31.1/pkg/endpoints/handlers/patch.go (about)

     1  /*
     2  Copyright 2017 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package handlers
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"net/http"
    23  	"strings"
    24  	"time"
    25  
    26  	"go.opentelemetry.io/otel/attribute"
    27  	jsonpatch "gopkg.in/evanphx/json-patch.v4"
    28  	kjson "sigs.k8s.io/json"
    29  
    30  	"k8s.io/apimachinery/pkg/api/errors"
    31  	"k8s.io/apimachinery/pkg/api/meta"
    32  	metainternalversionscheme "k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme"
    33  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    34  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    35  	"k8s.io/apimachinery/pkg/apis/meta/v1/validation"
    36  	"k8s.io/apimachinery/pkg/runtime"
    37  	"k8s.io/apimachinery/pkg/runtime/schema"
    38  	"k8s.io/apimachinery/pkg/types"
    39  	"k8s.io/apimachinery/pkg/util/managedfields"
    40  	"k8s.io/apimachinery/pkg/util/mergepatch"
    41  	"k8s.io/apimachinery/pkg/util/sets"
    42  	"k8s.io/apimachinery/pkg/util/strategicpatch"
    43  	"k8s.io/apimachinery/pkg/util/validation/field"
    44  	"k8s.io/apimachinery/pkg/util/yaml"
    45  	"k8s.io/apiserver/pkg/admission"
    46  	"k8s.io/apiserver/pkg/audit"
    47  	"k8s.io/apiserver/pkg/authorization/authorizer"
    48  	"k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager"
    49  	"k8s.io/apiserver/pkg/endpoints/handlers/finisher"
    50  	requestmetrics "k8s.io/apiserver/pkg/endpoints/handlers/metrics"
    51  	"k8s.io/apiserver/pkg/endpoints/handlers/negotiation"
    52  	"k8s.io/apiserver/pkg/endpoints/request"
    53  	"k8s.io/apiserver/pkg/registry/rest"
    54  	"k8s.io/apiserver/pkg/util/dryrun"
    55  	"k8s.io/component-base/tracing"
    56  )
    57  
    58  const (
    59  	// maximum number of operations a single json patch may contain.
    60  	maxJSONPatchOperations = 10000
    61  )
    62  
    63  // PatchResource returns a function that will handle a resource patch.
    64  func PatchResource(r rest.Patcher, scope *RequestScope, admit admission.Interface, patchTypes []string) http.HandlerFunc {
    65  	return func(w http.ResponseWriter, req *http.Request) {
    66  		ctx := req.Context()
    67  		// For performance tracking purposes.
    68  		ctx, span := tracing.Start(ctx, "Patch", traceFields(req)...)
    69  		defer span.End(500 * time.Millisecond)
    70  
    71  		// Do this first, otherwise name extraction can fail for unrecognized content types
    72  		// TODO: handle this in negotiation
    73  		contentType := req.Header.Get("Content-Type")
    74  		// Remove "; charset=" if included in header.
    75  		if idx := strings.Index(contentType, ";"); idx > 0 {
    76  			contentType = contentType[:idx]
    77  		}
    78  		patchType := types.PatchType(contentType)
    79  
    80  		// Ensure the patchType is one we support
    81  		if !sets.NewString(patchTypes...).Has(contentType) {
    82  			scope.err(negotiation.NewUnsupportedMediaTypeError(patchTypes), w, req)
    83  			return
    84  		}
    85  
    86  		namespace, name, err := scope.Namer.Name(req)
    87  		if err != nil {
    88  			scope.err(err, w, req)
    89  			return
    90  		}
    91  
    92  		// enforce a timeout of at most requestTimeoutUpperBound (34s) or less if the user-provided
    93  		// timeout inside the parent context is lower than requestTimeoutUpperBound.
    94  		ctx, cancel := context.WithTimeout(ctx, requestTimeoutUpperBound)
    95  		defer cancel()
    96  
    97  		ctx = request.WithNamespace(ctx, namespace)
    98  
    99  		outputMediaType, _, err := negotiation.NegotiateOutputMediaType(req, scope.Serializer, scope)
   100  		if err != nil {
   101  			scope.err(err, w, req)
   102  			return
   103  		}
   104  
   105  		patchBytes, err := limitedReadBodyWithRecordMetric(ctx, req, scope.MaxRequestBodyBytes, scope.Resource.GroupResource().String(), requestmetrics.Patch)
   106  		if err != nil {
   107  			span.AddEvent("limitedReadBody failed", attribute.Int("len", len(patchBytes)), attribute.String("err", err.Error()))
   108  			scope.err(err, w, req)
   109  			return
   110  		}
   111  		span.AddEvent("limitedReadBody succeeded", attribute.Int("len", len(patchBytes)))
   112  
   113  		options := &metav1.PatchOptions{}
   114  		if err := metainternalversionscheme.ParameterCodec.DecodeParameters(req.URL.Query(), scope.MetaGroupVersion, options); err != nil {
   115  			err = errors.NewBadRequest(err.Error())
   116  			scope.err(err, w, req)
   117  			return
   118  		}
   119  		if errs := validation.ValidatePatchOptions(options, patchType); len(errs) > 0 {
   120  			err := errors.NewInvalid(schema.GroupKind{Group: metav1.GroupName, Kind: "PatchOptions"}, "", errs)
   121  			scope.err(err, w, req)
   122  			return
   123  		}
   124  		options.TypeMeta.SetGroupVersionKind(metav1.SchemeGroupVersion.WithKind("PatchOptions"))
   125  
   126  		admit = admission.WithAudit(admit)
   127  
   128  		audit.LogRequestPatch(req.Context(), patchBytes)
   129  		span.AddEvent("Recorded the audit event")
   130  
   131  		baseContentType := runtime.ContentTypeJSON
   132  		if patchType == types.ApplyPatchType {
   133  			baseContentType = runtime.ContentTypeYAML
   134  		}
   135  		s, ok := runtime.SerializerInfoForMediaType(scope.Serializer.SupportedMediaTypes(), baseContentType)
   136  		if !ok {
   137  			scope.err(fmt.Errorf("no serializer defined for %v", baseContentType), w, req)
   138  			return
   139  		}
   140  		gv := scope.Kind.GroupVersion()
   141  
   142  		validationDirective := fieldValidation(options.FieldValidation)
   143  		decodeSerializer := s.Serializer
   144  		if validationDirective == metav1.FieldValidationWarn || validationDirective == metav1.FieldValidationStrict {
   145  			decodeSerializer = s.StrictSerializer
   146  		}
   147  
   148  		codec := runtime.NewCodec(
   149  			scope.Serializer.EncoderForVersion(s.Serializer, gv),
   150  			scope.Serializer.DecoderToVersion(decodeSerializer, scope.HubGroupVersion),
   151  		)
   152  
   153  		userInfo, _ := request.UserFrom(ctx)
   154  		staticCreateAttributes := admission.NewAttributesRecord(
   155  			nil,
   156  			nil,
   157  			scope.Kind,
   158  			namespace,
   159  			name,
   160  			scope.Resource,
   161  			scope.Subresource,
   162  			admission.Create,
   163  			patchToCreateOptions(options),
   164  			dryrun.IsDryRun(options.DryRun),
   165  			userInfo)
   166  		staticUpdateAttributes := admission.NewAttributesRecord(
   167  			nil,
   168  			nil,
   169  			scope.Kind,
   170  			namespace,
   171  			name,
   172  			scope.Resource,
   173  			scope.Subresource,
   174  			admission.Update,
   175  			patchToUpdateOptions(options),
   176  			dryrun.IsDryRun(options.DryRun),
   177  			userInfo,
   178  		)
   179  
   180  		admit = fieldmanager.NewManagedFieldsValidatingAdmissionController(admit)
   181  
   182  		mutatingAdmission, _ := admit.(admission.MutationInterface)
   183  		createAuthorizerAttributes := authorizer.AttributesRecord{
   184  			User:            userInfo,
   185  			ResourceRequest: true,
   186  			Path:            req.URL.Path,
   187  			Verb:            "create",
   188  			APIGroup:        scope.Resource.Group,
   189  			APIVersion:      scope.Resource.Version,
   190  			Resource:        scope.Resource.Resource,
   191  			Subresource:     scope.Subresource,
   192  			Namespace:       namespace,
   193  			Name:            name,
   194  		}
   195  
   196  		p := patcher{
   197  			namer:               scope.Namer,
   198  			creater:             scope.Creater,
   199  			defaulter:           scope.Defaulter,
   200  			typer:               scope.Typer,
   201  			unsafeConvertor:     scope.UnsafeConvertor,
   202  			kind:                scope.Kind,
   203  			resource:            scope.Resource,
   204  			subresource:         scope.Subresource,
   205  			dryRun:              dryrun.IsDryRun(options.DryRun),
   206  			validationDirective: validationDirective,
   207  
   208  			objectInterfaces: scope,
   209  
   210  			hubGroupVersion: scope.HubGroupVersion,
   211  
   212  			createValidation: withAuthorization(rest.AdmissionToValidateObjectFunc(admit, staticCreateAttributes, scope), scope.Authorizer, createAuthorizerAttributes),
   213  			updateValidation: rest.AdmissionToValidateObjectUpdateFunc(admit, staticUpdateAttributes, scope),
   214  			admissionCheck:   mutatingAdmission,
   215  
   216  			codec: codec,
   217  
   218  			options: options,
   219  
   220  			restPatcher: r,
   221  			name:        name,
   222  			patchType:   patchType,
   223  			patchBytes:  patchBytes,
   224  			userAgent:   req.UserAgent(),
   225  		}
   226  
   227  		result, wasCreated, err := p.patchResource(ctx, scope)
   228  		if err != nil {
   229  			scope.err(err, w, req)
   230  			return
   231  		}
   232  		span.AddEvent("Object stored in database")
   233  
   234  		status := http.StatusOK
   235  		if wasCreated {
   236  			status = http.StatusCreated
   237  		}
   238  
   239  		span.AddEvent("About to write a response")
   240  		defer span.AddEvent("Writing http response done")
   241  		transformResponseObject(ctx, scope, req, w, status, outputMediaType, result)
   242  	}
   243  }
   244  
   245  type mutateObjectUpdateFunc func(ctx context.Context, obj, old runtime.Object) error
   246  
   247  // patcher breaks the process of patch application and retries into smaller
   248  // pieces of functionality.
   249  // TODO: Use builder pattern to construct this object?
   250  // TODO: As part of that effort, some aspects of PatchResource above could be
   251  // moved into this type.
   252  type patcher struct {
   253  	// Pieces of RequestScope
   254  	namer               ScopeNamer
   255  	creater             runtime.ObjectCreater
   256  	defaulter           runtime.ObjectDefaulter
   257  	typer               runtime.ObjectTyper
   258  	unsafeConvertor     runtime.ObjectConvertor
   259  	resource            schema.GroupVersionResource
   260  	kind                schema.GroupVersionKind
   261  	subresource         string
   262  	dryRun              bool
   263  	validationDirective string
   264  
   265  	objectInterfaces admission.ObjectInterfaces
   266  
   267  	hubGroupVersion schema.GroupVersion
   268  
   269  	// Validation functions
   270  	createValidation rest.ValidateObjectFunc
   271  	updateValidation rest.ValidateObjectUpdateFunc
   272  	admissionCheck   admission.MutationInterface
   273  
   274  	codec runtime.Codec
   275  
   276  	options *metav1.PatchOptions
   277  
   278  	// Operation information
   279  	restPatcher rest.Patcher
   280  	name        string
   281  	patchType   types.PatchType
   282  	patchBytes  []byte
   283  	userAgent   string
   284  
   285  	// Set at invocation-time (by applyPatch) and immutable thereafter
   286  	namespace         string
   287  	updatedObjectInfo rest.UpdatedObjectInfo
   288  	mechanism         patchMechanism
   289  	forceAllowCreate  bool
   290  }
   291  
   292  type patchMechanism interface {
   293  	applyPatchToCurrentObject(requextContext context.Context, currentObject runtime.Object) (runtime.Object, error)
   294  	createNewObject(requestContext context.Context) (runtime.Object, error)
   295  }
   296  
   297  type jsonPatcher struct {
   298  	*patcher
   299  
   300  	fieldManager *managedfields.FieldManager
   301  }
   302  
   303  func (p *jsonPatcher) applyPatchToCurrentObject(requestContext context.Context, currentObject runtime.Object) (runtime.Object, error) {
   304  	// Encode will convert & return a versioned object in JSON.
   305  	currentObjJS, err := runtime.Encode(p.codec, currentObject)
   306  	if err != nil {
   307  		return nil, err
   308  	}
   309  
   310  	// Apply the patch.
   311  	patchedObjJS, appliedStrictErrs, err := p.applyJSPatch(currentObjJS)
   312  	if err != nil {
   313  		return nil, err
   314  	}
   315  
   316  	// Construct the resulting typed, unversioned object.
   317  	objToUpdate := p.restPatcher.New()
   318  	if err := runtime.DecodeInto(p.codec, patchedObjJS, objToUpdate); err != nil {
   319  		strictError, isStrictError := runtime.AsStrictDecodingError(err)
   320  		switch {
   321  		case !isStrictError:
   322  			// disregard any appliedStrictErrs, because it's an incomplete
   323  			// list of strict errors given that we don't know what fields were
   324  			// unknown because DecodeInto failed. Non-strict errors trump in this case.
   325  			return nil, errors.NewInvalid(schema.GroupKind{}, "", field.ErrorList{
   326  				field.Invalid(field.NewPath("patch"), string(patchedObjJS), err.Error()),
   327  			})
   328  		case p.validationDirective == metav1.FieldValidationWarn:
   329  			addStrictDecodingWarnings(requestContext, append(appliedStrictErrs, strictError.Errors()...))
   330  		default:
   331  			strictDecodingError := runtime.NewStrictDecodingError(append(appliedStrictErrs, strictError.Errors()...))
   332  			return nil, errors.NewInvalid(schema.GroupKind{}, "", field.ErrorList{
   333  				field.Invalid(field.NewPath("patch"), string(patchedObjJS), strictDecodingError.Error()),
   334  			})
   335  		}
   336  	} else if len(appliedStrictErrs) > 0 {
   337  		switch {
   338  		case p.validationDirective == metav1.FieldValidationWarn:
   339  			addStrictDecodingWarnings(requestContext, appliedStrictErrs)
   340  		default:
   341  			return nil, errors.NewInvalid(schema.GroupKind{}, "", field.ErrorList{
   342  				field.Invalid(field.NewPath("patch"), string(patchedObjJS), runtime.NewStrictDecodingError(appliedStrictErrs).Error()),
   343  			})
   344  		}
   345  	}
   346  
   347  	if p.options == nil {
   348  		// Provide a more informative error for the crash that would
   349  		// happen on the next line
   350  		panic("PatchOptions required but not provided")
   351  	}
   352  	objToUpdate = p.fieldManager.UpdateNoErrors(currentObject, objToUpdate, managerOrUserAgent(p.options.FieldManager, p.userAgent))
   353  	return objToUpdate, nil
   354  }
   355  
   356  func (p *jsonPatcher) createNewObject(_ context.Context) (runtime.Object, error) {
   357  	return nil, errors.NewNotFound(p.resource.GroupResource(), p.name)
   358  }
   359  
   360  type jsonPatchOp struct {
   361  	Op    string      `json:"op"`
   362  	Path  string      `json:"path"`
   363  	From  string      `json:"from"`
   364  	Value interface{} `json:"value"`
   365  }
   366  
   367  // applyJSPatch applies the patch. Input and output objects must both have
   368  // the external version, since that is what the patch must have been constructed against.
   369  func (p *jsonPatcher) applyJSPatch(versionedJS []byte) (patchedJS []byte, strictErrors []error, retErr error) {
   370  	switch p.patchType {
   371  	case types.JSONPatchType:
   372  		if p.validationDirective == metav1.FieldValidationStrict || p.validationDirective == metav1.FieldValidationWarn {
   373  			var v []jsonPatchOp
   374  			var err error
   375  			if strictErrors, err = kjson.UnmarshalStrict(p.patchBytes, &v); err != nil {
   376  				return nil, nil, errors.NewBadRequest(fmt.Sprintf("error decoding patch: %v", err))
   377  			}
   378  			for i, e := range strictErrors {
   379  				strictErrors[i] = fmt.Errorf("json patch %v", e)
   380  			}
   381  		}
   382  
   383  		patchObj, err := jsonpatch.DecodePatch(p.patchBytes)
   384  		if err != nil {
   385  			return nil, nil, errors.NewBadRequest(err.Error())
   386  		}
   387  		if len(patchObj) > maxJSONPatchOperations {
   388  			return nil, nil, errors.NewRequestEntityTooLargeError(
   389  				fmt.Sprintf("The allowed maximum operations in a JSON patch is %d, got %d",
   390  					maxJSONPatchOperations, len(patchObj)))
   391  		}
   392  		patchedJS, err := patchObj.Apply(versionedJS)
   393  		if err != nil {
   394  			return nil, nil, errors.NewGenericServerResponse(http.StatusUnprocessableEntity, "", schema.GroupResource{}, "", err.Error(), 0, false)
   395  		}
   396  		return patchedJS, strictErrors, nil
   397  	case types.MergePatchType:
   398  		if p.validationDirective == metav1.FieldValidationStrict || p.validationDirective == metav1.FieldValidationWarn {
   399  			v := map[string]interface{}{}
   400  			var err error
   401  			strictErrors, err = kjson.UnmarshalStrict(p.patchBytes, &v)
   402  			if err != nil {
   403  				return nil, nil, errors.NewBadRequest(fmt.Sprintf("error decoding patch: %v", err))
   404  			}
   405  		}
   406  
   407  		patchedJS, retErr = jsonpatch.MergePatch(versionedJS, p.patchBytes)
   408  		if retErr == jsonpatch.ErrBadJSONPatch {
   409  			return nil, nil, errors.NewBadRequest(retErr.Error())
   410  		}
   411  		return patchedJS, strictErrors, retErr
   412  	default:
   413  		// only here as a safety net - go-restful filters content-type
   414  		return nil, nil, fmt.Errorf("unknown Content-Type header for patch: %v", p.patchType)
   415  	}
   416  }
   417  
   418  type smpPatcher struct {
   419  	*patcher
   420  
   421  	// Schema
   422  	schemaReferenceObj runtime.Object
   423  	fieldManager       *managedfields.FieldManager
   424  }
   425  
   426  func (p *smpPatcher) applyPatchToCurrentObject(requestContext context.Context, currentObject runtime.Object) (runtime.Object, error) {
   427  	// Since the patch is applied on versioned objects, we need to convert the
   428  	// current object to versioned representation first.
   429  	currentVersionedObject, err := p.unsafeConvertor.ConvertToVersion(currentObject, p.kind.GroupVersion())
   430  	if err != nil {
   431  		return nil, err
   432  	}
   433  	versionedObjToUpdate, err := p.creater.New(p.kind)
   434  	if err != nil {
   435  		return nil, err
   436  	}
   437  	if err := strategicPatchObject(requestContext, p.defaulter, currentVersionedObject, p.patchBytes, versionedObjToUpdate, p.schemaReferenceObj, p.validationDirective); err != nil {
   438  		return nil, err
   439  	}
   440  	// Convert the object back to the hub version
   441  	newObj, err := p.unsafeConvertor.ConvertToVersion(versionedObjToUpdate, p.hubGroupVersion)
   442  	if err != nil {
   443  		return nil, err
   444  	}
   445  
   446  	newObj = p.fieldManager.UpdateNoErrors(currentObject, newObj, managerOrUserAgent(p.options.FieldManager, p.userAgent))
   447  	return newObj, nil
   448  }
   449  
   450  func (p *smpPatcher) createNewObject(_ context.Context) (runtime.Object, error) {
   451  	return nil, errors.NewNotFound(p.resource.GroupResource(), p.name)
   452  }
   453  
   454  type applyPatcher struct {
   455  	patch               []byte
   456  	options             *metav1.PatchOptions
   457  	creater             runtime.ObjectCreater
   458  	kind                schema.GroupVersionKind
   459  	fieldManager        *managedfields.FieldManager
   460  	userAgent           string
   461  	validationDirective string
   462  }
   463  
   464  func (p *applyPatcher) applyPatchToCurrentObject(requestContext context.Context, obj runtime.Object) (runtime.Object, error) {
   465  	force := false
   466  	if p.options.Force != nil {
   467  		force = *p.options.Force
   468  	}
   469  	if p.fieldManager == nil {
   470  		panic("FieldManager must be installed to run apply")
   471  	}
   472  
   473  	patchObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
   474  	if err := yaml.Unmarshal(p.patch, &patchObj.Object); err != nil {
   475  		return nil, errors.NewBadRequest(fmt.Sprintf("error decoding YAML: %v", err))
   476  	}
   477  
   478  	obj, err := p.fieldManager.Apply(obj, patchObj, p.options.FieldManager, force)
   479  	if err != nil {
   480  		return obj, err
   481  	}
   482  
   483  	// TODO: spawn something to track deciding whether a fieldValidation=Strict
   484  	// fatal error should return before an error from the apply operation
   485  	if p.validationDirective == metav1.FieldValidationStrict || p.validationDirective == metav1.FieldValidationWarn {
   486  		if err := yaml.UnmarshalStrict(p.patch, &map[string]interface{}{}); err != nil {
   487  			if p.validationDirective == metav1.FieldValidationStrict {
   488  				return nil, errors.NewBadRequest(fmt.Sprintf("error strict decoding YAML: %v", err))
   489  			}
   490  			addStrictDecodingWarnings(requestContext, []error{err})
   491  		}
   492  	}
   493  	return obj, nil
   494  }
   495  
   496  func (p *applyPatcher) createNewObject(requestContext context.Context) (runtime.Object, error) {
   497  	obj, err := p.creater.New(p.kind)
   498  	if err != nil {
   499  		return nil, fmt.Errorf("failed to create new object: %v", err)
   500  	}
   501  	return p.applyPatchToCurrentObject(requestContext, obj)
   502  }
   503  
   504  // strategicPatchObject applies a strategic merge patch of `patchBytes` to
   505  // `originalObject` and stores the result in `objToUpdate`.
   506  // It additionally returns the map[string]interface{} representation of the
   507  // `originalObject` and `patchBytes`.
   508  // NOTE: Both `originalObject` and `objToUpdate` are supposed to be versioned.
   509  func strategicPatchObject(
   510  	requestContext context.Context,
   511  	defaulter runtime.ObjectDefaulter,
   512  	originalObject runtime.Object,
   513  	patchBytes []byte,
   514  	objToUpdate runtime.Object,
   515  	schemaReferenceObj runtime.Object,
   516  	validationDirective string,
   517  ) error {
   518  	originalObjMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(originalObject)
   519  	if err != nil {
   520  		return err
   521  	}
   522  
   523  	patchMap := make(map[string]interface{})
   524  	var strictErrs []error
   525  	if validationDirective == metav1.FieldValidationWarn || validationDirective == metav1.FieldValidationStrict {
   526  		strictErrs, err = kjson.UnmarshalStrict(patchBytes, &patchMap)
   527  		if err != nil {
   528  			return errors.NewBadRequest(err.Error())
   529  		}
   530  	} else {
   531  		if err = kjson.UnmarshalCaseSensitivePreserveInts(patchBytes, &patchMap); err != nil {
   532  			return errors.NewBadRequest(err.Error())
   533  		}
   534  	}
   535  
   536  	if err := applyPatchToObject(requestContext, defaulter, originalObjMap, patchMap, objToUpdate, schemaReferenceObj, strictErrs, validationDirective); err != nil {
   537  		return err
   538  	}
   539  	return nil
   540  }
   541  
   542  // applyPatch is called every time GuaranteedUpdate asks for the updated object,
   543  // and is given the currently persisted object as input.
   544  // TODO: rename this function because the name implies it is related to applyPatcher
   545  func (p *patcher) applyPatch(ctx context.Context, _, currentObject runtime.Object) (objToUpdate runtime.Object, patchErr error) {
   546  	// Make sure we actually have a persisted currentObject
   547  	tracing.SpanFromContext(ctx).AddEvent("About to apply patch")
   548  	currentObjectHasUID, err := hasUID(currentObject)
   549  	if err != nil {
   550  		return nil, err
   551  	} else if !currentObjectHasUID {
   552  		objToUpdate, patchErr = p.mechanism.createNewObject(ctx)
   553  	} else {
   554  		objToUpdate, patchErr = p.mechanism.applyPatchToCurrentObject(ctx, currentObject)
   555  	}
   556  
   557  	if patchErr != nil {
   558  		return nil, patchErr
   559  	}
   560  
   561  	objToUpdateHasUID, err := hasUID(objToUpdate)
   562  	if err != nil {
   563  		return nil, err
   564  	}
   565  	if objToUpdateHasUID && !currentObjectHasUID {
   566  		accessor, err := meta.Accessor(objToUpdate)
   567  		if err != nil {
   568  			return nil, err
   569  		}
   570  		return nil, errors.NewConflict(p.resource.GroupResource(), p.name, fmt.Errorf("uid mismatch: the provided object specified uid %s, and no existing object was found", accessor.GetUID()))
   571  	}
   572  
   573  	// if this object supports namespace info
   574  	if objectMeta, err := meta.Accessor(objToUpdate); err == nil {
   575  		// ensure namespace on the object is correct, or error if a conflicting namespace was set in the object
   576  		if err := rest.EnsureObjectNamespaceMatchesRequestNamespace(rest.ExpectedNamespaceForResource(p.namespace, p.resource), objectMeta); err != nil {
   577  			return nil, err
   578  		}
   579  	}
   580  
   581  	if err := checkName(objToUpdate, p.name, p.namespace, p.namer); err != nil {
   582  		return nil, err
   583  	}
   584  	return objToUpdate, nil
   585  }
   586  
   587  func (p *patcher) admissionAttributes(ctx context.Context, updatedObject runtime.Object, currentObject runtime.Object, operation admission.Operation, operationOptions runtime.Object) admission.Attributes {
   588  	userInfo, _ := request.UserFrom(ctx)
   589  	return admission.NewAttributesRecord(updatedObject, currentObject, p.kind, p.namespace, p.name, p.resource, p.subresource, operation, operationOptions, p.dryRun, userInfo)
   590  }
   591  
   592  // applyAdmission is called every time GuaranteedUpdate asks for the updated object,
   593  // and is given the currently persisted object and the patched object as input.
   594  // TODO: rename this function because the name implies it is related to applyPatcher
   595  func (p *patcher) applyAdmission(ctx context.Context, patchedObject runtime.Object, currentObject runtime.Object) (runtime.Object, error) {
   596  	tracing.SpanFromContext(ctx).AddEvent("About to check admission control")
   597  	var operation admission.Operation
   598  	var options runtime.Object
   599  	if hasUID, err := hasUID(currentObject); err != nil {
   600  		return nil, err
   601  	} else if !hasUID {
   602  		operation = admission.Create
   603  		currentObject = nil
   604  		options = patchToCreateOptions(p.options)
   605  	} else {
   606  		operation = admission.Update
   607  		options = patchToUpdateOptions(p.options)
   608  	}
   609  	if p.admissionCheck != nil && p.admissionCheck.Handles(operation) {
   610  		attributes := p.admissionAttributes(ctx, patchedObject, currentObject, operation, options)
   611  		return patchedObject, p.admissionCheck.Admit(ctx, attributes, p.objectInterfaces)
   612  	}
   613  	return patchedObject, nil
   614  }
   615  
   616  // patchResource divides PatchResource for easier unit testing
   617  func (p *patcher) patchResource(ctx context.Context, scope *RequestScope) (runtime.Object, bool, error) {
   618  	p.namespace = request.NamespaceValue(ctx)
   619  	switch p.patchType {
   620  	case types.JSONPatchType, types.MergePatchType:
   621  		p.mechanism = &jsonPatcher{
   622  			patcher:      p,
   623  			fieldManager: scope.FieldManager,
   624  		}
   625  	case types.StrategicMergePatchType:
   626  		schemaReferenceObj, err := p.unsafeConvertor.ConvertToVersion(p.restPatcher.New(), p.kind.GroupVersion())
   627  		if err != nil {
   628  			return nil, false, err
   629  		}
   630  		p.mechanism = &smpPatcher{
   631  			patcher:            p,
   632  			schemaReferenceObj: schemaReferenceObj,
   633  			fieldManager:       scope.FieldManager,
   634  		}
   635  	// this case is unreachable if ServerSideApply is not enabled because we will have already rejected the content type
   636  	case types.ApplyPatchType:
   637  		p.mechanism = &applyPatcher{
   638  			fieldManager:        scope.FieldManager,
   639  			patch:               p.patchBytes,
   640  			options:             p.options,
   641  			creater:             p.creater,
   642  			kind:                p.kind,
   643  			userAgent:           p.userAgent,
   644  			validationDirective: p.validationDirective,
   645  		}
   646  		p.forceAllowCreate = true
   647  	default:
   648  		return nil, false, fmt.Errorf("%v: unimplemented patch type", p.patchType)
   649  	}
   650  	dedupOwnerReferencesTransformer := func(_ context.Context, obj, _ runtime.Object) (runtime.Object, error) {
   651  		// Dedup owner references after mutating admission happens
   652  		dedupOwnerReferencesAndAddWarning(obj, ctx, true)
   653  		return obj, nil
   654  	}
   655  
   656  	transformers := []rest.TransformFunc{p.applyPatch, p.applyAdmission, dedupOwnerReferencesTransformer}
   657  
   658  	wasCreated := false
   659  	p.updatedObjectInfo = rest.DefaultUpdatedObjectInfo(nil, transformers...)
   660  	requestFunc := func() (runtime.Object, error) {
   661  		// Pass in UpdateOptions to override UpdateStrategy.AllowUpdateOnCreate
   662  		options := patchToUpdateOptions(p.options)
   663  		updateObject, created, updateErr := p.restPatcher.Update(ctx, p.name, p.updatedObjectInfo, p.createValidation, p.updateValidation, p.forceAllowCreate, options)
   664  		wasCreated = created
   665  		return updateObject, updateErr
   666  	}
   667  	result, err := finisher.FinishRequest(ctx, func() (runtime.Object, error) {
   668  
   669  		result, err := requestFunc()
   670  		// If the object wasn't committed to storage because it's serialized size was too large,
   671  		// it is safe to remove managedFields (which can be large) and try again.
   672  		if isTooLargeError(err) && p.patchType != types.ApplyPatchType {
   673  			if _, accessorErr := meta.Accessor(p.restPatcher.New()); accessorErr == nil {
   674  				p.updatedObjectInfo = rest.DefaultUpdatedObjectInfo(nil,
   675  					p.applyPatch,
   676  					p.applyAdmission,
   677  					dedupOwnerReferencesTransformer,
   678  					func(_ context.Context, obj, _ runtime.Object) (runtime.Object, error) {
   679  						accessor, _ := meta.Accessor(obj)
   680  						accessor.SetManagedFields(nil)
   681  						return obj, nil
   682  					})
   683  				result, err = requestFunc()
   684  			}
   685  		}
   686  		return result, err
   687  	})
   688  	return result, wasCreated, err
   689  }
   690  
   691  // applyPatchToObject applies a strategic merge patch of <patchMap> to
   692  // <originalMap> and stores the result in <objToUpdate>.
   693  // NOTE: <objToUpdate> must be a versioned object.
   694  func applyPatchToObject(
   695  	requestContext context.Context,
   696  	defaulter runtime.ObjectDefaulter,
   697  	originalMap map[string]interface{},
   698  	patchMap map[string]interface{},
   699  	objToUpdate runtime.Object,
   700  	schemaReferenceObj runtime.Object,
   701  	strictErrs []error,
   702  	validationDirective string,
   703  ) error {
   704  	patchedObjMap, err := strategicpatch.StrategicMergeMapPatch(originalMap, patchMap, schemaReferenceObj)
   705  	if err != nil {
   706  		return interpretStrategicMergePatchError(err)
   707  	}
   708  
   709  	// Rather than serialize the patched map to JSON, then decode it to an object, we go directly from a map to an object
   710  	converter := runtime.DefaultUnstructuredConverter
   711  	returnUnknownFields := validationDirective == metav1.FieldValidationWarn || validationDirective == metav1.FieldValidationStrict
   712  	if err := converter.FromUnstructuredWithValidation(patchedObjMap, objToUpdate, returnUnknownFields); err != nil {
   713  		strictError, isStrictError := runtime.AsStrictDecodingError(err)
   714  		switch {
   715  		case !isStrictError:
   716  			// disregard any sttrictErrs, because it's an incomplete
   717  			// list of strict errors given that we don't know what fields were
   718  			// unknown because StrategicMergeMapPatch failed.
   719  			// Non-strict errors trump in this case.
   720  			return errors.NewInvalid(schema.GroupKind{}, "", field.ErrorList{
   721  				field.Invalid(field.NewPath("patch"), fmt.Sprintf("%+v", patchMap), err.Error()),
   722  			})
   723  		case validationDirective == metav1.FieldValidationWarn:
   724  			addStrictDecodingWarnings(requestContext, append(strictErrs, strictError.Errors()...))
   725  		default:
   726  			strictDecodingError := runtime.NewStrictDecodingError(append(strictErrs, strictError.Errors()...))
   727  			return errors.NewInvalid(schema.GroupKind{}, "", field.ErrorList{
   728  				field.Invalid(field.NewPath("patch"), fmt.Sprintf("%+v", patchMap), strictDecodingError.Error()),
   729  			})
   730  		}
   731  	} else if len(strictErrs) > 0 {
   732  		switch {
   733  		case validationDirective == metav1.FieldValidationWarn:
   734  			addStrictDecodingWarnings(requestContext, strictErrs)
   735  		default:
   736  			return errors.NewInvalid(schema.GroupKind{}, "", field.ErrorList{
   737  				field.Invalid(field.NewPath("patch"), fmt.Sprintf("%+v", patchMap), runtime.NewStrictDecodingError(strictErrs).Error()),
   738  			})
   739  		}
   740  	}
   741  
   742  	// Decoding from JSON to a versioned object would apply defaults, so we do the same here
   743  	defaulter.Default(objToUpdate)
   744  
   745  	return nil
   746  }
   747  
   748  // interpretStrategicMergePatchError interprets the error type and returns an error with appropriate HTTP code.
   749  func interpretStrategicMergePatchError(err error) error {
   750  	switch err {
   751  	case mergepatch.ErrBadJSONDoc, mergepatch.ErrBadPatchFormatForPrimitiveList, mergepatch.ErrBadPatchFormatForRetainKeys, mergepatch.ErrBadPatchFormatForSetElementOrderList, mergepatch.ErrUnsupportedStrategicMergePatchFormat:
   752  		return errors.NewBadRequest(err.Error())
   753  	case mergepatch.ErrNoListOfLists, mergepatch.ErrPatchContentNotMatchRetainKeys:
   754  		return errors.NewGenericServerResponse(http.StatusUnprocessableEntity, "", schema.GroupResource{}, "", err.Error(), 0, false)
   755  	default:
   756  		return err
   757  	}
   758  }
   759  
   760  // patchToUpdateOptions creates an UpdateOptions with the same field values as the provided PatchOptions.
   761  func patchToUpdateOptions(po *metav1.PatchOptions) *metav1.UpdateOptions {
   762  	if po == nil {
   763  		return nil
   764  	}
   765  	uo := &metav1.UpdateOptions{
   766  		DryRun:          po.DryRun,
   767  		FieldManager:    po.FieldManager,
   768  		FieldValidation: po.FieldValidation,
   769  	}
   770  	uo.TypeMeta.SetGroupVersionKind(metav1.SchemeGroupVersion.WithKind("UpdateOptions"))
   771  	return uo
   772  }
   773  
   774  // patchToCreateOptions creates an CreateOptions with the same field values as the provided PatchOptions.
   775  func patchToCreateOptions(po *metav1.PatchOptions) *metav1.CreateOptions {
   776  	if po == nil {
   777  		return nil
   778  	}
   779  	co := &metav1.CreateOptions{
   780  		DryRun:          po.DryRun,
   781  		FieldManager:    po.FieldManager,
   782  		FieldValidation: po.FieldValidation,
   783  	}
   784  	co.TypeMeta.SetGroupVersionKind(metav1.SchemeGroupVersion.WithKind("CreateOptions"))
   785  	return co
   786  }