Repository: kubernetes/kubernetes (language: go)

Issue:
[FG:InPlacePodVerticalScaling] Handle in-place pod resource updates in LimitRanger admission plugin
The LimitRanger admission plugin does not currently handle pod updates, but needs to be updated to account for InPlacePodVerticalScaling:

https://github.com/kubernetes/kubernetes/blob/4f04dffe5b2cd652a20b362eaea30164e3e5ea54/plugin/pkg/admission/limitranger/admission.go#L424-L429

/sig node


Discussion / hints:
/triage accepted
> /triage accepted

can let me try？
/assign
/assign

Fix patch:
diff --git a/api/discovery/api__v1.json b/api/discovery/api__v1.json
index c7d8484b315ce..aa18a21b9b63e 100644
--- a/api/discovery/api__v1.json
+++ b/api/discovery/api__v1.json
@@ -355,6 +355,17 @@
         "update"
       ]
     },
+    {
+      "kind": "Pod",
+      "name": "pods/resize",
+      "namespaced": true,
+      "singularName": "",
+      "verbs": [
+        "get",
+        "patch",
+        "update"
+      ]
+    },
     {
       "kind": "Pod",
       "name": "pods/status",
diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json
index d3d108f27872f..2d0aad06761de 100644
--- a/api/openapi-spec/swagger.json
+++ b/api/openapi-spec/swagger.json
@@ -24893,6 +24893,197 @@
         }
       }
     },
+    "/api/v1/namespaces/{namespace}/pods/{name}/resize": {
+      "get": {
+        "consumes": [
+          "*/*"
+        ],
+        "description": "read resize of the specified Pod",
+        "operationId": "readCoreV1NamespacedPodResize",
+        "produces": [
+          "application/json",
+          "application/yaml",
+          "application/vnd.kubernetes.protobuf"
+        ],
+        "responses": {
+          "200": {
+            "description": "OK",
+            "schema": {
+              "$ref": "#/definitions/io.k8s.api.core.v1.Pod"
+            }
+          },
+          "401": {
+            "description": "Unauthorized"
+          }
+        },
+        "schemes": [
+          "https"
+        ],
+        "tags": [
+          "core_v1"
+        ],
+        "x-kubernetes-action": "get",
+        "x-kubernetes-group-version-kind": {
+          "group": "",
+          "kind": "Pod",
+          "version": "v1"
+        }
+      },
+      "parameters": [
+        {
+          "description": "name of the Pod",
+          "in": "path",
+          "name": "name",
+          "required": true,
+          "type": "string",
+          "uniqueItems": true
+        },
+        {
+          "$ref": "#/parameters/namespace-vgWSWtn3"
+        },
+        {
+          "$ref": "#/parameters/pretty-tJGM1-ng"
+        }
+      ],
+      "patch": {
+        "consumes": [
+          "application/json-patch+json",
+          "application/merge-patch+json",
+          "application/strategic-merge-patch+json",
+          "application/apply-patch+yaml",
+          "application/apply-patch+cbor"
+        ],
+        "description": "partially update resize of the specified Pod",
+        "operationId": "patchCoreV1NamespacedPodResize",
+        "parameters": [
+          {
+            "$ref": "#/parameters/body-78PwaGsr"
+          },
+          {
+            "description": "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed",
+            "in": "query",
+            "name": "dryRun",
+            "type": "string",
+            "uniqueItems": true
+          },
+          {
+            "$ref": "#/parameters/fieldManager-7c6nTn1T"
+          },
+          {
+            "description": "fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered.",
+            "in": "query",
+            "name": "fieldValidation",
+            "type": "string",
+            "uniqueItems": true
+          },
+          {
+            "$ref": "#/parameters/force-tOGGb0Yi"
+          }
+        ],
+        "produces": [
+          "application/json",
+          "application/yaml",
+          "application/vnd.kubernetes.protobuf"
+        ],
+        "responses": {
+          "200": {
+            "description": "OK",
+            "schema": {
+              "$ref": "#/definitions/io.k8s.api.core.v1.Pod"
+            }
+          },
+          "201": {
+            "description": "Created",
+            "schema": {
+              "$ref": "#/definitions/io.k8s.api.core.v1.Pod"
+            }
+          },
+          "401": {
+            "description": "Unauthorized"
+          }
+        },
+        "schemes": [
+          "https"
+        ],
+        "tags": [
+          "core_v1"
+        ],
+        "x-kubernetes-action": "patch",
+        "x-kubernetes-group-version-kind": {
+          "group": "",
+          "kind": "Pod",
+          "version": "v1"
+        }
+      },
+      "put": {
+        "consumes": [
+          "*/*"
+        ],
+        "description": "replace resize of the specified Pod",
+        "operationId": "replaceCoreV1NamespacedPodResize",
+        "parameters": [
+          {
+            "in": "body",
+            "name": "body",
+            "required": true,
+            "schema": {
+              "$ref": "#/definitions/io.k8s.api.core.v1.Pod"
+            }
+          },
+          {
+            "description": "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed",
+            "in": "query",
+            "name": "dryRun",
+            "type": "string",
+            "uniqueItems": true
+          },
+          {
+            "$ref": "#/parameters/fieldManager-Qy4HdaTW"
+          },
+          {
+            "description": "fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered.",
+            "in": "query",
+            "name": "fieldValidation",
+            "type": "string",
+            "uniqueItems": true
+          }
+        ],
+        "produces": [
+          "application/json",
+          "application/yaml",
+          "application/vnd.kubernetes.protobuf"
+        ],
+        "responses": {
+          "200": {
+            "description": "OK",
+            "schema": {
+              "$ref": "#/definitions/io.k8s.api.core.v1.Pod"
+            }
+          },
+          "201": {
+            "description": "Created",
+            "schema": {
+              "$ref": "#/definitions/io.k8s.api.core.v1.Pod"
+            }
+          },
+          "401": {
+            "description": "Unauthorized"
+          }
+        },
+        "schemes": [
+          "https"
+        ],
+        "tags": [
+          "core_v1"
+        ],
+        "x-kubernetes-action": "put",
+        "x-kubernetes-group-version-kind": {
+          "group": "",
+          "kind": "Pod",
+          "version": "v1"
+        }
+      }
+    },
     "/api/v1/namespaces/{namespace}/pods/{name}/status": {
       "get": {
         "consumes": [
diff --git a/api/openapi-spec/v3/api__v1_openapi.json b/api/openapi-spec/v3/api__v1_openapi.json
index 65045c72c08f4..10a7b9fd7e015 100644
--- a/api/openapi-spec/v3/api__v1_openapi.json
+++ b/api/openapi-spec/v3/api__v1_openapi.json
@@ -18029,6 +18029,300 @@
         }
       }
     },
+    "/api/v1/namespaces/{namespace}/pods/{name}/resize": {
+      "get": {
+        "description": "read resize of the specified Pod",
+        "operationId": "readCoreV1NamespacedPodResize",
+        "responses": {
+          "200": {
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/io.k8s.api.core.v1.Pod"
+                }
+              },
+              "application/vnd.kubernetes.protobuf": {
+                "schema": {
+                  "$ref": "#/components/schemas/io.k8s.api.core.v1.Pod"
+                }
+              },
+              "application/yaml": {
+                "schema": {
+                  "$ref": "#/components/schemas/io.k8s.api.core.v1.Pod"
+                }
+              }
+            },
+            "description": "OK"
+          },
+          "401": {
+            "description": "Unauthorized"
+          }
+        },
+        "tags": [
+          "core_v1"
+        ],
+        "x-kubernetes-action": "get",
+        "x-kubernetes-group-version-kind": {
+          "group": "",
+          "kind": "Pod",
+          "version": "v1"
+        }
+      },
+      "parameters": [
+        {
+          "description": "name of the Pod",
+          "in": "path",
+          "name": "name",
+          "required": true,
+          "schema": {
+            "type": "string",
+            "uniqueItems": true
+          }
+        },
+        {
+          "description": "object name and auth scope, such as for teams and projects",
+          "in": "path",
+          "name": "namespace",
+          "required": true,
+          "schema": {
+            "type": "string",
+            "uniqueItems": true
+          }
+        },
+        {
+          "description": "If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget).",
+          "in": "query",
+          "name": "pretty",
+          "schema": {
+            "type": "string",
+            "uniqueItems": true
+          }
+        }
+      ],
+      "patch": {
+        "description": "partially update resize of the specified Pod",
+        "operationId": "patchCoreV1NamespacedPodResize",
+        "parameters": [
+          {
+            "description": "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed",
+            "in": "query",
+            "name": "dryRun",
+            "schema": {
+              "type": "string",
+              "uniqueItems": true
+            }
+          },
+          {
+            "description": "fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch).",
+            "in": "query",
+            "name": "fieldManager",
+            "schema": {
+              "type": "string",
+              "uniqueItems": true
+            }
+          },
+          {
+            "description": "fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered.",
+            "in": "query",
+            "name": "fieldValidation",
+            "schema": {
+              "type": "string",
+              "uniqueItems": true
+            }
+          },
+          {
+            "description": "Force is going to \"force\" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests.",
+            "in": "query",
+            "name": "force",
+            "schema": {
+              "type": "boolean",
+              "uniqueItems": true
+            }
+          }
+        ],
+        "requestBody": {
+          "content": {
+            "application/apply-patch+cbor": {
+              "schema": {
+                "$ref": "#/components/schemas/io.k8s.apimachinery.pkg.apis.meta.v1.Patch"
+              }
+            },
+            "application/apply-patch+yaml": {
+              "schema": {
+                "$ref": "#/components/schemas/io.k8s.apimachinery.pkg.apis.meta.v1.Patch"
+              }
+            },
+            "application/json-patch+json": {
+              "schema": {
+                "$ref": "#/components/schemas/io.k8s.apimachinery.pkg.apis.meta.v1.Patch"
+              }
+            },
+            "application/merge-patch+json": {
+              "schema": {
+                "$ref": "#/components/schemas/io.k8s.apimachinery.pkg.apis.meta.v1.Patch"
+              }
+            },
+            "application/strategic-merge-patch+json": {
+              "schema": {
+                "$ref": "#/components/schemas/io.k8s.apimachinery.pkg.apis.meta.v1.Patch"
+              }
+            }
+          },
+          "required": true
+        },
+        "responses": {
+          "200": {
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/io.k8s.api.core.v1.Pod"
+                }
+              },
+              "application/vnd.kubernetes.protobuf": {
+                "schema": {
+                  "$ref": "#/components/schemas/io.k8s.api.core.v1.Pod"
+                }
+              },
+              "application/yaml": {
+                "schema": {
+                  "$ref": "#/components/schemas/io.k8s.api.core.v1.Pod"
+                }
+              }
+            },
+            "description": "OK"
+          },
+          "201": {
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/io.k8s.api.core.v1.Pod"
+                }
+              },
+              "application/vnd.kubernetes.protobuf": {
+                "schema": {
+                  "$ref": "#/components/schemas/io.k8s.api.core.v1.Pod"
+                }
+              },
+              "application/yaml": {
+                "schema": {
+                  "$ref": "#/components/schemas/io.k8s.api.core.v1.Pod"
+                }
+              }
+            },
+            "description": "Created"
+          },
+          "401": {
+            "description": "Unauthorized"
+          }
+        },
+        "tags": [
+          "core_v1"
+        ],
+        "x-kubernetes-action": "patch",
+        "x-kubernetes-group-version-kind": {
+          "group": "",
+          "kind": "Pod",
+          "version": "v1"
+        }
+      },
+      "put": {
+        "description": "replace resize of the specified Pod",
+        "operationId": "replaceCoreV1NamespacedPodResize",
+        "parameters": [
+          {
+            "description": "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed",
+            "in": "query",
+            "name": "dryRun",
+            "schema": {
+              "type": "string",
+              "uniqueItems": true
+            }
+          },
+          {
+            "description": "fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint.",
+            "in": "query",
+            "name": "fieldManager",
+            "schema": {
+              "type": "string",
+              "uniqueItems": true
+            }
+          },
+          {
+            "description": "fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered.",
+            "in": "query",
+            "name": "fieldValidation",
+            "schema": {
+              "type": "string",
+              "uniqueItems": true
+            }
+          }
+        ],
+        "requestBody": {
+          "content": {
+            "*/*": {
+              "schema": {
+                "$ref": "#/components/schemas/io.k8s.api.core.v1.Pod"
+              }
+            }
+          },
+          "required": true
+        },
+        "responses": {
+          "200": {
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/io.k8s.api.core.v1.Pod"
+                }
+              },
+              "application/vnd.kubernetes.protobuf": {
+                "schema": {
+                  "$ref": "#/components/schemas/io.k8s.api.core.v1.Pod"
+                }
+              },
+              "application/yaml": {
+                "schema": {
+                  "$ref": "#/components/schemas/io.k8s.api.core.v1.Pod"
+                }
+              }
+            },
+            "description": "OK"
+          },
+          "201": {
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/io.k8s.api.core.v1.Pod"
+                }
+              },
+              "application/vnd.kubernetes.protobuf": {
+                "schema": {
+                  "$ref": "#/components/schemas/io.k8s.api.core.v1.Pod"
+                }
+              },
+              "application/yaml": {
+                "schema": {
+                  "$ref": "#/components/schemas/io.k8s.api.core.v1.Pod"
+                }
+              }
+            },
+            "description": "Created"
+          },
+          "401": {
+            "description": "Unauthorized"
+          }
+        },
+        "tags": [
+          "core_v1"
+        ],
+        "x-kubernetes-action": "put",
+        "x-kubernetes-group-version-kind": {
+          "group": "",
+          "kind": "Pod",
+          "version": "v1"
+        }
+      }
+    },
     "/api/v1/namespaces/{namespace}/pods/{name}/status": {
       "get": {
         "description": "read status of the specified Pod",
diff --git a/pkg/apis/core/validation/validation.go b/pkg/apis/core/validation/validation.go
index 031f4494f5162..7e814919da1ec 100644
--- a/pkg/apis/core/validation/validation.go
+++ b/pkg/apis/core/validation/validation.go
@@ -5135,16 +5135,6 @@ var updatablePodSpecFields = []string{
 	"`spec.activeDeadlineSeconds`",
 	"`spec.tolerations` (only additions to existing tolerations)",
 	"`spec.terminationGracePeriodSeconds` (allow it to be set to 1 if it was previously negative)",
-	"`spec.containers[*].resources` (for CPU/memory only)",
-}
-
-// TODO(vinaykul,InPlacePodVerticalScaling): Drop this var once InPlacePodVerticalScaling goes GA and featuregate is gone.
-var updatablePodSpecFieldsNoResources = []string{
-	"`spec.containers[*].image`",
-	"`spec.initContainers[*].image`",
-	"`spec.activeDeadlineSeconds`",
-	"`spec.tolerations` (only additions to existing tolerations)",
-	"`spec.terminationGracePeriodSeconds` (allow it to be set to 1 if it was previously negative)",
 }
 
 // ValidatePodUpdate tests to see if the update is legal for an end user to make. newPod is updated with fields
@@ -5206,45 +5196,12 @@ func ValidatePodUpdate(newPod, oldPod *core.Pod, opts PodValidationOptions) fiel
 		return allErrs
 	}
 
-	if qos.GetPodQOS(oldPod) != qos.ComputePodQOS(newPod) {
-		allErrs = append(allErrs, field.Invalid(fldPath, newPod.Status.QOSClass, "Pod QoS is immutable"))
-	}
-
 	// handle updateable fields by munging those fields prior to deep equal comparison.
 	mungedPodSpec := *newPod.Spec.DeepCopy()
 	// munge spec.containers[*].image
 	var newContainers []core.Container
 	for ix, container := range mungedPodSpec.Containers {
 		container.Image = oldPod.Spec.Containers[ix].Image // +k8s:verify-mutation:reason=clone
-		// When the feature-gate is turned off, any new requests attempting to update CPU or memory
-		// resource values will result in validation failure.
-		if utilfeature.DefaultFeatureGate.Enabled(features.InPlacePodVerticalScaling) {
-			// Resources are mutable for CPU & memory only
-			//   - user can now modify Resources to express new desired Resources
-			mungeCpuMemResources := func(resourceList, oldResourceList core.ResourceList) core.ResourceList {
-				if oldResourceList == nil {
-					return nil
-				}
-				var mungedResourceList core.ResourceList
-				if resourceList == nil {
-					mungedResourceList = make(core.ResourceList)
-				} else {
-					mungedResourceList = resourceList.DeepCopy()
-				}
-				delete(mungedResourceList, core.ResourceCPU)
-				delete(mungedResourceList, core.ResourceMemory)
-				if cpu, found := oldResourceList[core.ResourceCPU]; found {
-					mungedResourceList[core.ResourceCPU] = cpu
-				}
-				if mem, found := oldResourceList[core.ResourceMemory]; found {
-					mungedResourceList[core.ResourceMemory] = mem
-				}
-				return mungedResourceList
-			}
-			lim := mungeCpuMemResources(container.Resources.Limits, oldPod.Spec.Containers[ix].Resources.Limits)
-			req := mungeCpuMemResources(container.Resources.Requests, oldPod.Spec.Containers[ix].Resources.Requests)
-			container.Resources = core.ResourceRequirements{Limits: lim, Requests: req}
-		}
 		newContainers = append(newContainers, container)
 	}
 	mungedPodSpec.Containers = newContainers
@@ -5321,10 +5278,7 @@ func ValidatePodUpdate(newPod, oldPod *core.Pod, opts PodValidationOptions) fiel
 		// This diff isn't perfect, but it's a helluva lot better an "I'm not going to tell you what the difference is".
 		// TODO: Pinpoint the specific field that causes the invalid error after we have strategic merge diff
 		specDiff := cmp.Diff(oldPod.Spec, mungedPodSpec)
-		errs := field.Forbidden(specPath, fmt.Sprintf("pod updates may not change fields other than %s\n%v", strings.Join(updatablePodSpecFieldsNoResources, ","), specDiff))
-		if utilfeature.DefaultFeatureGate.Enabled(features.InPlacePodVerticalScaling) {
-			errs = field.Forbidden(specPath, fmt.Sprintf("pod updates may not change fields other than %s\n%v", strings.Join(updatablePodSpecFields, ","), specDiff))
-		}
+		errs := field.Forbidden(specPath, fmt.Sprintf("pod updates may not change fields other than %s\n%v", strings.Join(updatablePodSpecFields, ","), specDiff))
 		allErrs = append(allErrs, errs)
 	}
 	return allErrs
@@ -5531,6 +5485,67 @@ func ValidatePodEphemeralContainersUpdate(newPod, oldPod *core.Pod, opts PodVali
 	return allErrs
 }
 
+// ValidatePodResize tests that a user update to pod container resources is valid.
+// newPod and oldPod must only differ in their Containers[*].Resources and
+// Containers[*].ResizePolicy field.
+func ValidatePodResize(newPod, oldPod *core.Pod, opts PodValidationOptions) field.ErrorList {
+	// Part 1: Validate newPod's spec and updates to metadata
+	fldPath := field.NewPath("metadata")
+	allErrs := ValidateImmutableField(&newPod.ObjectMeta, &oldPod.ObjectMeta, fldPath)
+	allErrs = append(allErrs, validatePodMetadataAndSpec(newPod, opts)...)
+
+	// static pods cannot be resized.
+	if _, ok := oldPod.Annotations[core.MirrorPodAnnotationKey]; ok {
+		return field.ErrorList{field.Forbidden(field.NewPath(""), "static pods cannot be resized")}
+	}
+
+	// Part 2: Validate that the changes between oldPod.Spec.Containers[].Resources and
+	// newPod.Spec.Containers[].Resources are allowed.
+	specPath := field.NewPath("spec")
+	if qos.GetPodQOS(oldPod) != qos.ComputePodQOS(newPod) {
+		allErrs = append(allErrs, field.Invalid(specPath, newPod.Status.QOSClass, "Pod QOS Class may not change as a result of resizing"))
+	}
+
+	// Ensure that only CPU and memory resources are mutable.
+	originalCPUMemPodSpec := *newPod.Spec.DeepCopy()
+	var newContainers []core.Container
+	for ix, container := range originalCPUMemPodSpec.Containers {
+		dropCPUMemoryUpdates := func(resourceList, oldResourceList core.ResourceList) core.ResourceList {
+			if oldResourceList == nil {
+				return nil
+			}
+			var mungedResourceList core.ResourceList
+			if resourceList == nil {
+				mungedResourceList = make(core.ResourceList)
+			} else {
+				mungedResourceList = resourceList.DeepCopy()
+			}
+			delete(mungedResourceList, core.ResourceCPU)
+			delete(mungedResourceList, core.ResourceMemory)
+			if cpu, found := oldResourceList[core.ResourceCPU]; found {
+				mungedResourceList[core.ResourceCPU] = cpu
+			}
+			if mem, found := oldResourceList[core.ResourceMemory]; found {
+				mungedResourceList[core.ResourceMemory] = mem
+			}
+			return mungedResourceList
+		}
+		lim := dropCPUMemoryUpdates(container.Resources.Limits, oldPod.Spec.Containers[ix].Resources.Limits)
+		req := dropCPUMemoryUpdates(container.Resources.Requests, oldPod.Spec.Containers[ix].Resources.Requests)
+		container.Resources = core.ResourceRequirements{Limits: lim, Requests: req}
+		container.ResizePolicy = oldPod.Spec.Containers[ix].ResizePolicy // +k8s:verify-mutation:reason=clone
+		newContainers = append(newContainers, container)
+	}
+	originalCPUMemPodSpec.Containers = newContainers
+	if !apiequality.Semantic.DeepEqual(originalCPUMemPodSpec, oldPod.Spec) {
+		// This likely means that the user has made changes to resources other than CPU and Memory.
+		specDiff := cmp.Diff(oldPod.Spec, originalCPUMemPodSpec)
+		errs := field.Forbidden(specPath, fmt.Sprintf("only cpu and memory resources are mutable\n%v", specDiff))
+		allErrs = append(allErrs, errs)
+	}
+	return allErrs
+}
+
 // ValidatePodBinding tests if required fields in the pod binding are legal.
 func ValidatePodBinding(binding *core.Binding) field.ErrorList {
 	allErrs := field.ErrorList{}
diff --git a/pkg/quota/v1/evaluator/core/persistent_volume_claims.go b/pkg/quota/v1/evaluator/core/persistent_volume_claims.go
index 059dd6d154412..a4da87b496b69 100644
--- a/pkg/quota/v1/evaluator/core/persistent_volume_claims.go
+++ b/pkg/quota/v1/evaluator/core/persistent_volume_claims.go
@@ -90,14 +90,11 @@ func (p *pvcEvaluator) GroupResource() schema.GroupResource {
 
 // Handles returns true if the evaluator should handle the specified operation.
 func (p *pvcEvaluator) Handles(a admission.Attributes) bool {
-	op := a.GetOperation()
-	if op == admission.Create {
-		return true
-	}
-	if op == admission.Update {
-		return true
+	if a.GetSubresource() != "" {
+		return false
 	}
-	return false
+	op := a.GetOperation()
+	return admission.Create == op || admission.Update == op
 }
 
 // Matches returns true if the evaluator matches the specified quota with the provided input item
diff --git a/pkg/quota/v1/evaluator/core/pods.go b/pkg/quota/v1/evaluator/core/pods.go
index c82fa98437c05..ac438685db008 100644
--- a/pkg/quota/v1/evaluator/core/pods.go
+++ b/pkg/quota/v1/evaluator/core/pods.go
@@ -156,13 +156,14 @@ func (p *podEvaluator) GroupResource() schema.GroupResource {
 // Handles returns true if the evaluator should handle the specified attributes.
 func (p *podEvaluator) Handles(a admission.Attributes) bool {
 	op := a.GetOperation()
-	if op == admission.Create {
-		return true
-	}
-	if feature.DefaultFeatureGate.Enabled(features.InPlacePodVerticalScaling) && op == admission.Update {
-		return true
+	switch a.GetSubresource() {
+	case "":
+		return op == admission.Create
+	case "resize":
+		return op == admission.Update
+	default:
+		return false
 	}
-	return false
 }
 
 // Matches returns true if the evaluator matches the specified quota with the provided input item
diff --git a/pkg/quota/v1/evaluator/core/resource_claims.go b/pkg/quota/v1/evaluator/core/resource_claims.go
index db594ffb5e20c..a55715023bc55 100644
--- a/pkg/quota/v1/evaluator/core/resource_claims.go
+++ b/pkg/quota/v1/evaluator/core/resource_claims.go
@@ -68,14 +68,11 @@ func (p *claimEvaluator) GroupResource() schema.GroupResource {
 
 // Handles returns true if the evaluator should handle the specified operation.
 func (p *claimEvaluator) Handles(a admission.Attributes) bool {
-	op := a.GetOperation()
-	if op == admission.Create {
-		return true
-	}
-	if op == admission.Update {
-		return true
+	if a.GetSubresource() != "" {
+		return false
 	}
-	return false
+	op := a.GetOperation()
+	return admission.Create == op || admission.Update == op
 }
 
 // Matches returns true if the evaluator matches the specified quota with the provided input item
diff --git a/pkg/quota/v1/evaluator/core/services.go b/pkg/quota/v1/evaluator/core/services.go
index b681a853ac607..7bba26eeb8888 100644
--- a/pkg/quota/v1/evaluator/core/services.go
+++ b/pkg/quota/v1/evaluator/core/services.go
@@ -67,6 +67,9 @@ func (p *serviceEvaluator) GroupResource() schema.GroupResource {
 
 // Handles returns true of the evaluator should handle the specified operation.
 func (p *serviceEvaluator) Handles(a admission.Attributes) bool {
+	if a.GetSubresource() != "" {
+		return false
+	}
 	operation := a.GetOperation()
 	// We handle create and update because a service type can change.
 	return admission.Create == operation || admission.Update == operation
diff --git a/pkg/registry/core/pod/storage/storage.go b/pkg/registry/core/pod/storage/storage.go
index 5bdf342d06857..8aaa358d0856f 100644
--- a/pkg/registry/core/pod/storage/storage.go
+++ b/pkg/registry/core/pod/storage/storage.go
@@ -54,6 +54,7 @@ type PodStorage struct {
 	Eviction            *EvictionREST
 	Status              *StatusREST
 	EphemeralContainers *EphemeralContainersREST
+	Resize              *ResizeREST
 	Log                 *podrest.LogREST
 	Proxy               *podrest.ProxyREST
 	Exec                *podrest.ExecREST
@@ -100,6 +101,8 @@ func NewStorage(optsGetter generic.RESTOptionsGetter, k client.ConnectionInfoGet
 	statusStore.ResetFieldsStrategy = registrypod.StatusStrategy
 	ephemeralContainersStore := *store
 	ephemeralContainersStore.UpdateStrategy = registrypod.EphemeralContainersStrategy
+	resizeStore := *store
+	resizeStore.UpdateStrategy = registrypod.ResizeStrategy
 
 	bindingREST := &BindingREST{store: store}
 	return PodStorage{
@@ -109,6 +112,7 @@ func NewStorage(optsGetter generic.RESTOptionsGetter, k client.ConnectionInfoGet
 		Eviction:            newEvictionStorage(&statusStore, podDisruptionBudgetClient),
 		Status:              &StatusREST{store: &statusStore},
 		EphemeralContainers: &EphemeralContainersREST{store: &ephemeralContainersStore},
+		Resize:              &ResizeREST{store: &resizeStore},
 		Log:                 &podrest.LogREST{Store: store, KubeletConn: k},
 		Proxy:               &podrest.ProxyREST{Store: store, ProxyTransport: proxyTransport},
 		Exec:                &podrest.ExecREST{Store: store, KubeletConn: k},
@@ -365,3 +369,33 @@ func (r *EphemeralContainersREST) Update(ctx context.Context, name string, objIn
 	// subresources should never allow create on update.
 	return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
 }
+
+// ResizeREST implements the REST endpoint for resizing Pod containers.
+type ResizeREST struct {
+	store *genericregistry.Store
+}
+
+var _ = rest.Patcher(&ResizeREST{})
+
+// Get retrieves the object from the storage. It is required to support Patch.
+func (r *ResizeREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
+	return r.store.Get(ctx, name, options)
+}
+
+// New creates a new pod resource
+func (r *ResizeREST) New() runtime.Object {
+	return &api.Pod{}
+}
+
+// Destroy cleans up resources on shutdown.
+func (r *ResizeREST) Destroy() {
+	// Given that underlying store is shared with REST,
+	// we don't destroy it here explicitly.
+}
+
+// Update alters the resource fields in PodSpec
+func (r *ResizeREST) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) {
+	// We are explicitly setting forceAllowCreate to false in the call to the underlying storage because
+	// subresources should never allow create on update.
+	return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
+}
diff --git a/pkg/registry/core/pod/strategy.go b/pkg/registry/core/pod/strategy.go
index 541fc43a2202d..05257423fdc95 100644
--- a/pkg/registry/core/pod/strategy.go
+++ b/pkg/registry/core/pod/strategy.go
@@ -101,15 +101,6 @@ func (podStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object
 	newPod := obj.(*api.Pod)
 	oldPod := old.(*api.Pod)
 	newPod.Status = oldPod.Status
-
-	if utilfeature.DefaultFeatureGate.Enabled(features.InPlacePodVerticalScaling) {
-		// With support for in-place pod resizing, container resources are now mutable.
-		// If container resources are updated with new resource requests values, a pod resize is
-		// desired. The status of this request is reflected by setting Resize field to "Proposed"
-		// as a signal to the caller that the request is being considered.
-		podutil.MarkPodProposedForResize(oldPod, newPod)
-	}
-
 	podutil.DropDisabledPodFields(newPod, oldPod)
 }
 
@@ -256,11 +247,7 @@ var EphemeralContainersStrategy = podEphemeralContainersStrategy{Strategy}
 
 // dropNonEphemeralContainerUpdates discards all changes except for pod.Spec.EphemeralContainers and certain metadata
 func dropNonEphemeralContainerUpdates(newPod, oldPod *api.Pod) *api.Pod {
-	pod := oldPod.DeepCopy()
-	pod.Name = newPod.Name
-	pod.Namespace = newPod.Namespace
-	pod.ResourceVersion = newPod.ResourceVersion
-	pod.UID = newPod.UID
+	pod := dropPodUpdates(newPod, oldPod)
 	pod.Spec.EphemeralContainers = newPod.Spec.EphemeralContainers
 	return pod
 }
@@ -286,6 +273,85 @@ func (podEphemeralContainersStrategy) WarningsOnUpdate(ctx context.Context, obj,
 	return nil
 }
 
+type podResizeStrategy struct {
+	podStrategy
+
+	resetFieldsFilter fieldpath.Filter
+}
+
+// ResizeStrategy wraps and exports the used podStrategy for the storage package.
+var ResizeStrategy = podResizeStrategy{
+	podStrategy: Strategy,
+	resetFieldsFilter: fieldpath.NewIncludeMatcherFilter(
+		fieldpath.MakePrefixMatcherOrDie("spec", "containers", fieldpath.MatchAnyPathElement(), "resources"),
+		fieldpath.MakePrefixMatcherOrDie("spec", "containers", fieldpath.MatchAnyPathElement(), "resizePolicy"),
+	),
+}
+
+// dropNonResizeUpdates discards all changes except for pod.Spec.Containers[*].Resources,ResizePolicy and certain metadata
+func dropNonResizeUpdates(newPod, oldPod *api.Pod) *api.Pod {
+	pod := dropPodUpdates(newPod, oldPod)
+
+	// Containers are not allowed to be re-ordered, but in case they were,
+	// we don't want to corrupt them here. It will get caught in validation.
+	oldCtrToIndex := make(map[string]int)
+	for idx, ctr := range pod.Spec.Containers {
+		oldCtrToIndex[ctr.Name] = idx
+	}
+	// TODO: Once we add in-place pod resize support for sidecars, we need to allow
+	// modifying sidecar resources via resize subresource too.
+	for _, ctr := range newPod.Spec.Containers {
+		idx, ok := oldCtrToIndex[ctr.Name]
+		if !ok {
+			continue
+		}
+		pod.Spec.Containers[idx].Resources = ctr.Resources
+		pod.Spec.Containers[idx].ResizePolicy = ctr.ResizePolicy
+	}
+	return pod
+}
+
+func (podResizeStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
+	newPod := obj.(*api.Pod)
+	oldPod := old.(*api.Pod)
+
+	*newPod = *dropNonResizeUpdates(newPod, oldPod)
+	podutil.MarkPodProposedForResize(oldPod, newPod)
+	podutil.DropDisabledPodFields(newPod, oldPod)
+}
+
+func (podResizeStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
+	newPod := obj.(*api.Pod)
+	oldPod := old.(*api.Pod)
+	opts := podutil.GetValidationOptionsFromPodSpecAndMeta(&newPod.Spec, &oldPod.Spec, &newPod.ObjectMeta, &oldPod.ObjectMeta)
+	opts.ResourceIsPod = true
+	return corevalidation.ValidatePodResize(newPod, oldPod, opts)
+}
+
+// WarningsOnUpdate returns warnings for the given update.
+func (podResizeStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
+	return nil
+}
+
+// GetResetFieldsFilter returns a set of fields filter reset by the strategy
+// and should not be modified by the user.
+func (p podResizeStrategy) GetResetFieldsFilter() map[fieldpath.APIVersion]fieldpath.Filter {
+	return map[fieldpath.APIVersion]fieldpath.Filter{
+		"v1": p.resetFieldsFilter,
+	}
+}
+
+// dropPodUpdates drops any changes in the pod.
+func dropPodUpdates(newPod, oldPod *api.Pod) *api.Pod {
+	pod := oldPod.DeepCopy()
+	pod.Name = newPod.Name
+	pod.Namespace = newPod.Namespace
+	pod.ResourceVersion = newPod.ResourceVersion
+	pod.UID = newPod.UID
+
+	return pod
+}
+
 // GetAttrs returns labels and fields of a given object for filtering purposes.
 func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) {
 	pod, ok := obj.(*api.Pod)
diff --git a/pkg/registry/core/rest/storage_core.go b/pkg/registry/core/rest/storage_core.go
index bac4b133de1c1..b5c4e39ec9561 100644
--- a/pkg/registry/core/rest/storage_core.go
+++ b/pkg/registry/core/rest/storage_core.go
@@ -242,6 +242,9 @@ func (p *legacyProvider) NewRESTStorage(apiResourceConfigSource serverstorage.AP
 			storage[resource+"/eviction"] = podStorage.Eviction
 		}
 		storage[resource+"/ephemeralcontainers"] = podStorage.EphemeralContainers
+		if utilfeature.DefaultFeatureGate.Enabled(features.InPlacePodVerticalScaling) {
+			storage[resource+"/resize"] = podStorage.Resize
+		}
 	}
 	if resource := "bindings"; apiResourceConfigSource.ResourceEnabled(corev1.SchemeGroupVersion.WithResource(resource)) {
 		storage[resource] = podStorage.LegacyBinding
diff --git a/plugin/pkg/admission/limitranger/admission.go b/plugin/pkg/admission/limitranger/admission.go
index 4ee9e6fb57214..db02fbd7dd4d9 100644
--- a/plugin/pkg/admission/limitranger/admission.go
+++ b/plugin/pkg/admission/limitranger/admission.go
@@ -415,6 +415,13 @@ func (d *DefaultLimitRangerActions) ValidateLimit(limitRange *corev1.LimitRange,
 // SupportsAttributes ignores all calls that do not deal with pod resources or storage requests (PVCs).
 // Also ignores any call that has a subresource defined.
 func (d *DefaultLimitRangerActions) SupportsAttributes(a admission.Attributes) bool {
+	// Handle in-place vertical scaling of pods, where users modify container
+	// resources using the resize subresource.
+	if a.GetSubresource() == "resize" && a.GetKind().GroupKind() == api.Kind("Pod") && a.GetOperation() == admission.Update {
+		return true
+	}
+
+	// No other subresources are supported
 	if a.GetSubresource() != "" {
 		return false
 	}
diff --git a/staging/src/k8s.io/api/core/v1/types.go b/staging/src/k8s.io/api/core/v1/types.go
index 492b49b3911ce..9f1c3ec603570 100644
--- a/staging/src/k8s.io/api/core/v1/types.go
+++ b/staging/src/k8s.io/api/core/v1/types.go
@@ -4911,6 +4911,7 @@ type PodStatusResult struct {
 
 // +genclient
 // +genclient:method=UpdateEphemeralContainers,verb=update,subresource=ephemeralcontainers
+// +genclient:method=UpdateResize,verb=update,subresource=resize
 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 // +k8s:prerelease-lifecycle-gen:introduced=1.0
 
diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/resourcequota/admission.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/resourcequota/admission.go
index 25c266479dbd0..e7d59bb707da0 100644
--- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/resourcequota/admission.go
+++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/resourcequota/admission.go
@@ -155,10 +155,6 @@ func (a *QuotaAdmission) ValidateInitialization() error {
 
 // Validate makes admission decisions while enforcing quota
 func (a *QuotaAdmission) Validate(ctx context.Context, attr admission.Attributes, o admission.ObjectInterfaces) (err error) {
-	// ignore all operations that correspond to sub-resource actions
-	if attr.GetSubresource() != "" {
-		return nil
-	}
 	// ignore all operations that are not namespaced or creation of namespaces
 	if attr.GetNamespace() == "" || isNamespaceCreation(attr) {
 		return nil
diff --git a/staging/src/k8s.io/apiserver/pkg/quota/v1/generic/evaluator.go b/staging/src/k8s.io/apiserver/pkg/quota/v1/generic/evaluator.go
index e122248f861ca..7549a2e561f8e 100644
--- a/staging/src/k8s.io/apiserver/pkg/quota/v1/generic/evaluator.go
+++ b/staging/src/k8s.io/apiserver/pkg/quota/v1/generic/evaluator.go
@@ -250,6 +250,9 @@ func (o *objectCountEvaluator) Constraints(required []corev1.ResourceName, item
 
 // Handles returns true if the object count evaluator needs to track this attributes.
 func (o *objectCountEvaluator) Handles(a admission.Attributes) bool {
+	if a.GetSubresource() != "" {
+		return false
+	}
 	operation := a.GetOperation()
 	return operation == admission.Create
 }
diff --git a/staging/src/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_pod.go b/staging/src/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_pod.go
index 759c9a5265bd6..bb3972560a501 100644
--- a/staging/src/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_pod.go
+++ b/staging/src/k8s.io/client-go/kubernetes/typed/core/v1/fake/fake_pod.go
@@ -207,3 +207,15 @@ func (c *FakePods) UpdateEphemeralContainers(ctx context.Context, podName string
 	}
 	return obj.(*v1.Pod), err
 }
+
+// UpdateResize takes the representation of a pod and updates it. Returns the server's representation of the pod, and an error, if there is any.
+func (c *FakePods) UpdateResize(ctx context.Context, podName string, pod *v1.Pod, opts metav1.UpdateOptions) (result *v1.Pod, err error) {
+	emptyResult := &v1.Pod{}
+	obj, err := c.Fake.
+		Invokes(testing.NewUpdateSubresourceActionWithOptions(podsResource, "resize", c.ns, pod, opts), &v1.Pod{})
+
+	if obj == nil {
+		return emptyResult, err
+	}
+	return obj.(*v1.Pod), err
+}
diff --git a/staging/src/k8s.io/client-go/kubernetes/typed/core/v1/pod.go b/staging/src/k8s.io/client-go/kubernetes/typed/core/v1/pod.go
index 939d8be4beff1..072a559414d91 100644
--- a/staging/src/k8s.io/client-go/kubernetes/typed/core/v1/pod.go
+++ b/staging/src/k8s.io/client-go/kubernetes/typed/core/v1/pod.go
@@ -52,6 +52,7 @@ type PodInterface interface {
 	// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus().
 	ApplyStatus(ctx context.Context, pod *applyconfigurationscorev1.PodApplyConfiguration, opts metav1.ApplyOptions) (result *corev1.Pod, err error)
 	UpdateEphemeralContainers(ctx context.Context, podName string, pod *corev1.Pod, opts metav1.UpdateOptions) (*corev1.Pod, error)
+	UpdateResize(ctx context.Context, podName string, pod *corev1.Pod, opts metav1.UpdateOptions) (*corev1.Pod, error)
 
 	PodExpansion
 }
@@ -91,3 +92,19 @@ func (c *pods) UpdateEphemeralContainers(ctx context.Context, podName string, po
 		Into(result)
 	return
 }
+
+// UpdateResize takes the top resource name and the representation of a pod and updates it. Returns the server's representation of the pod, and an error, if there is any.
+func (c *pods) UpdateResize(ctx context.Context, podName string, pod *corev1.Pod, opts metav1.UpdateOptions) (result *corev1.Pod, err error) {
+	result = &corev1.Pod{}
+	err = c.GetClient().Put().
+		UseProtobufAsDefault().
+		Namespace(c.GetNamespace()).
+		Resource("pods").
+		Name(podName).
+		SubResource("resize").
+		VersionedParams(&opts, scheme.ParameterCodec).
+		Body(pod).
+		Do(ctx).
+		Into(result)
+	return
+}


Test patch:
diff --git a/pkg/api/pod/testing/make.go b/pkg/api/pod/testing/make.go
index 8667f71060a75..b73de5d1a11b3 100644
--- a/pkg/api/pod/testing/make.go
+++ b/pkg/api/pod/testing/make.go
@@ -27,6 +27,7 @@ import (
 // Tweak is a function that modifies a Pod.
 type Tweak func(*api.Pod)
 type TweakContainer func(*api.Container)
+type TweakPodStatus func(*api.PodStatus)
 
 // MakePod helps construct Pod objects (which pass API validation) more
 // legibly and tersely than a Go struct definition.  By default this produces
@@ -297,3 +298,34 @@ func SetContainerRestartPolicy(policy api.ContainerRestartPolicy) TweakContainer
 		cnr.RestartPolicy = &policy
 	}
 }
+
+func MakePodStatus(tweaks ...TweakPodStatus) api.PodStatus {
+	ps := api.PodStatus{}
+
+	for _, tweak := range tweaks {
+		tweak(&ps)
+	}
+
+	return ps
+}
+
+func SetContainerStatuses(containerStatuses ...api.ContainerStatus) TweakPodStatus {
+	return func(podstatus *api.PodStatus) {
+		podstatus.ContainerStatuses = containerStatuses
+	}
+}
+
+func MakeContainerStatus(name string, allocatedResources api.ResourceList) api.ContainerStatus {
+	cs := api.ContainerStatus{
+		Name:               name,
+		AllocatedResources: allocatedResources,
+	}
+
+	return cs
+}
+
+func SetResizeStatus(resizeStatus api.PodResizeStatus) TweakPodStatus {
+	return func(podstatus *api.PodStatus) {
+		podstatus.Resize = resizeStatus
+	}
+}
diff --git a/pkg/apis/core/validation/validation_test.go b/pkg/apis/core/validation/validation_test.go
index 6adb7d1892b3c..dde5004d37e4b 100644
--- a/pkg/apis/core/validation/validation_test.go
+++ b/pkg/apis/core/validation/validation_test.go
@@ -7795,14 +7795,7 @@ func TestValidateResizePolicy(t *testing.T) {
 	}
 }
 
-func getResourceLimits(cpu, memory string) core.ResourceList {
-	res := core.ResourceList{}
-	res[core.ResourceCPU] = resource.MustParse(cpu)
-	res[core.ResourceMemory] = resource.MustParse(memory)
-	return res
-}
-
-func getResources(cpu, memory, storage string) core.ResourceList {
+func getResources(cpu, memory, ephemeralStorage, persistentStorage string) core.ResourceList {
 	res := core.ResourceList{}
 	if cpu != "" {
 		res[core.ResourceCPU] = resource.MustParse(cpu)
@@ -7810,8 +7803,11 @@ func getResources(cpu, memory, storage string) core.ResourceList {
 	if memory != "" {
 		res[core.ResourceMemory] = resource.MustParse(memory)
 	}
-	if storage != "" {
-		res[core.ResourceEphemeralStorage] = resource.MustParse(storage)
+	if ephemeralStorage != "" {
+		res[core.ResourceEphemeralStorage] = resource.MustParse(ephemeralStorage)
+	}
+	if persistentStorage != "" {
+		res[core.ResourceStorage] = resource.MustParse(persistentStorage)
 	}
 	return res
 }
@@ -8945,7 +8941,7 @@ func TestValidateContainers(t *testing.T) {
 			Name:  "abc-123",
 			Image: "image",
 			Resources: core.ResourceRequirements{
-				Limits: getResourceLimits("-10", "0"),
+				Limits: getResources("-10", "0", "", ""),
 			},
 			ImagePullPolicy:          "IfNotPresent",
 			TerminationMessagePolicy: "File",
@@ -8958,7 +8954,7 @@ func TestValidateContainers(t *testing.T) {
 			Name:  "abc-123",
 			Image: "image",
 			Resources: core.ResourceRequirements{
-				Requests: getResourceLimits("-10", "0"),
+				Requests: getResources("-10", "0", "", ""),
 			},
 			ImagePullPolicy:          "IfNotPresent",
 			TerminationMessagePolicy: "File",
@@ -8971,7 +8967,7 @@ func TestValidateContainers(t *testing.T) {
 			Name:  "abc-123",
 			Image: "image",
 			Resources: core.ResourceRequirements{
-				Limits: getResourceLimits("0", "-10"),
+				Limits: getResources("0", "-10", "", ""),
 			},
 			ImagePullPolicy:          "IfNotPresent",
 			TerminationMessagePolicy: "File",
@@ -8984,8 +8980,8 @@ func TestValidateContainers(t *testing.T) {
 			Name:  "abc-123",
 			Image: "image",
 			Resources: core.ResourceRequirements{
-				Limits:   getResourceLimits("5", "3"),
-				Requests: getResourceLimits("6", "3"),
+				Limits:   getResources("5", "3", "", ""),
+				Requests: getResources("6", "3", "", ""),
 			},
 			ImagePullPolicy:          "IfNotPresent",
 			TerminationMessagePolicy: "File",
@@ -9016,8 +9012,8 @@ func TestValidateContainers(t *testing.T) {
 			Name:  "abc-123",
 			Image: "image",
 			Resources: core.ResourceRequirements{
-				Limits:   getResourceLimits("5", "3"),
-				Requests: getResourceLimits("6", "3"),
+				Limits:   getResources("5", "3", "", ""),
+				Requests: getResources("6", "3", "", ""),
 			},
 			ImagePullPolicy:          "IfNotPresent",
 			TerminationMessagePolicy: "File",
@@ -9030,8 +9026,8 @@ func TestValidateContainers(t *testing.T) {
 			Name:  "abc-123",
 			Image: "image",
 			Resources: core.ResourceRequirements{
-				Limits:   getResourceLimits("5", "3"),
-				Requests: getResourceLimits("5", "4"),
+				Limits:   getResources("5", "3", "", ""),
+				Requests: getResources("5", "4", "", ""),
 			},
 			ImagePullPolicy:          "IfNotPresent",
 			TerminationMessagePolicy: "File",
@@ -12317,10 +12313,10 @@ func TestValidatePodUpdate(t *testing.T) {
 	)
 
 	tests := []struct {
-		new  core.Pod
+		test string
 		old  core.Pod
+		new  core.Pod
 		err  string
-		test string
 	}{
 		{new: *podtest.MakePod(""), old: *podtest.MakePod(""), err: "", test: "nothing"}, {
 			new:  *podtest.MakePod("foo"),
@@ -12486,43 +12482,43 @@ func TestValidatePodUpdate(t *testing.T) {
 			new: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Limits: getResources("200m", "0", "1Gi"),
+						Limits: getResources("200m", "0", "1Gi", ""),
 					}))),
 			),
 			old: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Limits: getResources("100m", "0", "1Gi"),
+						Limits: getResources("100m", "0", "1Gi", ""),
 					}))),
 			),
-			err:  "",
+			err:  "spec: Forbidden: pod updates may not change fields",
 			test: "cpu limit change",
 		}, {
 			new: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Limits: getResourceLimits("100m", "100Mi"),
+						Limits: getResources("100m", "100Mi", "", ""),
 					}))),
 			),
 			old: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Limits: getResourceLimits("100m", "200Mi"),
+						Limits: getResources("100m", "200Mi", "", ""),
 					}))),
 			),
-			err:  "",
+			err:  "spec: Forbidden: pod updates may not change fields",
 			test: "memory limit change",
 		}, {
 			new: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Limits: getResources("100m", "100Mi", "1Gi"),
+						Limits: getResources("100m", "100Mi", "1Gi", ""),
 					}))),
 			),
 			old: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Limits: getResources("100m", "100Mi", "2Gi"),
+						Limits: getResources("100m", "100Mi", "2Gi", ""),
 					}))),
 			),
 			err:  "Forbidden: pod updates may not change fields other than",
@@ -12531,43 +12527,43 @@ func TestValidatePodUpdate(t *testing.T) {
 			new: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Requests: getResourceLimits("100m", "0"),
+						Requests: getResources("100m", "0", "", ""),
 					}))),
 			),
 			old: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Requests: getResourceLimits("200m", "0"),
+						Requests: getResources("200m", "0", "", ""),
 					}))),
 			),
-			err:  "",
+			err:  "spec: Forbidden: pod updates may not change fields",
 			test: "cpu request change",
 		}, {
 			new: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Requests: getResourceLimits("0", "200Mi"),
+						Requests: getResources("0", "200Mi", "", ""),
 					}))),
 			),
 			old: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Requests: getResourceLimits("0", "100Mi"),
+						Requests: getResources("0", "100Mi", "", ""),
 					}))),
 			),
-			err:  "",
+			err:  "spec: Forbidden: pod updates may not change fields",
 			test: "memory request change",
 		}, {
 			new: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Requests: getResources("100m", "0", "2Gi"),
+						Requests: getResources("100m", "0", "2Gi", ""),
 					}))),
 			),
 			old: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Requests: getResources("100m", "0", "1Gi"),
+						Requests: getResources("100m", "0", "1Gi", ""),
 					}))),
 			),
 			err:  "Forbidden: pod updates may not change fields other than",
@@ -12576,154 +12572,154 @@ func TestValidatePodUpdate(t *testing.T) {
 			new: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Limits:   getResources("200m", "400Mi", "1Gi"),
-						Requests: getResources("200m", "400Mi", "1Gi"),
+						Limits:   getResources("200m", "400Mi", "1Gi", ""),
+						Requests: getResources("200m", "400Mi", "1Gi", ""),
 					}))),
 			),
 			old: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Limits:   getResources("100m", "100Mi", "1Gi"),
-						Requests: getResources("100m", "100Mi", "1Gi"),
+						Limits:   getResources("100m", "100Mi", "1Gi", ""),
+						Requests: getResources("100m", "100Mi", "1Gi", ""),
 					}))),
 			),
-			err:  "",
+			err:  "spec: Forbidden: pod updates may not change fields",
 			test: "Pod QoS unchanged, guaranteed -> guaranteed",
 		}, {
 			new: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Limits:   getResources("200m", "200Mi", "2Gi"),
-						Requests: getResources("100m", "100Mi", "1Gi"),
+						Limits:   getResources("200m", "200Mi", "2Gi", ""),
+						Requests: getResources("100m", "100Mi", "1Gi", ""),
 					}))),
 			),
 			old: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Limits:   getResources("400m", "400Mi", "2Gi"),
-						Requests: getResources("200m", "200Mi", "1Gi"),
+						Limits:   getResources("400m", "400Mi", "2Gi", ""),
+						Requests: getResources("200m", "200Mi", "1Gi", ""),
 					}))),
 			),
-			err:  "",
+			err:  "spec: Forbidden: pod updates may not change fields",
 			test: "Pod QoS unchanged, burstable -> burstable",
 		}, {
 			new: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Limits:   getResourceLimits("200m", "200Mi"),
-						Requests: getResourceLimits("100m", "100Mi"),
+						Limits:   getResources("200m", "200Mi", "", ""),
+						Requests: getResources("100m", "100Mi", "", ""),
 					}))),
 			),
 			old: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Requests: getResourceLimits("100m", "100Mi"),
+						Requests: getResources("100m", "100Mi", "", ""),
 					}))),
 			),
-			err:  "",
+			err:  "spec: Forbidden: pod updates may not change fields",
 			test: "Pod QoS unchanged, burstable -> burstable, add limits",
 		}, {
 			new: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Requests: getResourceLimits("100m", "100Mi"),
+						Requests: getResources("100m", "100Mi", "", ""),
 					}))),
 			),
 			old: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Limits:   getResourceLimits("200m", "200Mi"),
-						Requests: getResourceLimits("100m", "100Mi"),
+						Limits:   getResources("200m", "200Mi", "", ""),
+						Requests: getResources("100m", "100Mi", "", ""),
 					}))),
 			),
-			err:  "",
+			err:  "spec: Forbidden: pod updates may not change fields",
 			test: "Pod QoS unchanged, burstable -> burstable, remove limits",
 		}, {
 			new: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Limits:   getResources("400m", "", "1Gi"),
-						Requests: getResources("300m", "", "1Gi"),
+						Limits:   getResources("400m", "", "1Gi", ""),
+						Requests: getResources("300m", "", "1Gi", ""),
 					}))),
 			),
 			old: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Limits: getResources("200m", "500Mi", "1Gi"),
+						Limits: getResources("200m", "500Mi", "1Gi", ""),
 					}))),
 			),
-			err:  "",
+			err:  "spec: Forbidden: pod updates may not change fields",
 			test: "Pod QoS unchanged, burstable -> burstable, add requests",
 		}, {
 			new: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Limits: getResources("400m", "500Mi", "2Gi"),
+						Limits: getResources("400m", "500Mi", "2Gi", ""),
 					}))),
 			),
 			old: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Limits:   getResources("200m", "300Mi", "2Gi"),
-						Requests: getResourceLimits("100m", "200Mi"),
+						Limits:   getResources("200m", "300Mi", "2Gi", ""),
+						Requests: getResources("100m", "200Mi", "", ""),
 					}))),
 			),
-			err:  "",
+			err:  "spec: Forbidden: pod updates may not change fields",
 			test: "Pod QoS unchanged, burstable -> burstable, remove requests",
 		}, {
 			new: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Limits:   getResourceLimits("200m", "200Mi"),
-						Requests: getResourceLimits("100m", "100Mi"),
+						Limits:   getResources("200m", "200Mi", "", ""),
+						Requests: getResources("100m", "100Mi", "", ""),
 					}))),
 			),
 			old: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Limits:   getResourceLimits("100m", "100Mi"),
-						Requests: getResourceLimits("100m", "100Mi"),
+						Limits:   getResources("100m", "100Mi", "", ""),
+						Requests: getResources("100m", "100Mi", "", ""),
 					}))),
 			),
-			err:  "Pod QoS is immutable",
+			err:  "spec: Forbidden: pod updates may not change fields",
 			test: "Pod QoS change, guaranteed -> burstable",
 		}, {
 			new: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Limits:   getResourceLimits("100m", "100Mi"),
-						Requests: getResourceLimits("100m", "100Mi"),
+						Limits:   getResources("100m", "100Mi", "", ""),
+						Requests: getResources("100m", "100Mi", "", ""),
 					}))),
 			),
 			old: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Requests: getResourceLimits("100m", "100Mi"),
+						Requests: getResources("100m", "100Mi", "", ""),
 					}))),
 			),
-			err:  "Pod QoS is immutable",
+			err:  "spec: Forbidden: pod updates may not change fields",
 			test: "Pod QoS change, burstable -> guaranteed",
 		}, {
 			new: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Limits:   getResourceLimits("200m", "200Mi"),
-						Requests: getResourceLimits("100m", "100Mi"),
+						Limits:   getResources("200m", "200Mi", "", ""),
+						Requests: getResources("100m", "100Mi", "", ""),
 					}))),
 			),
 			old:  *podtest.MakePod("pod"),
-			err:  "Pod QoS is immutable",
+			err:  "spec: Forbidden: pod updates may not change fields",
 			test: "Pod QoS change, besteffort -> burstable",
 		}, {
 			new: *podtest.MakePod("pod"),
 			old: *podtest.MakePod("pod",
 				podtest.SetContainers(podtest.MakeContainer("container",
 					podtest.SetContainerResources(core.ResourceRequirements{
-						Limits:   getResourceLimits("200m", "200Mi"),
-						Requests: getResourceLimits("100m", "100Mi"),
+						Limits:   getResources("200m", "200Mi", "", ""),
+						Requests: getResources("100m", "100Mi", "", ""),
 					}))),
 			),
-			err:  "Pod QoS is immutable",
+			err:  "spec: Forbidden: pod updates may not change fields",
 			test: "Pod QoS change, burstable -> besteffort",
 		}, {
 			new: *podtest.MakePod("pod",
@@ -18692,33 +18688,6 @@ func TestValidateResourceNames(t *testing.T) {
 	}
 }
 
-func getResourceList(cpu, memory string) core.ResourceList {
-	res := core.ResourceList{}
-	if cpu != "" {
-		res[core.ResourceCPU] = resource.MustParse(cpu)
-	}
-	if memory != "" {
-		res[core.ResourceMemory] = resource.MustParse(memory)
-	}
-	return res
-}
-
-func getStorageResourceList(storage string) core.ResourceList {
-	res := core.ResourceList{}
-	if storage != "" {
-		res[core.ResourceStorage] = resource.MustParse(storage)
-	}
-	return res
-}
-
-func getLocalStorageResourceList(ephemeralStorage string) core.ResourceList {
-	res := core.ResourceList{}
-	if ephemeralStorage != "" {
-		res[core.ResourceEphemeralStorage] = resource.MustParse(ephemeralStorage)
-	}
-	return res
-}
-
 func TestValidateLimitRangeForLocalStorage(t *testing.T) {
 	testCases := []struct {
 		name string
@@ -18728,16 +18697,16 @@ func TestValidateLimitRangeForLocalStorage(t *testing.T) {
 		spec: core.LimitRangeSpec{
 			Limits: []core.LimitRangeItem{{
 				Type:                 core.LimitTypePod,
-				Max:                  getLocalStorageResourceList("10000Mi"),
-				Min:                  getLocalStorageResourceList("100Mi"),
-				MaxLimitRequestRatio: getLocalStorageResourceList(""),
+				Max:                  getResources("", "", "10000Mi", ""),
+				Min:                  getResources("", "", "100Mi", ""),
+				MaxLimitRequestRatio: getResources("", "", "", ""),
 			}, {
 				Type:                 core.LimitTypeContainer,
-				Max:                  getLocalStorageResourceList("10000Mi"),
-				Min:                  getLocalStorageResourceList("100Mi"),
-				Default:              getLocalStorageResourceList("500Mi"),
-				DefaultRequest:       getLocalStorageResourceList("200Mi"),
-				MaxLimitRequestRatio: getLocalStorageResourceList(""),
+				Max:                  getResources("", "", "10000Mi", ""),
+				Min:                  getResources("", "", "100Mi", ""),
+				Default:              getResources("", "", "500Mi", ""),
+				DefaultRequest:       getResources("", "", "200Mi", ""),
+				MaxLimitRequestRatio: getResources("", "", "", ""),
 			}},
 		},
 	},
@@ -18760,20 +18729,20 @@ func TestValidateLimitRange(t *testing.T) {
 		spec: core.LimitRangeSpec{
 			Limits: []core.LimitRangeItem{{
 				Type:                 core.LimitTypePod,
-				Max:                  getResourceList("100m", "10000Mi"),
-				Min:                  getResourceList("5m", "100Mi"),
-				MaxLimitRequestRatio: getResourceList("10", ""),
+				Max:                  getResources("100m", "10000Mi", "", ""),
+				Min:                  getResources("5m", "100Mi", "", ""),
+				MaxLimitRequestRatio: getResources("10", "", "", ""),
 			}, {
 				Type:                 core.LimitTypeContainer,
-				Max:                  getResourceList("100m", "10000Mi"),
-				Min:                  getResourceList("5m", "100Mi"),
-				Default:              getResourceList("50m", "500Mi"),
-				DefaultRequest:       getResourceList("10m", "200Mi"),
-				MaxLimitRequestRatio: getResourceList("10", ""),
+				Max:                  getResources("100m", "10000Mi", "", ""),
+				Min:                  getResources("5m", "100Mi", "", ""),
+				Default:              getResources("50m", "500Mi", "", ""),
+				DefaultRequest:       getResources("10m", "200Mi", "", ""),
+				MaxLimitRequestRatio: getResources("10", "", "", ""),
 			}, {
 				Type: core.LimitTypePersistentVolumeClaim,
-				Max:  getStorageResourceList("10Gi"),
-				Min:  getStorageResourceList("5Gi"),
+				Max:  getResources("", "", "", "10Gi"),
+				Min:  getResources("", "", "", "5Gi"),
 			}},
 		},
 	}, {
@@ -18781,7 +18750,7 @@ func TestValidateLimitRange(t *testing.T) {
 		spec: core.LimitRangeSpec{
 			Limits: []core.LimitRangeItem{{
 				Type: core.LimitTypePersistentVolumeClaim,
-				Min:  getStorageResourceList("5Gi"),
+				Min:  getResources("", "", "", "5Gi"),
 			}},
 		},
 	}, {
@@ -18789,7 +18758,7 @@ func TestValidateLimitRange(t *testing.T) {
 		spec: core.LimitRangeSpec{
 			Limits: []core.LimitRangeItem{{
 				Type: core.LimitTypePersistentVolumeClaim,
-				Max:  getStorageResourceList("10Gi"),
+				Max:  getResources("", "", "", "10Gi"),
 			}},
 		},
 	}, {
@@ -18797,11 +18766,11 @@ func TestValidateLimitRange(t *testing.T) {
 		spec: core.LimitRangeSpec{
 			Limits: []core.LimitRangeItem{{
 				Type:                 core.LimitTypeContainer,
-				Max:                  getResourceList("100m", "10000T"),
-				Min:                  getResourceList("5m", "100Mi"),
-				Default:              getResourceList("50m", "500Mi"),
-				DefaultRequest:       getResourceList("10m", "200Mi"),
-				MaxLimitRequestRatio: getResourceList("10", ""),
+				Max:                  getResources("100m", "10000T", "", ""),
+				Min:                  getResources("5m", "100Mi", "", ""),
+				Default:              getResources("50m", "500Mi", "", ""),
+				DefaultRequest:       getResources("10m", "200Mi", "", ""),
+				MaxLimitRequestRatio: getResources("10", "", "", ""),
 			}},
 		},
 	}, {
@@ -18809,11 +18778,11 @@ func TestValidateLimitRange(t *testing.T) {
 		spec: core.LimitRangeSpec{
 			Limits: []core.LimitRangeItem{{
 				Type:                 "thirdparty.com/foo",
-				Max:                  getResourceList("100m", "10000T"),
-				Min:                  getResourceList("5m", "100Mi"),
-				Default:              getResourceList("50m", "500Mi"),
-				DefaultRequest:       getResourceList("10m", "200Mi"),
-				MaxLimitRequestRatio: getResourceList("10", ""),
+				Max:                  getResources("100m", "10000T", "", ""),
+				Min:                  getResources("5m", "100Mi", "", ""),
+				Default:              getResources("50m", "500Mi", "", ""),
+				DefaultRequest:       getResources("10m", "200Mi", "", ""),
+				MaxLimitRequestRatio: getResources("10", "", "", ""),
 			}},
 		},
 	}, {
@@ -18821,11 +18790,11 @@ func TestValidateLimitRange(t *testing.T) {
 		spec: core.LimitRangeSpec{
 			Limits: []core.LimitRangeItem{{
 				Type:                 "thirdparty.com/foo",
-				Max:                  getStorageResourceList("10000T"),
-				Min:                  getStorageResourceList("100Mi"),
-				Default:              getStorageResourceList("500Mi"),
-				DefaultRequest:       getStorageResourceList("200Mi"),
-				MaxLimitRequestRatio: getStorageResourceList(""),
+				Max:                  getResources("", "", "", "10000T"),
+				Min:                  getResources("", "", "", "100Mi"),
+				Default:              getResources("", "", "", "500Mi"),
+				DefaultRequest:       getResources("", "", "", "200Mi"),
+				MaxLimitRequestRatio: getResources("", "", "", ""),
 			}},
 		},
 	},
@@ -18862,11 +18831,11 @@ func TestValidateLimitRange(t *testing.T) {
 			core.LimitRange{ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: "foo"}, Spec: core.LimitRangeSpec{
 				Limits: []core.LimitRangeItem{{
 					Type: core.LimitTypePod,
-					Max:  getResourceList("100m", "10000m"),
-					Min:  getResourceList("0m", "100m"),
+					Max:  getResources("100m", "10000m", "", ""),
+					Min:  getResources("0m", "100m", "", ""),
 				}, {
 					Type: core.LimitTypePod,
-					Min:  getResourceList("0m", "100m"),
+					Min:  getResources("0m", "100m", "", ""),
 				}},
 			}},
 			"",
@@ -18875,9 +18844,9 @@ func TestValidateLimitRange(t *testing.T) {
 			core.LimitRange{ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: "foo"}, Spec: core.LimitRangeSpec{
 				Limits: []core.LimitRangeItem{{
 					Type:    core.LimitTypePod,
-					Max:     getResourceList("100m", "10000m"),
-					Min:     getResourceList("0m", "100m"),
-					Default: getResourceList("10m", "100m"),
+					Max:     getResources("100m", "10000m", "", ""),
+					Min:     getResources("0m", "100m", "", ""),
+					Default: getResources("10m", "100m", "", ""),
 				}},
 			}},
 			"may not be specified when `type` is 'Pod'",
@@ -18886,9 +18855,9 @@ func TestValidateLimitRange(t *testing.T) {
 			core.LimitRange{ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: "foo"}, Spec: core.LimitRangeSpec{
 				Limits: []core.LimitRangeItem{{
 					Type:           core.LimitTypePod,
-					Max:            getResourceList("100m", "10000m"),
-					Min:            getResourceList("0m", "100m"),
-					DefaultRequest: getResourceList("10m", "100m"),
+					Max:            getResources("100m", "10000m", "", ""),
+					Min:            getResources("0m", "100m", "", ""),
+					DefaultRequest: getResources("10m", "100m", "", ""),
 				}},
 			}},
 			"may not be specified when `type` is 'Pod'",
@@ -18897,8 +18866,8 @@ func TestValidateLimitRange(t *testing.T) {
 			core.LimitRange{ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: "foo"}, Spec: core.LimitRangeSpec{
 				Limits: []core.LimitRangeItem{{
 					Type: core.LimitTypePod,
-					Max:  getResourceList("10m", ""),
-					Min:  getResourceList("100m", ""),
+					Max:  getResources("10m", "", "", ""),
+					Min:  getResources("100m", "", "", ""),
 				}},
 			}},
 			"min value 100m is greater than max value 10m",
@@ -18907,9 +18876,9 @@ func TestValidateLimitRange(t *testing.T) {
 			core.LimitRange{ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: "foo"}, Spec: core.LimitRangeSpec{
 				Limits: []core.LimitRangeItem{{
 					Type:    core.LimitTypeContainer,
-					Max:     getResourceList("1", ""),
-					Min:     getResourceList("100m", ""),
-					Default: getResourceList("2000m", ""),
+					Max:     getResources("1", "", "", ""),
+					Min:     getResources("100m", "", "", ""),
+					Default: getResources("2000m", "", "", ""),
 				}},
 			}},
 			"default value 2 is greater than max value 1",
@@ -18918,9 +18887,9 @@ func TestValidateLimitRange(t *testing.T) {
 			core.LimitRange{ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: "foo"}, Spec: core.LimitRangeSpec{
 				Limits: []core.LimitRangeItem{{
 					Type:           core.LimitTypeContainer,
-					Max:            getResourceList("1", ""),
-					Min:            getResourceList("100m", ""),
-					DefaultRequest: getResourceList("2000m", ""),
+					Max:            getResources("1", "", "", ""),
+					Min:            getResources("100m", "", "", ""),
+					DefaultRequest: getResources("2000m", "", "", ""),
 				}},
 			}},
 			"default request value 2 is greater than max value 1",
@@ -18929,10 +18898,10 @@ func TestValidateLimitRange(t *testing.T) {
 			core.LimitRange{ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: "foo"}, Spec: core.LimitRangeSpec{
 				Limits: []core.LimitRangeItem{{
 					Type:           core.LimitTypeContainer,
-					Max:            getResourceList("2", ""),
-					Min:            getResourceList("100m", ""),
-					Default:        getResourceList("500m", ""),
-					DefaultRequest: getResourceList("800m", ""),
+					Max:            getResources("2", "", "", ""),
+					Min:            getResources("100m", "", "", ""),
+					Default:        getResources("500m", "", "", ""),
+					DefaultRequest: getResources("800m", "", "", ""),
 				}},
 			}},
 			"default request value 800m is greater than default limit value 500m",
@@ -18941,7 +18910,7 @@ func TestValidateLimitRange(t *testing.T) {
 			core.LimitRange{ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: "foo"}, Spec: core.LimitRangeSpec{
 				Limits: []core.LimitRangeItem{{
 					Type:                 core.LimitTypePod,
-					MaxLimitRequestRatio: getResourceList("800m", ""),
+					MaxLimitRequestRatio: getResources("800m", "", "", ""),
 				}},
 			}},
 			"ratio 800m is less than 1",
@@ -18950,9 +18919,9 @@ func TestValidateLimitRange(t *testing.T) {
 			core.LimitRange{ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: "foo"}, Spec: core.LimitRangeSpec{
 				Limits: []core.LimitRangeItem{{
 					Type:                 core.LimitTypeContainer,
-					Max:                  getResourceList("", "2Gi"),
-					Min:                  getResourceList("", "512Mi"),
-					MaxLimitRequestRatio: getResourceList("", "10"),
+					Max:                  getResources("", "2Gi", "", ""),
+					Min:                  getResources("", "512Mi", "", ""),
+					MaxLimitRequestRatio: getResources("", "10", "", ""),
 				}},
 			}},
 			"ratio 10 is greater than max/min = 4.000000",
@@ -18961,11 +18930,11 @@ func TestValidateLimitRange(t *testing.T) {
 			core.LimitRange{ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: "foo"}, Spec: core.LimitRangeSpec{
 				Limits: []core.LimitRangeItem{{
 					Type:                 "foo",
-					Max:                  getStorageResourceList("10000T"),
-					Min:                  getStorageResourceList("100Mi"),
-					Default:              getStorageResourceList("500Mi"),
-					DefaultRequest:       getStorageResourceList("200Mi"),
-					MaxLimitRequestRatio: getStorageResourceList(""),
+					Max:                  getResources("", "", "", "10000T"),
+					Min:                  getResources("", "", "", "100Mi"),
+					Default:              getResources("", "", "", "500Mi"),
+					DefaultRequest:       getResources("", "", "", "200Mi"),
+					MaxLimitRequestRatio: getResources("", "", "", ""),
 				}},
 			}},
 			"must be a standard limit type or fully qualified",
@@ -18982,8 +18951,8 @@ func TestValidateLimitRange(t *testing.T) {
 			core.LimitRange{ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: "foo"}, Spec: core.LimitRangeSpec{
 				Limits: []core.LimitRangeItem{{
 					Type: core.LimitTypePersistentVolumeClaim,
-					Min:  getStorageResourceList("10Gi"),
-					Max:  getStorageResourceList("1Gi"),
+					Min:  getResources("", "", "", "10Gi"),
+					Max:  getResources("", "", "", "1Gi"),
 				}},
 			}},
 			"min value 10Gi is greater than max value 1Gi",
@@ -25104,3 +25073,152 @@ func TestValidateSELinuxChangePolicy(t *testing.T) {
 		})
 	}
 }
+
+func TestValidatePodResize(t *testing.T) {
+	mkPod := func(req, lim core.ResourceList, tweaks ...podtest.TweakContainer) *core.Pod {
+		return podtest.MakePod("pod",
+			podtest.SetContainers(
+				podtest.MakeContainer(
+					"container",
+					append(tweaks,
+						podtest.SetContainerResources(
+							core.ResourceRequirements{
+								Requests: req,
+								Limits:   lim,
+							},
+						),
+					)...,
+				),
+			),
+		)
+	}
+
+	tests := []struct {
+		test string
+		old  *core.Pod
+		new  *core.Pod
+		err  string
+	}{
+		{
+			test: "cpu limit change",
+			old:  mkPod(core.ResourceList{}, getResources("100m", "0", "1Gi", "")),
+			new:  mkPod(core.ResourceList{}, getResources("200m", "0", "1Gi", "")),
+			err:  "",
+		}, {
+			test: "memory limit change",
+			old:  mkPod(core.ResourceList{}, getResources("100m", "200Mi", "", "")),
+			new:  mkPod(core.ResourceList{}, getResources("100m", "100Mi", "", "")),
+			err:  "",
+		}, {
+			test: "storage limit change",
+			old:  mkPod(core.ResourceList{}, getResources("100m", "100Mi", "2Gi", "")),
+			new:  mkPod(core.ResourceList{}, getResources("100m", "100Mi", "1Gi", "")),
+			err:  "spec: Forbidden: only cpu and memory resources are mutable",
+		}, {
+			test: "cpu request change",
+			old:  mkPod(getResources("200m", "0", "", ""), core.ResourceList{}),
+			new:  mkPod(getResources("100m", "0", "", ""), core.ResourceList{}),
+			err:  "",
+		}, {
+			test: "memory request change",
+			old:  mkPod(getResources("0", "100Mi", "", ""), core.ResourceList{}),
+			new:  mkPod(getResources("0", "200Mi", "", ""), core.ResourceList{}),
+			err:  "",
+		}, {
+			test: "storage request change",
+			old:  mkPod(getResources("100m", "0", "1Gi", ""), core.ResourceList{}),
+			new:  mkPod(getResources("100m", "0", "2Gi", ""), core.ResourceList{}),
+			err:  "spec: Forbidden: only cpu and memory resources are mutable",
+		}, {
+			test: "Pod QoS unchanged, guaranteed -> guaranteed",
+			old:  mkPod(getResources("100m", "100Mi", "1Gi", ""), getResources("100m", "100Mi", "1Gi", "")),
+			new:  mkPod(getResources("200m", "400Mi", "1Gi", ""), getResources("200m", "400Mi", "1Gi", "")),
+			err:  "",
+		}, {
+			test: "Pod QoS unchanged, burstable -> burstable",
+			old:  mkPod(getResources("200m", "200Mi", "1Gi", ""), getResources("400m", "400Mi", "2Gi", "")),
+			new:  mkPod(getResources("100m", "100Mi", "1Gi", ""), getResources("200m", "200Mi", "2Gi", "")),
+			err:  "",
+		}, {
+			test: "Pod QoS unchanged, burstable -> burstable, add limits",
+			old:  mkPod(getResources("100m", "100Mi", "", ""), core.ResourceList{}),
+			new:  mkPod(getResources("100m", "100Mi", "", ""), getResources("200m", "200Mi", "", "")),
+			err:  "",
+		}, {
+			test: "Pod QoS unchanged, burstable -> burstable, remove limits",
+			old:  mkPod(getResources("100m", "100Mi", "", ""), getResources("200m", "200Mi", "", "")),
+			new:  mkPod(getResources("100m", "100Mi", "", ""), core.ResourceList{}),
+			err:  "",
+		}, {
+			test: "Pod QoS unchanged, burstable -> burstable, add requests",
+			old:  mkPod(core.ResourceList{}, getResources("200m", "500Mi", "1Gi", "")),
+			new:  mkPod(getResources("300m", "", "", ""), getResources("400m", "", "1Gi", "")),
+			err:  "",
+		}, {
+			test: "Pod QoS unchanged, burstable -> burstable, remove requests",
+			old:  mkPod(getResources("100m", "200Mi", "", ""), getResources("200m", "300Mi", "2Gi", "")),
+			new:  mkPod(core.ResourceList{}, getResources("400m", "500Mi", "2Gi", "")),
+			err:  "",
+		}, {
+			test: "Pod QoS change, guaranteed -> burstable",
+			old:  mkPod(getResources("100m", "100Mi", "", ""), getResources("100m", "100Mi", "", "")),
+			new:  mkPod(getResources("100m", "100Mi", "", ""), getResources("200m", "200Mi", "", "")),
+			err:  "Pod QOS Class may not change as a result of resizing",
+		}, {
+			test: "Pod QoS change, burstable -> guaranteed",
+			old:  mkPod(getResources("100m", "100Mi", "", ""), core.ResourceList{}),
+			new:  mkPod(getResources("100m", "100Mi", "", ""), getResources("100m", "100Mi", "", "")),
+			err:  "Pod QOS Class may not change as a result of resizing",
+		}, {
+			test: "Pod QoS change, besteffort -> burstable",
+			old:  mkPod(core.ResourceList{}, core.ResourceList{}),
+			new:  mkPod(getResources("100m", "100Mi", "", ""), getResources("200m", "200Mi", "", "")),
+			err:  "Pod QOS Class may not change as a result of resizing",
+		}, {
+			test: "Pod QoS change, burstable -> besteffort",
+			old:  mkPod(getResources("100m", "100Mi", "", ""), getResources("200m", "200Mi", "", "")),
+			new:  mkPod(core.ResourceList{}, core.ResourceList{}),
+			err:  "Pod QOS Class may not change as a result of resizing",
+		},
+	}
+
+	for _, test := range tests {
+		test.new.ObjectMeta.ResourceVersion = "1"
+		test.old.ObjectMeta.ResourceVersion = "1"
+
+		// set required fields if old and new match and have no opinion on the value
+		if test.new.Name == "" && test.old.Name == "" {
+			test.new.Name = "name"
+			test.old.Name = "name"
+		}
+		if test.new.Namespace == "" && test.old.Namespace == "" {
+			test.new.Namespace = "namespace"
+			test.old.Namespace = "namespace"
+		}
+		if test.new.Spec.Containers == nil && test.old.Spec.Containers == nil {
+			test.new.Spec.Containers = []core.Container{{Name: "autoadded", Image: "image", TerminationMessagePolicy: "File", ImagePullPolicy: "Always"}}
+			test.old.Spec.Containers = []core.Container{{Name: "autoadded", Image: "image", TerminationMessagePolicy: "File", ImagePullPolicy: "Always"}}
+		}
+		if len(test.new.Spec.DNSPolicy) == 0 && len(test.old.Spec.DNSPolicy) == 0 {
+			test.new.Spec.DNSPolicy = core.DNSClusterFirst
+			test.old.Spec.DNSPolicy = core.DNSClusterFirst
+		}
+		if len(test.new.Spec.RestartPolicy) == 0 && len(test.old.Spec.RestartPolicy) == 0 {
+			test.new.Spec.RestartPolicy = "Always"
+			test.old.Spec.RestartPolicy = "Always"
+		}
+
+		errs := ValidatePodResize(test.new, test.old, PodValidationOptions{})
+		if test.err == "" {
+			if len(errs) != 0 {
+				t.Errorf("unexpected invalid: %s (%+v)\nA: %+v\nB: %+v", test.test, errs, test.new, test.old)
+			}
+		} else {
+			if len(errs) == 0 {
+				t.Errorf("unexpected valid: %s\nA: %+v\nB: %+v", test.test, test.new, test.old)
+			} else if actualErr := errs.ToAggregate().Error(); !strings.Contains(actualErr, test.err) {
+				t.Errorf("unexpected error message: %s\nExpected error: %s\nActual error: %s", test.test, test.err, actualErr)
+			}
+		}
+	}
+}
diff --git a/pkg/quota/v1/evaluator/core/persistent_volume_claims_test.go b/pkg/quota/v1/evaluator/core/persistent_volume_claims_test.go
index 510028674bf99..697f679e6ab7d 100644
--- a/pkg/quota/v1/evaluator/core/persistent_volume_claims_test.go
+++ b/pkg/quota/v1/evaluator/core/persistent_volume_claims_test.go
@@ -24,6 +24,7 @@ import (
 	"k8s.io/apimachinery/pkg/api/resource"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime/schema"
+	"k8s.io/apiserver/pkg/admission"
 	quota "k8s.io/apiserver/pkg/quota/v1"
 	"k8s.io/apiserver/pkg/quota/v1/generic"
 	utilfeature "k8s.io/apiserver/pkg/util/feature"
@@ -223,3 +224,52 @@ func TestPersistentVolumeClaimEvaluatorMatchingResources(t *testing.T) {
 		}
 	}
 }
+
+func TestPersistentVolumeClaimEvaluatorHandles(t *testing.T) {
+	evaluator := NewPersistentVolumeClaimEvaluator(nil)
+	testCases := []struct {
+		name  string
+		attrs admission.Attributes
+		want  bool
+	}{
+		{
+			name:  "create",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "", admission.Create, nil, false, nil),
+			want:  true,
+		},
+		{
+			name:  "update",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "", admission.Update, nil, false, nil),
+			want:  true,
+		},
+		{
+			name:  "delete",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "", admission.Delete, nil, false, nil),
+			want:  false,
+		},
+		{
+			name:  "connect",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "", admission.Connect, nil, false, nil),
+			want:  false,
+		},
+		{
+			name:  "create-subresource",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "subresource", admission.Create, nil, false, nil),
+			want:  false,
+		},
+		{
+			name:  "update-subresource",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "subresource", admission.Update, nil, false, nil),
+			want:  false,
+		},
+	}
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			actual := evaluator.Handles(tc.attrs)
+
+			if tc.want != actual {
+				t.Errorf("%s expected:\n%v\n, actual:\n%v", tc.name, tc.want, actual)
+			}
+		})
+	}
+}
diff --git a/pkg/quota/v1/evaluator/core/pods_test.go b/pkg/quota/v1/evaluator/core/pods_test.go
index f92e7def0f078..11de6569212b0 100644
--- a/pkg/quota/v1/evaluator/core/pods_test.go
+++ b/pkg/quota/v1/evaluator/core/pods_test.go
@@ -27,6 +27,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/runtime/schema"
+	"k8s.io/apiserver/pkg/admission"
 	quota "k8s.io/apiserver/pkg/quota/v1"
 	"k8s.io/apiserver/pkg/quota/v1/generic"
 	utilfeature "k8s.io/apiserver/pkg/util/feature"
@@ -1195,3 +1196,58 @@ func makePod(name, pcName string, resList api.ResourceList, phase api.PodPhase)
 		},
 	}
 }
+
+func TestPodEvaluatorHandles(t *testing.T) {
+	fakeClock := testingclock.NewFakeClock(time.Now())
+	evaluator := NewPodEvaluator(nil, fakeClock)
+	testCases := []struct {
+		name  string
+		attrs admission.Attributes
+		want  bool
+	}{
+		{
+			name:  "create",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "", admission.Create, nil, false, nil),
+			want:  true,
+		},
+		{
+			name:  "update",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "", admission.Update, nil, false, nil),
+			want:  false,
+		},
+		{
+			name:  "delete",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "", admission.Delete, nil, false, nil),
+			want:  false,
+		},
+		{
+			name:  "connect",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "", admission.Connect, nil, false, nil),
+			want:  false,
+		},
+		{
+			name:  "create-subresource",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "subresource", admission.Create, nil, false, nil),
+			want:  false,
+		},
+		{
+			name:  "update-subresource",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "subresource", admission.Update, nil, false, nil),
+			want:  false,
+		},
+		{
+			name:  "update-resize",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "resize", admission.Update, nil, false, nil),
+			want:  true,
+		},
+	}
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			actual := evaluator.Handles(tc.attrs)
+
+			if tc.want != actual {
+				t.Errorf("%s expected:\n%v\n, actual:\n%v", tc.name, tc.want, actual)
+			}
+		})
+	}
+}
diff --git a/pkg/quota/v1/evaluator/core/resource_claims_test.go b/pkg/quota/v1/evaluator/core/resource_claims_test.go
index 244dbb2c28e49..33bbbbbb314d1 100644
--- a/pkg/quota/v1/evaluator/core/resource_claims_test.go
+++ b/pkg/quota/v1/evaluator/core/resource_claims_test.go
@@ -24,6 +24,8 @@ import (
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/resource"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	"k8s.io/apiserver/pkg/admission"
 	api "k8s.io/kubernetes/pkg/apis/resource"
 	"k8s.io/utils/ptr"
 )
@@ -171,3 +173,52 @@ func TestResourceClaimEvaluatorMatchingResources(t *testing.T) {
 		})
 	}
 }
+
+func TestResourceClaimEvaluatorHandles(t *testing.T) {
+	evaluator := NewResourceClaimEvaluator(nil)
+	testCases := []struct {
+		name  string
+		attrs admission.Attributes
+		want  bool
+	}{
+		{
+			name:  "create",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "", admission.Create, nil, false, nil),
+			want:  true,
+		},
+		{
+			name:  "update",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "", admission.Update, nil, false, nil),
+			want:  true,
+		},
+		{
+			name:  "delete",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "", admission.Delete, nil, false, nil),
+			want:  false,
+		},
+		{
+			name:  "connect",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "", admission.Connect, nil, false, nil),
+			want:  false,
+		},
+		{
+			name:  "create-subresource",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "subresource", admission.Create, nil, false, nil),
+			want:  false,
+		},
+		{
+			name:  "update-subresource",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "subresource", admission.Update, nil, false, nil),
+			want:  false,
+		},
+	}
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			actual := evaluator.Handles(tc.attrs)
+
+			if tc.want != actual {
+				t.Errorf("%s expected:\n%v\n, actual:\n%v", tc.name, tc.want, actual)
+			}
+		})
+	}
+}
diff --git a/pkg/quota/v1/evaluator/core/services_test.go b/pkg/quota/v1/evaluator/core/services_test.go
index ddc9997ffd3d1..c36fd2cf9ba4f 100644
--- a/pkg/quota/v1/evaluator/core/services_test.go
+++ b/pkg/quota/v1/evaluator/core/services_test.go
@@ -22,6 +22,7 @@ import (
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/resource"
 	"k8s.io/apimachinery/pkg/runtime/schema"
+	"k8s.io/apiserver/pkg/admission"
 	quota "k8s.io/apiserver/pkg/quota/v1"
 	"k8s.io/apiserver/pkg/quota/v1/generic"
 	api "k8s.io/kubernetes/pkg/apis/core"
@@ -330,3 +331,52 @@ func TestServiceConstraintsFunc(t *testing.T) {
 		}
 	}
 }
+
+func TestServiceEvaluatorHandles(t *testing.T) {
+	evaluator := NewServiceEvaluator(nil)
+	testCases := []struct {
+		name  string
+		attrs admission.Attributes
+		want  bool
+	}{
+		{
+			name:  "create",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "", admission.Create, nil, false, nil),
+			want:  true,
+		},
+		{
+			name:  "update",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "", admission.Update, nil, false, nil),
+			want:  true,
+		},
+		{
+			name:  "delete",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "", admission.Delete, nil, false, nil),
+			want:  false,
+		},
+		{
+			name:  "connect",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "", admission.Connect, nil, false, nil),
+			want:  false,
+		},
+		{
+			name:  "create-subresource",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "subresource", admission.Create, nil, false, nil),
+			want:  false,
+		},
+		{
+			name:  "update-subresource",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "subresource", admission.Update, nil, false, nil),
+			want:  false,
+		},
+	}
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			actual := evaluator.Handles(tc.attrs)
+
+			if tc.want != actual {
+				t.Errorf("%s expected:\n%v\n, actual:\n%v", tc.name, tc.want, actual)
+			}
+		})
+	}
+}
diff --git a/pkg/registry/core/pod/strategy_test.go b/pkg/registry/core/pod/strategy_test.go
index 9b5e290d2ad97..068ff294cc39c 100644
--- a/pkg/registry/core/pod/strategy_test.go
+++ b/pkg/registry/core/pod/strategy_test.go
@@ -2451,3 +2451,466 @@ var _ warning.Recorder = &warningRecorder{}
 func (w *warningRecorder) AddWarning(_, text string) {
 	w.warnings = append(w.warnings, text)
 }
+
+func TestPodResizePrepareForUpdate(t *testing.T) {
+	tests := []struct {
+		name     string
+		oldPod   *api.Pod
+		newPod   *api.Pod
+		expected *api.Pod
+	}{
+		{
+			name: "no resize",
+			oldPod: podtest.MakePod("test-pod",
+				podtest.SetResourceVersion("1"),
+				podtest.SetContainers(podtest.MakeContainer("container1",
+					podtest.SetContainerResources(api.ResourceRequirements{
+						Requests: api.ResourceList{
+							api.ResourceCPU:    resource.MustParse("100m"),
+							api.ResourceMemory: resource.MustParse("1Gi"),
+						},
+					}),
+				)),
+				podtest.SetStatus(podtest.MakePodStatus(
+					podtest.SetContainerStatuses(podtest.MakeContainerStatus("container1",
+						api.ResourceList{
+							api.ResourceCPU:    resource.MustParse("100m"),
+							api.ResourceMemory: resource.MustParse("1Gi"),
+						}),
+					),
+				)),
+			),
+			newPod: podtest.MakePod("test-pod",
+				podtest.SetResourceVersion("1"),
+				podtest.SetContainers(podtest.MakeContainer("container1",
+					podtest.SetContainerResources(api.ResourceRequirements{
+						Requests: api.ResourceList{
+							api.ResourceCPU:    resource.MustParse("100m"),
+							api.ResourceMemory: resource.MustParse("1Gi"),
+						},
+					}),
+				)),
+				podtest.SetStatus(podtest.MakePodStatus(
+					podtest.SetContainerStatuses(podtest.MakeContainerStatus("container1",
+						api.ResourceList{
+							api.ResourceCPU:    resource.MustParse("100m"),
+							api.ResourceMemory: resource.MustParse("1Gi"),
+						}),
+					),
+				)),
+			),
+			expected: podtest.MakePod("test-pod",
+				podtest.SetResourceVersion("1"),
+				podtest.SetContainers(podtest.MakeContainer("container1",
+					podtest.SetContainerResources(api.ResourceRequirements{
+						Requests: api.ResourceList{
+							api.ResourceCPU:    resource.MustParse("100m"),
+							api.ResourceMemory: resource.MustParse("1Gi"),
+						},
+					}),
+				)),
+				podtest.SetStatus(podtest.MakePodStatus(
+					podtest.SetContainerStatuses(podtest.MakeContainerStatus("container1",
+						api.ResourceList{
+							api.ResourceCPU:    resource.MustParse("100m"),
+							api.ResourceMemory: resource.MustParse("1Gi"),
+						}),
+					),
+				)),
+			),
+		},
+		{
+			name: "update resizepolicy",
+			oldPod: podtest.MakePod("test-pod",
+				podtest.SetResourceVersion("1"),
+				podtest.SetContainers(podtest.MakeContainer("container1",
+					podtest.SetContainerResources(api.ResourceRequirements{
+						Requests: api.ResourceList{
+							api.ResourceCPU:    resource.MustParse("100m"),
+							api.ResourceMemory: resource.MustParse("1Gi"),
+						},
+					}),
+				)),
+				podtest.SetStatus(podtest.MakePodStatus(
+					podtest.SetContainerStatuses(podtest.MakeContainerStatus("container1",
+						api.ResourceList{
+							api.ResourceCPU:    resource.MustParse("100m"),
+							api.ResourceMemory: resource.MustParse("1Gi"),
+						})),
+				)),
+			),
+			newPod: podtest.MakePod("test-pod",
+				podtest.SetResourceVersion("2"),
+				podtest.SetContainers(podtest.MakeContainer("container1",
+					podtest.SetContainerResources(api.ResourceRequirements{
+						Requests: api.ResourceList{
+							api.ResourceCPU:    resource.MustParse("100m"),
+							api.ResourceMemory: resource.MustParse("1Gi"),
+						},
+					}),
+					podtest.SetContainerResizePolicy(
+						api.ContainerResizePolicy{ResourceName: "cpu", RestartPolicy: "NotRequired"},
+						api.ContainerResizePolicy{ResourceName: "memory", RestartPolicy: "RestartContainer"},
+					),
+				)),
+				podtest.SetStatus(podtest.MakePodStatus(
+					podtest.SetContainerStatuses(podtest.MakeContainerStatus("container1",
+						api.ResourceList{
+							api.ResourceCPU:    resource.MustParse("100m"),
+							api.ResourceMemory: resource.MustParse("1Gi"),
+						})),
+				)),
+			),
+			expected: podtest.MakePod("test-pod",
+				podtest.SetResourceVersion("2"),
+				podtest.SetContainers(podtest.MakeContainer("container1",
+					podtest.SetContainerResources(api.ResourceRequirements{
+						Requests: api.ResourceList{
+							api.ResourceCPU:    resource.MustParse("100m"),
+							api.ResourceMemory: resource.MustParse("1Gi"),
+						},
+					}),
+					podtest.SetContainerResizePolicy(
+						api.ContainerResizePolicy{ResourceName: "cpu", RestartPolicy: "NotRequired"},
+						api.ContainerResizePolicy{ResourceName: "memory", RestartPolicy: "RestartContainer"},
+					),
+				)),
+				podtest.SetStatus(podtest.MakePodStatus(
+					podtest.SetContainerStatuses(podtest.MakeContainerStatus("container1",
+						api.ResourceList{
+							api.ResourceCPU:    resource.MustParse("100m"),
+							api.ResourceMemory: resource.MustParse("1Gi"),
+						})),
+				)),
+			),
+		},
+		{
+			name: "add new container",
+			oldPod: podtest.MakePod("test-pod",
+				podtest.SetResourceVersion("1"),
+				podtest.SetContainers(podtest.MakeContainer("container1",
+					podtest.SetContainerResources(api.ResourceRequirements{
+						Requests: api.ResourceList{
+							api.ResourceCPU:    resource.MustParse("100m"),
+							api.ResourceMemory: resource.MustParse("1Gi"),
+						},
+					}),
+				)),
+				podtest.SetStatus(podtest.MakePodStatus(
+					podtest.SetContainerStatuses(podtest.MakeContainerStatus("container1",
+						api.ResourceList{
+							api.ResourceCPU:    resource.MustParse("100m"),
+							api.ResourceMemory: resource.MustParse("1Gi"),
+						})),
+				)),
+			),
+			newPod: podtest.MakePod("test-pod",
+				podtest.SetResourceVersion("2"),
+				podtest.SetContainers(
+					podtest.MakeContainer("container1",
+						podtest.SetContainerResources(api.ResourceRequirements{
+							Requests: api.ResourceList{
+								api.ResourceCPU:    resource.MustParse("100m"),
+								api.ResourceMemory: resource.MustParse("1Gi"),
+							},
+						}),
+					),
+					podtest.MakeContainer("container2",
+						podtest.SetContainerResources(api.ResourceRequirements{
+							Requests: api.ResourceList{
+								api.ResourceCPU:    resource.MustParse("100m"),
+								api.ResourceMemory: resource.MustParse("1Gi"),
+							},
+						}),
+					),
+				),
+				podtest.SetStatus(podtest.MakePodStatus(
+					podtest.SetContainerStatuses(podtest.MakeContainerStatus("container1",
+						api.ResourceList{
+							api.ResourceCPU:    resource.MustParse("100m"),
+							api.ResourceMemory: resource.MustParse("1Gi"),
+						})),
+				)),
+			),
+			expected: podtest.MakePod("test-pod",
+				podtest.SetResourceVersion("2"),
+				podtest.SetContainers(podtest.MakeContainer("container1",
+					podtest.SetContainerResources(api.ResourceRequirements{
+						Requests: api.ResourceList{
+							api.ResourceCPU:    resource.MustParse("100m"),
+							api.ResourceMemory: resource.MustParse("1Gi"),
+						},
+					}),
+				)),
+				podtest.SetStatus(podtest.MakePodStatus(
+					podtest.SetContainerStatuses(podtest.MakeContainerStatus("container1",
+						api.ResourceList{
+							api.ResourceCPU:    resource.MustParse("100m"),
+							api.ResourceMemory: resource.MustParse("1Gi"),
+						})),
+				)),
+			),
+		},
+		{
+			name: "add new container and update resources of existing container",
+			oldPod: podtest.MakePod("test-pod",
+				podtest.SetResourceVersion("1"),
+				podtest.SetContainers(podtest.MakeContainer("container1",
+					podtest.SetContainerResources(api.ResourceRequirements{
+						Requests: api.ResourceList{
+							api.ResourceCPU:    resource.MustParse("100m"),
+							api.ResourceMemory: resource.MustParse("1Gi"),
+						},
+					}),
+				)),
+				podtest.SetStatus(podtest.MakePodStatus(
+					podtest.SetContainerStatuses(podtest.MakeContainerStatus("container1",
+						api.ResourceList{
+							api.ResourceCPU:    resource.MustParse("100m"),
+							api.ResourceMemory: resource.MustParse("1Gi"),
+						})),
+				)),
+			),
+			newPod: podtest.MakePod("test-pod",
+				podtest.SetResourceVersion("2"),
+				podtest.SetContainers(
+					podtest.MakeContainer("container1",
+						podtest.SetContainerResources(api.ResourceRequirements{
+							Requests: api.ResourceList{
+								api.ResourceCPU:    resource.MustParse("100m"),
+								api.ResourceMemory: resource.MustParse("2Gi"), // Updated resource
+							},
+						}),
+					),
+					podtest.MakeContainer("container2",
+						podtest.SetContainerResources(api.ResourceRequirements{
+							Requests: api.ResourceList{
+								api.ResourceCPU:    resource.MustParse("100m"),
+								api.ResourceMemory: resource.MustParse("1Gi"),
+							},
+						}),
+					),
+				),
+				podtest.SetStatus(podtest.MakePodStatus(
+					podtest.SetContainerStatuses(podtest.MakeContainerStatus("container1",
+						api.ResourceList{
+							api.ResourceCPU:    resource.MustParse("100m"),
+							api.ResourceMemory: resource.MustParse("1Gi"),
+						})),
+				)),
+			),
+			expected: podtest.MakePod("test-pod",
+				podtest.SetResourceVersion("2"),
+				podtest.SetContainers(podtest.MakeContainer("container1",
+					podtest.SetContainerResources(api.ResourceRequirements{
+						Requests: api.ResourceList{
+							api.ResourceCPU:    resource.MustParse("100m"),
+							api.ResourceMemory: resource.MustParse("2Gi"), // Updated resource
+						},
+					}),
+				)),
+				podtest.SetStatus(podtest.MakePodStatus(
+					podtest.SetResizeStatus(api.PodResizeStatusProposed), // Resize status set
+					podtest.SetContainerStatuses(podtest.MakeContainerStatus("container1",
+						api.ResourceList{
+							api.ResourceCPU:    resource.MustParse("100m"),
+							api.ResourceMemory: resource.MustParse("1Gi"),
+						})),
+				)),
+			),
+		},
+		{
+			name: "change container order and update resources",
+			oldPod: podtest.MakePod("test-pod",
+				podtest.SetResourceVersion("1"),
+				podtest.SetContainers(
+					podtest.MakeContainer("container1",
+						podtest.SetContainerResources(api.ResourceRequirements{
+							Requests: api.ResourceList{
+								api.ResourceCPU:    resource.MustParse("100m"),
+								api.ResourceMemory: resource.MustParse("1Gi"),
+							},
+						}),
+					),
+					podtest.MakeContainer("container2",
+						podtest.SetContainerResources(api.ResourceRequirements{
+							Requests: api.ResourceList{
+								api.ResourceCPU:    resource.MustParse("100m"),
+								api.ResourceMemory: resource.MustParse("1Gi"),
+							},
+						}),
+					),
+				),
+				podtest.SetStatus(podtest.MakePodStatus(
+					podtest.SetContainerStatuses(
+						podtest.MakeContainerStatus("container1",
+							api.ResourceList{
+								api.ResourceCPU:    resource.MustParse("100m"),
+								api.ResourceMemory: resource.MustParse("1Gi"),
+							}),
+						podtest.MakeContainerStatus("container2",
+							api.ResourceList{
+								api.ResourceCPU:    resource.MustParse("100m"),
+								api.ResourceMemory: resource.MustParse("1Gi"),
+							}),
+					),
+				)),
+			),
+			newPod: podtest.MakePod("test-pod",
+				podtest.SetResourceVersion("2"),
+				podtest.SetContainers(
+					podtest.MakeContainer("container2", // Order changed
+						podtest.SetContainerResources(api.ResourceRequirements{
+							Requests: api.ResourceList{
+								api.ResourceCPU:    resource.MustParse("200m"), // Updated resource
+								api.ResourceMemory: resource.MustParse("2Gi"),  // Updated resource
+							},
+						}),
+					),
+					podtest.MakeContainer("container1", // Order changed
+						podtest.SetContainerResources(api.ResourceRequirements{
+							Requests: api.ResourceList{
+								api.ResourceCPU:    resource.MustParse("200m"), // Updated resource
+								api.ResourceMemory: resource.MustParse("4Gi"),  // Updated resource
+							},
+						}),
+					),
+				),
+				podtest.SetStatus(podtest.MakePodStatus(
+					podtest.SetContainerStatuses(
+						podtest.MakeContainerStatus("container1",
+							api.ResourceList{
+								api.ResourceCPU:    resource.MustParse("100m"),
+								api.ResourceMemory: resource.MustParse("1Gi"),
+							}),
+						podtest.MakeContainerStatus("container2",
+							api.ResourceList{
+								api.ResourceCPU:    resource.MustParse("100m"),
+								api.ResourceMemory: resource.MustParse("1Gi"),
+							}),
+					),
+				)),
+			),
+			expected: podtest.MakePod("test-pod",
+				podtest.SetResourceVersion("2"),
+				podtest.SetContainers(
+					podtest.MakeContainer("container1",
+						podtest.SetContainerResources(api.ResourceRequirements{
+							Requests: api.ResourceList{
+								api.ResourceCPU:    resource.MustParse("200m"), // Updated resource
+								api.ResourceMemory: resource.MustParse("4Gi"),  // Updated resource
+							},
+						}),
+					),
+					podtest.MakeContainer("container2",
+						podtest.SetContainerResources(api.ResourceRequirements{
+							Requests: api.ResourceList{
+								api.ResourceCPU:    resource.MustParse("200m"), // Updated resource
+								api.ResourceMemory: resource.MustParse("2Gi"),  // Updated resource
+							},
+						}),
+					),
+				),
+				podtest.SetStatus(podtest.MakePodStatus(
+					podtest.SetResizeStatus(api.PodResizeStatusProposed), // Resize status set
+					podtest.SetContainerStatuses(
+						podtest.MakeContainerStatus("container1",
+							api.ResourceList{
+								api.ResourceCPU:    resource.MustParse("100m"),
+								api.ResourceMemory: resource.MustParse("1Gi"),
+							}),
+						podtest.MakeContainerStatus("container2",
+							api.ResourceList{
+								api.ResourceCPU:    resource.MustParse("100m"),
+								api.ResourceMemory: resource.MustParse("1Gi"),
+							}),
+					),
+				)),
+			),
+		},
+		{
+			name: "change pod labels",
+			oldPod: podtest.MakePod("test-pod",
+				podtest.SetResourceVersion("1"),
+				podtest.SetLabels(map[string]string{"foo": "bar"}),
+				podtest.SetContainers(
+					podtest.MakeContainer("container1",
+						podtest.SetContainerResources(api.ResourceRequirements{
+							Requests: api.ResourceList{
+								api.ResourceCPU:    resource.MustParse("100m"),
+								api.ResourceMemory: resource.MustParse("1Gi"),
+							},
+						}),
+					),
+				),
+				podtest.SetStatus(podtest.MakePodStatus(
+					podtest.SetContainerStatuses(
+						podtest.MakeContainerStatus("container1",
+							api.ResourceList{
+								api.ResourceCPU:    resource.MustParse("100m"),
+								api.ResourceMemory: resource.MustParse("1Gi"),
+							}),
+					),
+				)),
+			),
+			newPod: podtest.MakePod("test-pod",
+				podtest.SetResourceVersion("2"),
+				podtest.SetLabels(map[string]string{"foo": "bar", "baz": "qux"}),
+				podtest.SetContainers(
+					podtest.MakeContainer("container1",
+						podtest.SetContainerResources(api.ResourceRequirements{
+							Requests: api.ResourceList{
+								api.ResourceCPU:    resource.MustParse("100m"),
+								api.ResourceMemory: resource.MustParse("1Gi"),
+							},
+						}),
+					),
+				),
+				podtest.SetStatus(podtest.MakePodStatus(
+					podtest.SetContainerStatuses(
+						podtest.MakeContainerStatus("container1",
+							api.ResourceList{
+								api.ResourceCPU:    resource.MustParse("100m"),
+								api.ResourceMemory: resource.MustParse("1Gi"),
+							}),
+					),
+				)),
+			),
+			expected: podtest.MakePod("test-pod",
+				podtest.SetResourceVersion("2"),
+				podtest.SetLabels(map[string]string{"foo": "bar"}),
+				podtest.SetContainers(
+					podtest.MakeContainer("container1",
+						podtest.SetContainerResources(api.ResourceRequirements{
+							Requests: api.ResourceList{
+								api.ResourceCPU:    resource.MustParse("100m"),
+								api.ResourceMemory: resource.MustParse("1Gi"),
+							},
+						}),
+					),
+				),
+				podtest.SetStatus(podtest.MakePodStatus(
+					podtest.SetContainerStatuses(
+						podtest.MakeContainerStatus("container1",
+							api.ResourceList{
+								api.ResourceCPU:    resource.MustParse("100m"),
+								api.ResourceMemory: resource.MustParse("1Gi"),
+							}),
+					),
+				)),
+			),
+		},
+	}
+
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.InPlacePodVerticalScaling, true)
+			featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.InPlacePodVerticalScalingAllocatedStatus, true)
+			ctx := context.Background()
+			ResizeStrategy.PrepareForUpdate(ctx, tc.newPod, tc.oldPod)
+			if !cmp.Equal(tc.expected, tc.newPod) {
+				t.Errorf("ResizeStrategy.PrepareForUpdate() diff = %v", cmp.Diff(tc.expected, tc.newPod))
+			}
+		})
+	}
+}
diff --git a/plugin/pkg/admission/limitranger/admission_test.go b/plugin/pkg/admission/limitranger/admission_test.go
index d28b9d1cecce2..d8c4a2d3d1e43 100644
--- a/plugin/pkg/admission/limitranger/admission_test.go
+++ b/plugin/pkg/admission/limitranger/admission_test.go
@@ -34,10 +34,13 @@ import (
 	"k8s.io/apiserver/pkg/admission"
 	genericadmissioninitializer "k8s.io/apiserver/pkg/admission/initializer"
 	admissiontesting "k8s.io/apiserver/pkg/admission/testing"
+	utilfeature "k8s.io/apiserver/pkg/util/feature"
 	"k8s.io/client-go/informers"
 	clientset "k8s.io/client-go/kubernetes"
 	"k8s.io/client-go/kubernetes/fake"
 	core "k8s.io/client-go/testing"
+	featuregatetesting "k8s.io/component-base/featuregate/testing"
+	"k8s.io/kubernetes/pkg/features"
 
 	api "k8s.io/kubernetes/pkg/apis/core"
 	v1 "k8s.io/kubernetes/pkg/apis/core/v1"
@@ -751,7 +754,23 @@ func TestLimitRangerIgnoresSubresource(t *testing.T) {
 	if err != nil {
 		t.Errorf("Should have ignored calls to any subresource of pod %v", err)
 	}
+}
+
+func TestLimitRangerAllowPodResize(t *testing.T) {
+	limitRange := validLimitRangeNoDefaults()
+	mockClient := newMockClientForTest([]corev1.LimitRange{limitRange})
+	handler, informerFactory, err := newHandlerForTest(mockClient)
+	if err != nil {
+		t.Errorf("unexpected error initializing handler: %v", err)
+	}
+	informerFactory.Start(wait.NeverStop)
 
+	testPod := validPod("testPod", 1, api.ResourceRequirements{})
+	featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.InPlacePodVerticalScaling, true)
+	err = handler.Validate(context.TODO(), admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "resize", admission.Update, &metav1.UpdateOptions{}, false, nil), nil)
+	if err == nil {
+		t.Errorf("expect error, but got nil")
+	}
 }
 
 func TestLimitRangerAdmitPod(t *testing.T) {
diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/resourcequota/admission_test.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/resourcequota/admission_test.go
index efe323a079f2f..0cc3d7be137c6 100644
--- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/resourcequota/admission_test.go
+++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/resourcequota/admission_test.go
@@ -143,10 +143,6 @@ func TestExcludedOperations(t *testing.T) {
 		desc string
 		attr admission.Attributes
 	}{
-		{
-			"subresource",
-			admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, "namespace", "name", schema.GroupVersionResource{}, "subresource", admission.Create, nil, false, nil),
-		},
 		{
 			"non-namespaced resource",
 			admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{}, "", "namespace", schema.GroupVersionResource{}, "", admission.Create, nil, false, nil),
diff --git a/staging/src/k8s.io/apiserver/pkg/quota/v1/generic/evaluator_test.go b/staging/src/k8s.io/apiserver/pkg/quota/v1/generic/evaluator_test.go
index ce97b1bdf2fed..deaa5d74b9300 100644
--- a/staging/src/k8s.io/apiserver/pkg/quota/v1/generic/evaluator_test.go
+++ b/staging/src/k8s.io/apiserver/pkg/quota/v1/generic/evaluator_test.go
@@ -22,6 +22,8 @@ import (
 
 	"k8s.io/apimachinery/pkg/labels"
 	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	"k8s.io/apiserver/pkg/admission"
 	"k8s.io/client-go/tools/cache"
 )
 
@@ -129,3 +131,52 @@ func (f *fakeLister) Get(name string) (runtime.Object, error) {
 func (f *fakeLister) ByNamespace(namespace string) cache.GenericNamespaceLister {
 	panic("not implemented")
 }
+
+func TestObjectCountEvaluatorHandles(t *testing.T) {
+	evaluator := objectCountEvaluator{}
+	testCases := []struct {
+		name  string
+		attrs admission.Attributes
+		want  bool
+	}{
+		{
+			name:  "create",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "", admission.Create, nil, false, nil),
+			want:  true,
+		},
+		{
+			name:  "update",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "", admission.Update, nil, false, nil),
+			want:  false,
+		},
+		{
+			name:  "delete",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "", admission.Delete, nil, false, nil),
+			want:  false,
+		},
+		{
+			name:  "connect",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "", admission.Connect, nil, false, nil),
+			want:  false,
+		},
+		{
+			name:  "create-subresource",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "subresource", admission.Create, nil, false, nil),
+			want:  false,
+		},
+		{
+			name:  "update-subresource",
+			attrs: admission.NewAttributesRecord(nil, nil, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "Pod"}, "", "", schema.GroupVersionResource{Group: "core", Version: "v1", Resource: "pods"}, "subresource", admission.Update, nil, false, nil),
+			want:  false,
+		},
+	}
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			actual := evaluator.Handles(tc.attrs)
+
+			if tc.want != actual {
+				t.Errorf("%s expected:\n%v\n, actual:\n%v", tc.name, tc.want, actual)
+			}
+		})
+	}
+}
diff --git a/test/e2e/common/node/pod_resize.go b/test/e2e/common/node/pod_resize.go
index ac48b18398634..d6649c38e53a3 100644
--- a/test/e2e/common/node/pod_resize.go
+++ b/test/e2e/common/node/pod_resize.go
@@ -903,8 +903,8 @@ func doPodResizeTests(f *framework.Framework) {
 
 			patchAndVerify := func(patchString string, expectedContainers []e2epod.ResizableContainerInfo, opStr string) {
 				ginkgo.By(fmt.Sprintf("patching pod for %s", opStr))
-				patchedPod, pErr = f.ClientSet.CoreV1().Pods(newPod.Namespace).Patch(context.TODO(), newPod.Name,
-					types.StrategicMergePatchType, []byte(patchString), metav1.PatchOptions{})
+				patchedPod, pErr = f.ClientSet.CoreV1().Pods(newPod.Namespace).Patch(ctx, newPod.Name,
+					types.StrategicMergePatchType, []byte(patchString), metav1.PatchOptions{}, "resize")
 				framework.ExpectNoError(pErr, fmt.Sprintf("failed to patch pod for %s", opStr))
 
 				ginkgo.By(fmt.Sprintf("verifying pod patched for %s", opStr))
@@ -996,7 +996,7 @@ func doPodResizeErrorTests(f *framework.Framework) {
 
 			ginkgo.By("patching pod for resize")
 			patchedPod, pErr = f.ClientSet.CoreV1().Pods(newPod.Namespace).Patch(ctx, newPod.Name,
-				types.StrategicMergePatchType, []byte(tc.patchString), metav1.PatchOptions{})
+				types.StrategicMergePatchType, []byte(tc.patchString), metav1.PatchOptions{}, "resize")
 			if tc.patchError == "" {
 				framework.ExpectNoError(pErr, "failed to patch pod for resize")
 			} else {
diff --git a/test/e2e/node/pod_resize.go b/test/e2e/node/pod_resize.go
index 2a4628109c39b..7abc9ec25e917 100644
--- a/test/e2e/node/pod_resize.go
+++ b/test/e2e/node/pod_resize.go
@@ -37,107 +37,160 @@ import (
 	"github.com/onsi/gomega"
 )
 
-func doPodResizeResourceQuotaTests(f *framework.Framework) {
-	ginkgo.It("pod-resize-resource-quota-test", func(ctx context.Context) {
-		podClient := e2epod.NewPodClient(f)
-		resourceQuota := v1.ResourceQuota{
-			ObjectMeta: metav1.ObjectMeta{
-				Name:      "resize-resource-quota",
-				Namespace: f.Namespace.Name,
-			},
-			Spec: v1.ResourceQuotaSpec{
-				Hard: v1.ResourceList{
-					v1.ResourceCPU:    resource.MustParse("800m"),
-					v1.ResourceMemory: resource.MustParse("800Mi"),
-				},
-			},
-		}
-		containers := []e2epod.ResizableContainerInfo{
-			{
-				Name:      "c1",
-				Resources: &e2epod.ContainerResources{CPUReq: "300m", CPULim: "300m", MemReq: "300Mi", MemLim: "300Mi"},
-			},
-		}
-		patchString := `{"spec":{"containers":[
-			{"name":"c1", "resources":{"requests":{"cpu":"400m","memory":"400Mi"},"limits":{"cpu":"400m","memory":"400Mi"}}}
-		]}}`
-		expected := []e2epod.ResizableContainerInfo{
-			{
-				Name:      "c1",
-				Resources: &e2epod.ContainerResources{CPUReq: "400m", CPULim: "400m", MemReq: "400Mi", MemLim: "400Mi"},
-			},
-		}
-		patchStringExceedCPU := `{"spec":{"containers":[
-			{"name":"c1", "resources":{"requests":{"cpu":"600m","memory":"200Mi"},"limits":{"cpu":"600m","memory":"200Mi"}}}
-		]}}`
-		patchStringExceedMemory := `{"spec":{"containers":[
-			{"name":"c1", "resources":{"requests":{"cpu":"250m","memory":"750Mi"},"limits":{"cpu":"250m","memory":"750Mi"}}}
-		]}}`
-
-		ginkgo.By("Creating a ResourceQuota")
-		_, rqErr := f.ClientSet.CoreV1().ResourceQuotas(f.Namespace.Name).Create(ctx, &resourceQuota, metav1.CreateOptions{})
-		framework.ExpectNoError(rqErr, "failed to create resource quota")
-
-		tStamp := strconv.Itoa(time.Now().Nanosecond())
-		e2epod.InitDefaultResizePolicy(containers)
-		e2epod.InitDefaultResizePolicy(expected)
-		testPod1 := e2epod.MakePodWithResizableContainers(f.Namespace.Name, "testpod1", tStamp, containers)
-		testPod1 = e2epod.MustMixinRestrictedPodSecurity(testPod1)
-		testPod2 := e2epod.MakePodWithResizableContainers(f.Namespace.Name, "testpod2", tStamp, containers)
-		testPod2 = e2epod.MustMixinRestrictedPodSecurity(testPod2)
-
-		ginkgo.By("creating pods")
-		newPod1 := podClient.CreateSync(ctx, testPod1)
-		newPod2 := podClient.CreateSync(ctx, testPod2)
-
-		ginkgo.By("verifying initial pod resources, and policy are as expected")
-		e2epod.VerifyPodResources(newPod1, containers)
-
-		ginkgo.By("patching pod for resize within resource quota")
-		patchedPod, pErr := f.ClientSet.CoreV1().Pods(newPod1.Namespace).Patch(ctx, newPod1.Name,
-			types.StrategicMergePatchType, []byte(patchString), metav1.PatchOptions{})
-		framework.ExpectNoError(pErr, "failed to patch pod for resize")
-
-		ginkgo.By("verifying pod patched for resize within resource quota")
-		e2epod.VerifyPodResources(patchedPod, expected)
-
-		ginkgo.By("waiting for resize to be actuated")
-		resizedPod := e2epod.WaitForPodResizeActuation(ctx, f, podClient, newPod1)
-		e2epod.ExpectPodResized(ctx, f, resizedPod, expected)
-
-		ginkgo.By("verifying pod resources after resize")
-		e2epod.VerifyPodResources(resizedPod, expected)
-
-		ginkgo.By("patching pod for resize with memory exceeding resource quota")
-		_, pErrExceedMemory := f.ClientSet.CoreV1().Pods(resizedPod.Namespace).Patch(ctx,
-			resizedPod.Name, types.StrategicMergePatchType, []byte(patchStringExceedMemory), metav1.PatchOptions{})
-		gomega.Expect(pErrExceedMemory).To(gomega.HaveOccurred(), "exceeded quota: %s, requested: memory=350Mi, used: memory=700Mi, limited: memory=800Mi",
-			resourceQuota.Name)
-
-		ginkgo.By("verifying pod patched for resize exceeding memory resource quota remains unchanged")
-		patchedPodExceedMemory, pErrEx2 := podClient.Get(ctx, resizedPod.Name, metav1.GetOptions{})
-		framework.ExpectNoError(pErrEx2, "failed to get pod post exceed memory resize")
-		e2epod.VerifyPodResources(patchedPodExceedMemory, expected)
-		framework.ExpectNoError(e2epod.VerifyPodStatusResources(patchedPodExceedMemory, expected))
+func doPodResizeAdmissionPluginsTests() {
+	testcases := []struct {
+		name                  string
+		enableAdmissionPlugin func(ctx context.Context, f *framework.Framework)
+		wantMemoryError       string
+		wantCPUError          string
+	}{
+		{
+			name: "pod-resize-resource-quota-test",
+			enableAdmissionPlugin: func(ctx context.Context, f *framework.Framework) {
+				resourceQuota := v1.ResourceQuota{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "resize-resource-quota",
+						Namespace: f.Namespace.Name,
+					},
+					Spec: v1.ResourceQuotaSpec{
+						Hard: v1.ResourceList{
+							v1.ResourceCPU:    resource.MustParse("800m"),
+							v1.ResourceMemory: resource.MustParse("800Mi"),
+						},
+					},
+				}
 
-		ginkgo.By(fmt.Sprintf("patching pod %s for resize with CPU exceeding resource quota", resizedPod.Name))
-		_, pErrExceedCPU := f.ClientSet.CoreV1().Pods(resizedPod.Namespace).Patch(ctx,
-			resizedPod.Name, types.StrategicMergePatchType, []byte(patchStringExceedCPU), metav1.PatchOptions{})
-		gomega.Expect(pErrExceedCPU).To(gomega.HaveOccurred(), "exceeded quota: %s, requested: cpu=200m, used: cpu=700m, limited: cpu=800m",
-			resourceQuota.Name)
+				ginkgo.By("Creating a ResourceQuota")
+				_, rqErr := f.ClientSet.CoreV1().ResourceQuotas(f.Namespace.Name).Create(ctx, &resourceQuota, metav1.CreateOptions{})
+				framework.ExpectNoError(rqErr, "failed to create resource quota")
+			},
+			wantMemoryError: "exceeded quota: resize-resource-quota, requested: memory=350Mi, used: memory=700Mi, limited: memory=800Mi",
+			wantCPUError:    "exceeded quota: resize-resource-quota, requested: cpu=200m, used: cpu=700m, limited: cpu=800m",
+		},
+		{
+			name: "pod-resize-limit-ranger-test",
+			enableAdmissionPlugin: func(ctx context.Context, f *framework.Framework) {
+				lr := v1.LimitRange{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "resize-limit-ranger",
+						Namespace: f.Namespace.Name,
+					},
+					Spec: v1.LimitRangeSpec{
+						Limits: []v1.LimitRangeItem{
+							{
+								Type: v1.LimitTypeContainer,
+								Max: v1.ResourceList{
+									v1.ResourceCPU:    resource.MustParse("500m"),
+									v1.ResourceMemory: resource.MustParse("500Mi"),
+								},
+								Min: v1.ResourceList{
+									v1.ResourceCPU:    resource.MustParse("50m"),
+									v1.ResourceMemory: resource.MustParse("50Mi"),
+								},
+								Default: v1.ResourceList{
+									v1.ResourceCPU:    resource.MustParse("100m"),
+									v1.ResourceMemory: resource.MustParse("100Mi"),
+								},
+								DefaultRequest: v1.ResourceList{
+									v1.ResourceCPU:    resource.MustParse("50m"),
+									v1.ResourceMemory: resource.MustParse("50Mi"),
+								},
+							},
+						},
+					},
+				}
 
-		ginkgo.By("verifying pod patched for resize exceeding CPU resource quota remains unchanged")
-		patchedPodExceedCPU, pErrEx1 := podClient.Get(ctx, resizedPod.Name, metav1.GetOptions{})
-		framework.ExpectNoError(pErrEx1, "failed to get pod post exceed CPU resize")
-		e2epod.VerifyPodResources(patchedPodExceedCPU, expected)
-		framework.ExpectNoError(e2epod.VerifyPodStatusResources(patchedPodExceedMemory, expected))
+				ginkgo.By("Creating a LimitRanger")
+				_, lrErr := f.ClientSet.CoreV1().LimitRanges(f.Namespace.Name).Create(ctx, &lr, metav1.CreateOptions{})
+				framework.ExpectNoError(lrErr, "failed to create limit ranger")
+			},
+			wantMemoryError: "forbidden: maximum memory usage per Container is 500Mi, but limit is 750Mi",
+			wantCPUError:    "forbidden: maximum cpu usage per Container is 500m, but limit is 600m",
+		},
+	}
+
+	for _, tc := range testcases {
+		ginkgo.It(tc.name, func(ctx context.Context) {
+			f := framework.NewDefaultFramework(tc.name)
+
+			containers := []e2epod.ResizableContainerInfo{
+				{
+					Name:      "c1",
+					Resources: &e2epod.ContainerResources{CPUReq: "300m", CPULim: "300m", MemReq: "300Mi", MemLim: "300Mi"},
+				},
+			}
+			patchString := `{"spec":{"containers":[
+				{"name":"c1", "resources":{"requests":{"cpu":"400m","memory":"400Mi"},"limits":{"cpu":"400m","memory":"400Mi"}}}
+			]}}`
+			expected := []e2epod.ResizableContainerInfo{
+				{
+					Name:      "c1",
+					Resources: &e2epod.ContainerResources{CPUReq: "400m", CPULim: "400m", MemReq: "400Mi", MemLim: "400Mi"},
+				},
+			}
+			patchStringExceedCPU := `{"spec":{"containers":[
+				{"name":"c1", "resources":{"requests":{"cpu":"600m","memory":"200Mi"},"limits":{"cpu":"600m","memory":"200Mi"}}}
+			]}}`
+			patchStringExceedMemory := `{"spec":{"containers":[
+				{"name":"c1", "resources":{"requests":{"cpu":"250m","memory":"750Mi"},"limits":{"cpu":"250m","memory":"750Mi"}}}
+			]}}`
+
+			tc.enableAdmissionPlugin(ctx, f)
+
+			tStamp := strconv.Itoa(time.Now().Nanosecond())
+			e2epod.InitDefaultResizePolicy(containers)
+			e2epod.InitDefaultResizePolicy(expected)
+			testPod1 := e2epod.MakePodWithResizableContainers(f.Namespace.Name, "testpod1", tStamp, containers)
+			testPod1 = e2epod.MustMixinRestrictedPodSecurity(testPod1)
+			testPod2 := e2epod.MakePodWithResizableContainers(f.Namespace.Name, "testpod2", tStamp, containers)
+			testPod2 = e2epod.MustMixinRestrictedPodSecurity(testPod2)
+
+			ginkgo.By("creating pods")
+			podClient := e2epod.NewPodClient(f)
+			newPods := podClient.CreateBatch(ctx, []*v1.Pod{testPod1, testPod2})
+
+			ginkgo.By("verifying initial pod resources, and policy are as expected")
+			e2epod.VerifyPodResources(newPods[0], containers)
+
+			ginkgo.By("patching pod for resize within resource quota")
+			patchedPod, pErr := f.ClientSet.CoreV1().Pods(newPods[0].Namespace).Patch(ctx, newPods[0].Name,
+				types.StrategicMergePatchType, []byte(patchString), metav1.PatchOptions{}, "resize")
+			framework.ExpectNoError(pErr, "failed to patch pod for resize")
+
+			ginkgo.By("verifying pod patched for resize within resource quota")
+			e2epod.VerifyPodResources(patchedPod, expected)
+
+			ginkgo.By("waiting for resize to be actuated")
+			resizedPod := e2epod.WaitForPodResizeActuation(ctx, f, podClient, newPods[0])
+			e2epod.ExpectPodResized(ctx, f, resizedPod, expected)
+
+			ginkgo.By("verifying pod resources after resize")
+			e2epod.VerifyPodResources(resizedPod, expected)
+
+			ginkgo.By("patching pod for resize with memory exceeding resource quota")
+			_, pErrExceedMemory := f.ClientSet.CoreV1().Pods(resizedPod.Namespace).Patch(ctx,
+				resizedPod.Name, types.StrategicMergePatchType, []byte(patchStringExceedMemory), metav1.PatchOptions{}, "resize")
+			gomega.Expect(pErrExceedMemory).To(gomega.HaveOccurred(), tc.wantMemoryError)
+
+			ginkgo.By("verifying pod patched for resize exceeding memory resource quota remains unchanged")
+			patchedPodExceedMemory, pErrEx2 := podClient.Get(ctx, resizedPod.Name, metav1.GetOptions{})
+			framework.ExpectNoError(pErrEx2, "failed to get pod post exceed memory resize")
+			e2epod.VerifyPodResources(patchedPodExceedMemory, expected)
+			framework.ExpectNoError(e2epod.VerifyPodStatusResources(patchedPodExceedMemory, expected))
+
+			ginkgo.By(fmt.Sprintf("patching pod %s for resize with CPU exceeding resource quota", resizedPod.Name))
+			_, pErrExceedCPU := f.ClientSet.CoreV1().Pods(resizedPod.Namespace).Patch(ctx,
+				resizedPod.Name, types.StrategicMergePatchType, []byte(patchStringExceedCPU), metav1.PatchOptions{}, "resize")
+			gomega.Expect(pErrExceedCPU).To(gomega.HaveOccurred(), tc.wantCPUError)
+
+			ginkgo.By("verifying pod patched for resize exceeding CPU resource quota remains unchanged")
+			patchedPodExceedCPU, pErrEx1 := podClient.Get(ctx, resizedPod.Name, metav1.GetOptions{})
+			framework.ExpectNoError(pErrEx1, "failed to get pod post exceed CPU resize")
+			e2epod.VerifyPodResources(patchedPodExceedCPU, expected)
+			framework.ExpectNoError(e2epod.VerifyPodStatusResources(patchedPodExceedMemory, expected))
+		})
+	}
 
-		ginkgo.By("deleting pods")
-		delErr1 := e2epod.DeletePodWithWait(ctx, f.ClientSet, newPod1)
-		framework.ExpectNoError(delErr1, "failed to delete pod %s", newPod1.Name)
-		delErr2 := e2epod.DeletePodWithWait(ctx, f.ClientSet, newPod2)
-		framework.ExpectNoError(delErr2, "failed to delete pod %s", newPod2.Name)
-	})
 }
 
 func doPodResizeSchedulerTests(f *framework.Framework) {
@@ -235,7 +288,7 @@ func doPodResizeSchedulerTests(f *framework.Framework) {
 
 		ginkgo.By(fmt.Sprintf("TEST1: Resize pod '%s' to fit in node '%s'", testPod2.Name, node.Name))
 		testPod2, pErr := f.ClientSet.CoreV1().Pods(testPod2.Namespace).Patch(ctx,
-			testPod2.Name, types.StrategicMergePatchType, []byte(patchTestpod2ToFitNode), metav1.PatchOptions{})
+			testPod2.Name, types.StrategicMergePatchType, []byte(patchTestpod2ToFitNode), metav1.PatchOptions{}, "resize")
 		framework.ExpectNoError(pErr, "failed to patch pod for resize")
 
 		ginkgo.By(fmt.Sprintf("TEST1: Verify that pod '%s' is running after resize", testPod2.Name))
@@ -284,7 +337,7 @@ func doPodResizeSchedulerTests(f *framework.Framework) {
 
 		ginkgo.By(fmt.Sprintf("TEST2: Resize pod '%s' to make enough space for pod '%s'", testPod1.Name, testPod3.Name))
 		testPod1, p1Err := f.ClientSet.CoreV1().Pods(testPod1.Namespace).Patch(ctx,
-			testPod1.Name, types.StrategicMergePatchType, []byte(patchTestpod1ToMakeSpaceForPod3), metav1.PatchOptions{})
+			testPod1.Name, types.StrategicMergePatchType, []byte(patchTestpod1ToMakeSpaceForPod3), metav1.PatchOptions{}, "resize")
 		framework.ExpectNoError(p1Err, "failed to patch pod for resize")
 
 		ginkgo.By(fmt.Sprintf("TEST2: Verify pod '%s' is running after successfully resizing pod '%s'", testPod3.Name, testPod1.Name))
@@ -316,13 +369,13 @@ var _ = SIGDescribe(framework.WithSerial(), "Pod InPlace Resize Container (sched
 })
 
 var _ = SIGDescribe("Pod InPlace Resize Container", feature.InPlacePodVerticalScaling, func() {
-	f := framework.NewDefaultFramework("pod-resize-tests")
 	ginkgo.BeforeEach(func(ctx context.Context) {
+		f := framework.NewDefaultFramework("pod-resize-tests")
 		node, err := e2enode.GetRandomReadySchedulableNode(ctx, f.ClientSet)
 		framework.ExpectNoError(err)
 		if framework.NodeOSDistroIs("windows") || e2enode.IsARM64(node) {
 			e2eskipper.Skipf("runtime does not support InPlacePodVerticalScaling -- skipping")
 		}
 	})
-	doPodResizeResourceQuotaTests(f)
+	doPodResizeAdmissionPluginsTests()
 })
diff --git a/test/integration/apiserver/cel/validatingadmissionpolicy_test.go b/test/integration/apiserver/cel/validatingadmissionpolicy_test.go
index bf618da56d36d..72e2fac942287 100644
--- a/test/integration/apiserver/cel/validatingadmissionpolicy_test.go
+++ b/test/integration/apiserver/cel/validatingadmissionpolicy_test.go
@@ -2589,7 +2589,7 @@ func Test_ValidateSecondaryAuthorization(t *testing.T) {
 		},
 		{
 			name:           "serviceaccount is authorized for custom verb on current resource",
-			extraAccountFn: serviceAccountClient("default", "extra-acct"),
+			extraAccountFn: authutil.ServiceAccountClient("default", "extra-acct"),
 			extraAccountRbac: &rbacv1.PolicyRule{
 				Verbs:     []string{"anthropomorphize"},
 				APIGroups: []string{""},
@@ -2985,8 +2985,6 @@ contexts:
 	}
 }
 
-type clientFn func(t *testing.T, adminClient *clientset.Clientset, clientConfig *rest.Config, rules []rbacv1.PolicyRule) *clientset.Clientset
-
 func secondaryAuthorizationUserClient(t *testing.T, adminClient *clientset.Clientset, clientConfig *rest.Config, rules []rbacv1.PolicyRule) *clientset.Clientset {
 	clientConfig = rest.CopyConfig(clientConfig)
 	clientConfig.Impersonate = rest.ImpersonationConfig{
@@ -3002,29 +3000,7 @@ func secondaryAuthorizationUserClient(t *testing.T, adminClient *clientset.Clien
 }
 
 func secondaryAuthorizationServiceAccountClient(t *testing.T, adminClient *clientset.Clientset, clientConfig *rest.Config, rules []rbacv1.PolicyRule) *clientset.Clientset {
-	return serviceAccountClient("default", "test-service-acct")(t, adminClient, clientConfig, rules)
-}
-
-func serviceAccountClient(namespace, name string) clientFn {
-	return func(t *testing.T, adminClient *clientset.Clientset, clientConfig *rest.Config, rules []rbacv1.PolicyRule) *clientset.Clientset {
-		clientConfig = rest.CopyConfig(clientConfig)
-		sa, err := adminClient.CoreV1().ServiceAccounts(namespace).Create(context.TODO(), &v1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: name}}, metav1.CreateOptions{})
-		if err != nil && !apierrors.IsAlreadyExists(err) {
-			t.Fatal(err)
-		}
-		uid := sa.UID
-
-		clientConfig.Impersonate = rest.ImpersonationConfig{
-			UserName: "system:serviceaccount:" + namespace + ":" + name,
-			UID:      string(uid),
-		}
-		client := clientset.NewForConfigOrDie(clientConfig)
-
-		for _, rule := range rules {
-			authutil.GrantServiceAccountAuthorization(t, context.TODO(), adminClient, name, namespace, rule)
-		}
-		return client
-	}
+	return authutil.ServiceAccountClient("default", "test-service-acct")(t, adminClient, clientConfig, rules)
 }
 
 func withWaitReadyConstraintAndExpression(policy *admissionregistrationv1.ValidatingAdmissionPolicy) *admissionregistrationv1.ValidatingAdmissionPolicy {
diff --git a/test/integration/authutil/authutil.go b/test/integration/authutil/authutil.go
index 8373de2360fff..6bd169e86a715 100644
--- a/test/integration/authutil/authutil.go
+++ b/test/integration/authutil/authutil.go
@@ -23,12 +23,15 @@ import (
 	"time"
 
 	authorizationv1 "k8s.io/api/authorization/v1"
+	v1 "k8s.io/api/core/v1"
 	rbacv1 "k8s.io/api/rbac/v1"
+	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime/schema"
 	"k8s.io/apimachinery/pkg/util/wait"
 	clientset "k8s.io/client-go/kubernetes"
 	authorizationv1client "k8s.io/client-go/kubernetes/typed/authorization/v1"
+	"k8s.io/client-go/rest"
 )
 
 // WaitForNamedAuthorizationUpdate checks if the given user can perform the named verb and action on the named resource.
@@ -132,3 +135,27 @@ func grantAuthorization(t *testing.T, ctx context.Context, adminClient clientset
 		true,
 	)
 }
+
+type clientFn func(t *testing.T, adminClient *clientset.Clientset, clientConfig *rest.Config, rules []rbacv1.PolicyRule) *clientset.Clientset
+
+func ServiceAccountClient(namespace, name string) clientFn {
+	return func(t *testing.T, adminClient *clientset.Clientset, clientConfig *rest.Config, rules []rbacv1.PolicyRule) *clientset.Clientset {
+		clientConfig = rest.CopyConfig(clientConfig)
+		sa, err := adminClient.CoreV1().ServiceAccounts(namespace).Create(context.TODO(), &v1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: name}}, metav1.CreateOptions{})
+		if err != nil && !apierrors.IsAlreadyExists(err) {
+			t.Fatal(err)
+		}
+		uid := sa.UID
+
+		clientConfig.Impersonate = rest.ImpersonationConfig{
+			UserName: "system:serviceaccount:" + namespace + ":" + name,
+			UID:      string(uid),
+		}
+		client := clientset.NewForConfigOrDie(clientConfig)
+
+		for _, rule := range rules {
+			GrantServiceAccountAuthorization(t, context.TODO(), adminClient, name, namespace, rule)
+		}
+		return client
+	}
+}
diff --git a/test/integration/pods/pods_test.go b/test/integration/pods/pods_test.go
index e0c0f7d7861bd..c137a3311cb1b 100644
--- a/test/integration/pods/pods_test.go
+++ b/test/integration/pods/pods_test.go
@@ -23,15 +23,20 @@ import (
 	"testing"
 
 	v1 "k8s.io/api/core/v1"
+	rbacv1 "k8s.io/api/rbac/v1"
+	"k8s.io/apimachinery/pkg/api/resource"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/types"
 	utilfeature "k8s.io/apiserver/pkg/util/feature"
 	clientset "k8s.io/client-go/kubernetes"
 	typedv1 "k8s.io/client-go/kubernetes/typed/core/v1"
+	"k8s.io/client-go/rest"
 	featuregatetesting "k8s.io/component-base/featuregate/testing"
 	kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
+	rbachelper "k8s.io/kubernetes/pkg/apis/rbac/v1"
 	"k8s.io/kubernetes/pkg/features"
 	"k8s.io/kubernetes/test/integration"
+	"k8s.io/kubernetes/test/integration/authutil"
 	"k8s.io/kubernetes/test/integration/framework"
 )
 
@@ -678,6 +683,352 @@ func TestPodUpdateEphemeralContainers(t *testing.T) {
 	}
 }
 
+func TestPodResizeRBAC(t *testing.T) {
+	featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.InPlacePodVerticalScaling, true)
+	server := kubeapiservertesting.StartTestServerOrDie(t, nil,
+		append(framework.DefaultTestServerFlags(), "--authorization-mode=RBAC"), framework.SharedEtcd())
+	defer server.TearDownFn()
+	adminClient := clientset.NewForConfigOrDie(server.ClientConfig)
+
+	ns := framework.CreateNamespaceOrDie(adminClient, "pod-resize", t)
+	defer framework.DeleteNamespaceOrDie(adminClient, ns, t)
+
+	testPod := func(name string) *v1.Pod {
+		return &v1.Pod{
+			ObjectMeta: metav1.ObjectMeta{
+				Name: name,
+			},
+			Spec: v1.PodSpec{
+				Containers: []v1.Container{
+					{
+						Name:  "fake-name",
+						Image: "fakeimage",
+					},
+				},
+			},
+		}
+	}
+
+	testcases := []struct {
+		name               string
+		serviceAccountFn   func(t *testing.T, adminClient *clientset.Clientset, clientConfig *rest.Config, rules []rbacv1.PolicyRule) *clientset.Clientset
+		serviceAccountRBAC rbacv1.PolicyRule
+		allowResize        bool
+		allowUpdate        bool
+	}{
+		{
+			name:               "pod-mutator",
+			serviceAccountFn:   authutil.ServiceAccountClient(ns.Name, "pod-mutator"),
+			serviceAccountRBAC: rbachelper.NewRule("get", "update", "patch").Groups("").Resources("pods").RuleOrDie(),
+			allowResize:        false,
+			allowUpdate:        true,
+		},
+		{
+			name:               "pod-resizer",
+			serviceAccountFn:   authutil.ServiceAccountClient(ns.Name, "pod-resizer"),
+			serviceAccountRBAC: rbachelper.NewRule("get", "update", "patch").Groups("").Resources("pods/resize").RuleOrDie(),
+			allowResize:        true,
+			allowUpdate:        false,
+		},
+	}
+
+	for i, tc := range testcases {
+		t.Run(tc.name, func(t *testing.T) {
+			// 1. Create a test pod.
+			pod := testPod(fmt.Sprintf("resize-%d", i))
+			resp, err := adminClient.CoreV1().Pods(ns.Name).Create(context.TODO(), pod, metav1.CreateOptions{})
+			if err != nil {
+				t.Fatalf("Unexpected error when creating pod: %v", err)
+				integration.DeletePodOrErrorf(t, adminClient, ns.Name, pod.Name)
+			}
+
+			// 2. Create a service account and fetch its client.
+			saClient := tc.serviceAccountFn(t, adminClient, server.ClientConfig, []rbacv1.PolicyRule{tc.serviceAccountRBAC})
+
+			// 3. Update pod and check whether it should be allowed.
+			resp.Spec.Containers[0].Image = "updated-image"
+			if _, err := saClient.CoreV1().Pods(ns.Name).Update(context.TODO(), resp, metav1.UpdateOptions{}); err == nil && !tc.allowUpdate {
+				t.Fatalf("Unexpected allowed pod update")
+				integration.DeletePodOrErrorf(t, adminClient, ns.Name, pod.Name)
+			} else if err != nil && tc.allowUpdate {
+				t.Fatalf("Unexpected error when updating pod container resources: %v", err)
+				integration.DeletePodOrErrorf(t, adminClient, ns.Name, pod.Name)
+			}
+
+			// 4. Resize pod container resource and check whether it should be allowed.
+			resp, err = adminClient.CoreV1().Pods(ns.Name).Get(context.TODO(), resp.Name, metav1.GetOptions{})
+			if err != nil {
+				t.Fatalf("Unexpected error when fetching the pod: %v", err)
+				integration.DeletePodOrErrorf(t, adminClient, ns.Name, pod.Name)
+			}
+			resp.Spec.Containers[0].Resources = v1.ResourceRequirements{
+				Requests: v1.ResourceList{
+					v1.ResourceEphemeralStorage: resource.MustParse("2Gi"),
+				},
+			}
+			_, err = saClient.CoreV1().Pods(ns.Name).UpdateResize(context.TODO(), resp.Name, resp, metav1.UpdateOptions{})
+			if tc.allowResize && err != nil {
+				t.Fatalf("Unexpected pod resize failure: %v", err)
+				integration.DeletePodOrErrorf(t, adminClient, ns.Name, pod.Name)
+			}
+			if !tc.allowResize && err == nil {
+				t.Fatalf("Unexpected pod resize success")
+				integration.DeletePodOrErrorf(t, adminClient, ns.Name, pod.Name)
+			}
+
+			// 5. Delete the test pod.
+			integration.DeletePodOrErrorf(t, adminClient, ns.Name, pod.Name)
+		})
+	}
+}
+
+func TestPodResize(t *testing.T) {
+	featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.InPlacePodVerticalScaling, true)
+	// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
+	server := kubeapiservertesting.StartTestServerOrDie(t, nil, framework.DefaultTestServerFlags(), framework.SharedEtcd())
+	defer server.TearDownFn()
+
+	client := clientset.NewForConfigOrDie(server.ClientConfig)
+
+	ns := framework.CreateNamespaceOrDie(client, "pod-resize", t)
+	defer framework.DeleteNamespaceOrDie(client, ns, t)
+
+	testPod := func(name string) *v1.Pod {
+		return &v1.Pod{
+			ObjectMeta: metav1.ObjectMeta{
+				Name: name,
+			},
+			Spec: v1.PodSpec{
+				Containers: []v1.Container{
+					{
+						Name:  "fake-name",
+						Image: "fakeimage",
+					},
+				},
+			},
+		}
+	}
+
+	resizeCases := []struct {
+		name        string
+		originalRes v1.ResourceRequirements
+		resize      v1.ResourceRequirements
+		valid       bool
+	}{
+		{
+			name: "cpu request change",
+			originalRes: v1.ResourceRequirements{
+				Requests: v1.ResourceList{
+					v1.ResourceCPU: resource.MustParse("10m"),
+				},
+			},
+			resize: v1.ResourceRequirements{
+				Requests: v1.ResourceList{
+					v1.ResourceCPU: resource.MustParse("20m"),
+				},
+			},
+			valid: true,
+		},
+		{
+			name: "memory request change",
+			originalRes: v1.ResourceRequirements{
+				Requests: v1.ResourceList{
+					v1.ResourceMemory: resource.MustParse("1Gi"),
+				},
+			},
+			resize: v1.ResourceRequirements{
+				Requests: v1.ResourceList{
+					v1.ResourceMemory: resource.MustParse("2Gi"),
+				},
+			},
+			valid: true,
+		},
+		{
+			name: "storage request change",
+			originalRes: v1.ResourceRequirements{
+				Requests: v1.ResourceList{
+					v1.ResourceEphemeralStorage: resource.MustParse("1Gi"),
+				},
+			},
+			resize: v1.ResourceRequirements{
+				Requests: v1.ResourceList{
+					v1.ResourceEphemeralStorage: resource.MustParse("2Gi"),
+				},
+			},
+			valid: false,
+		},
+	}
+
+	for _, tc := range resizeCases {
+		pod := testPod("resize")
+		pod.Spec.Containers[0].Resources = tc.originalRes
+		resp, err := client.CoreV1().Pods(ns.Name).Create(context.TODO(), pod, metav1.CreateOptions{})
+		if err != nil {
+			t.Fatalf("Unexpected error when creating pod: %v", err)
+			integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
+		}
+
+		// Part 1. Resize
+		resp.Spec.Containers[0].Resources = tc.resize
+		if _, err := client.CoreV1().Pods(ns.Name).Update(context.TODO(), resp, metav1.UpdateOptions{}); err == nil {
+			t.Fatalf("Unexpected allowed pod update")
+			integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
+		} else if !strings.Contains(err.Error(), "spec: Forbidden: pod updates may not change fields other than") {
+			t.Fatalf("Unexpected error when updating pod container resources: %v", err)
+			integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
+		}
+
+		resp, err = client.CoreV1().Pods(ns.Name).UpdateResize(context.TODO(), resp.Name, resp, metav1.UpdateOptions{})
+		if tc.valid && err != nil {
+			t.Fatalf("Unexpected pod resize failure: %v", err)
+			integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
+		}
+		if !tc.valid && err == nil {
+			t.Fatalf("Unexpected pod resize success")
+			integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
+		}
+
+		// Part 2. Rollback
+		if !tc.valid {
+			integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
+			continue
+		}
+		resp.Spec.Containers[0].Resources = tc.originalRes
+		_, err = client.CoreV1().Pods(ns.Name).UpdateResize(context.TODO(), resp.Name, resp, metav1.UpdateOptions{})
+		if tc.valid && err != nil {
+			t.Fatalf("Unexpected pod resize failure: %v", err)
+			integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
+		}
+		if !tc.valid && err == nil {
+			t.Fatalf("Unexpected pod resize success")
+			integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
+		}
+
+		integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
+	}
+
+	patchCases := []struct {
+		name        string
+		originalRes v1.ResourceRequirements
+		patchBody   string
+		patchType   types.PatchType
+		valid       bool
+	}{
+		{
+			name: "cpu request change (strategic)",
+			originalRes: v1.ResourceRequirements{
+				Requests: v1.ResourceList{
+					v1.ResourceCPU: resource.MustParse("10m"),
+				},
+			},
+			patchType: types.StrategicMergePatchType,
+			patchBody: `{
+				"spec":{
+					"containers":[
+						{
+							"name":"fake-name",
+							"resources": {
+								"requests": {
+									"cpu":"20m"
+								}
+							}
+						}
+					]
+				}
+			}`,
+			valid: true,
+		},
+		{
+			name: "cpu request change (merge)",
+			originalRes: v1.ResourceRequirements{
+				Requests: v1.ResourceList{
+					v1.ResourceCPU: resource.MustParse("10m"),
+				},
+			},
+			patchType: types.MergePatchType,
+			patchBody: `{
+				"spec":{
+					"containers":[
+						{
+							"name":"fake-name",
+							"resources": {
+								"requests": {
+									"cpu":"20m"
+								}
+							}
+						}
+					]
+				}
+			}`,
+			valid: true,
+		},
+		{
+			name: "cpu request change (JSON)",
+			originalRes: v1.ResourceRequirements{
+				Requests: v1.ResourceList{
+					v1.ResourceCPU: resource.MustParse("10m"),
+				},
+			},
+			patchType: types.JSONPatchType,
+			patchBody: `[{
+				"op":"add",
+				"path":"/spec/containers",
+				"value":[{
+					"name":"fake-name",
+					"resources": {
+						"requests": {
+							"cpu":"20m"
+						}
+					}
+				}]
+			}]`,
+			valid: true,
+		},
+		{
+			name: "storage request change (merge)",
+			originalRes: v1.ResourceRequirements{
+				Requests: v1.ResourceList{
+					v1.ResourceCPU: resource.MustParse("10m"),
+				},
+			},
+			patchType: types.MergePatchType,
+			patchBody: `{
+				"spec":{
+					"containers":[
+						{
+							"name":"fake-name",
+							"resources": {
+								"requests": {
+									"ephemeral-storage":"20m"
+								}
+							}
+						}
+					]
+				}
+			}`,
+			valid: false,
+		},
+	}
+
+	for _, tc := range patchCases {
+		pod := testPod("resize")
+		pod.Spec.Containers[0].Resources = tc.originalRes
+		if _, err := client.CoreV1().Pods(ns.Name).Create(context.TODO(), pod, metav1.CreateOptions{}); err != nil {
+			t.Fatalf("Unexpected error when creating pod: %v", err)
+			integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
+		}
+
+		if _, err := client.CoreV1().Pods(ns.Name).Patch(context.TODO(), pod.Name, tc.patchType, []byte(tc.patchBody), metav1.PatchOptions{}, "resize"); tc.valid && err != nil {
+			t.Fatalf("Unexpected pod resize failure: %v", err)
+			integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
+		} else if !tc.valid && err == nil {
+			t.Fatalf("Unexpected pod resize success")
+			integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
+		}
+		integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
+	}
+}
+
 func TestMutablePodSchedulingDirectives(t *testing.T) {
 	// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
 	server := kubeapiservertesting.StartTestServerOrDie(t, nil, framework.DefaultTestServerFlags(), framework.SharedEtcd())
diff --git a/test/integration/scheduler/queue_test.go b/test/integration/scheduler/queue_test.go
index f874c558b9d7e..78df6a7be27df 100644
--- a/test/integration/scheduler/queue_test.go
+++ b/test/integration/scheduler/queue_test.go
@@ -406,8 +406,8 @@ func TestCoreResourceEnqueue(t *testing.T) {
 			triggerFn: func(testCtx *testutils.TestContext) (map[framework.ClusterEvent]uint64, error) {
 				// Trigger a PodUpdate event by reducing cpu requested by pod1.
 				// It makes Pod1 schedulable.
-				if _, err := testCtx.ClientSet.CoreV1().Pods(testCtx.NS.Name).Update(testCtx.Ctx, st.MakePod().Name("pod1").Req(map[v1.ResourceName]string{v1.ResourceCPU: "2"}).Container("image").Obj(), metav1.UpdateOptions{}); err != nil {
-					return nil, fmt.Errorf("failed to update the pod: %w", err)
+				if _, err := testCtx.ClientSet.CoreV1().Pods(testCtx.NS.Name).UpdateResize(testCtx.Ctx, "pod1", st.MakePod().Name("pod1").Req(map[v1.ResourceName]string{v1.ResourceCPU: "2"}).Container("image").Obj(), metav1.UpdateOptions{}); err != nil {
+					return nil, fmt.Errorf("failed to resize the pod: %w", err)
 				}
 				return map[framework.ClusterEvent]uint64{{Resource: unschedulablePod, ActionType: framework.UpdatePodScaleDown}: 1}, nil
 			},