Merge pull request #131876 from pohly/automated-cherry-pick-of-#131844-origin-release-1.33

Automated cherry pick of #131844: DRA node: reject static pods which reference ResourceClaims
This commit is contained in:
Kubernetes Prow Robot 2025-06-04 11:02:42 -07:00 committed by GitHub
commit 6144faccba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 92 additions and 1 deletions

View File

@ -3038,6 +3038,13 @@ func gatherPodResourceClaimNames(claims []core.PodResourceClaim) sets.Set[string
}
func validatePodResourceClaim(podMeta *metav1.ObjectMeta, claim core.PodResourceClaim, podClaimNames *sets.Set[string], fldPath *field.Path) field.ErrorList {
// static pods don't support resource claims
if podMeta != nil {
if _, ok := podMeta.Annotations[core.MirrorPodAnnotationKey]; ok {
return field.ErrorList{field.Forbidden(field.NewPath(""), "static pods do not support resource claims")}
}
}
var allErrs field.ErrorList
if claim.Name == "" {
allErrs = append(allErrs, field.Required(fldPath.Child("name"), ""))

View File

@ -25321,6 +25321,8 @@ func TestValidateDynamicResourceAllocation(t *testing.T) {
}
failureCases := map[string]*core.Pod{
"static pod with resource claim reference": goodClaimReference,
"static pod with resource claim template": goodClaimTemplate,
"pod claim name with prefix": podtest.MakePod("",
podtest.SetResourceClaims(core.PodResourceClaim{
Name: "../my-claim",
@ -25450,7 +25452,14 @@ func TestValidateDynamicResourceAllocation(t *testing.T) {
}(),
}
for k, v := range failureCases {
if errs := ValidatePodSpec(&v.Spec, nil, field.NewPath("field"), PodValidationOptions{}); len(errs) == 0 {
podMeta := shortPodName
if strings.HasPrefix(k, "static pod") {
podMeta = podMeta.DeepCopy()
podMeta.Annotations = map[string]string{
core.MirrorPodAnnotationKey: "True",
}
}
if errs := ValidatePodSpec(&v.Spec, podMeta, field.NewPath("field"), PodValidationOptions{}); len(errs) == 0 {
t.Errorf("expected failure for %q", k)
}
}

View File

@ -106,6 +106,9 @@ type defaultFunc func(pod *api.Pod) error
// A static pod tried to use a ClusterTrustBundle projected volume source.
var ErrStaticPodTriedToUseClusterTrustBundle = errors.New("static pods may not use ClusterTrustBundle projected volume sources")
// A static pod tried to use a resource claim.
var ErrStaticPodTriedToUseResourceClaims = errors.New("static pods may not use ResourceClaims")
// tryDecodeSinglePod takes data and tries to extract valid Pod config information from it.
func tryDecodeSinglePod(data []byte, defaultFn defaultFunc) (parsed bool, pod *v1.Pod, err error) {
// JSON is valid YAML, so this should work for everything.
@ -152,6 +155,9 @@ func tryDecodeSinglePod(data []byte, defaultFn defaultFunc) (parsed bool, pod *v
}
}
}
if len(v1Pod.Spec.ResourceClaims) > 0 {
return true, nil, ErrStaticPodTriedToUseResourceClaims
}
return true, v1Pod, nil
}

View File

@ -180,6 +180,62 @@ func TestDecodeSinglePodRejectsClusterTrustBundleVolumes(t *testing.T) {
}
}
func TestDecodeSinglePodRejectsResourceClaims(t *testing.T) {
grace := int64(30)
enableServiceLinks := v1.DefaultEnableServiceLinks
pod := &v1.Pod{
TypeMeta: metav1.TypeMeta{
APIVersion: "",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test",
UID: "12345",
Namespace: "mynamespace",
},
Spec: v1.PodSpec{
RestartPolicy: v1.RestartPolicyAlways,
DNSPolicy: v1.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
Containers: []v1.Container{{
Name: "image",
Image: "test/image",
ImagePullPolicy: "IfNotPresent",
TerminationMessagePath: "/dev/termination-log",
TerminationMessagePolicy: v1.TerminationMessageReadFile,
SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(),
Resources: v1.ResourceRequirements{
Claims: []v1.ResourceClaim{{
Name: "my-claim",
}},
},
}},
ResourceClaims: []v1.PodResourceClaim{{
Name: "my-claim",
ResourceClaimName: ptr.To("some-external-claim"),
}},
SecurityContext: &v1.PodSecurityContext{},
SchedulerName: v1.DefaultSchedulerName,
EnableServiceLinks: &enableServiceLinks,
},
Status: v1.PodStatus{
PodIP: "1.2.3.4",
PodIPs: []v1.PodIP{
{
IP: "1.2.3.4",
},
},
},
}
json, err := runtime.Encode(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), pod)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
_, _, err = tryDecodeSinglePod(json, noDefault)
if !errors.Is(err, ErrStaticPodTriedToUseResourceClaims) {
t.Errorf("Got error %q, want %q", err, ErrStaticPodTriedToUseResourceClaims)
}
}
func TestDecodePodList(t *testing.T) {
grace := int64(30)
enableServiceLinks := v1.DefaultEnableServiceLinks

View File

@ -335,6 +335,10 @@ func (p *Plugin) admitPodCreate(nodeName string, a admission.Attributes) error {
}
}
if len(pod.Spec.ResourceClaims) > 0 {
return admission.NewForbidden(a, fmt.Errorf("node %q can not create pods that reference resourceclaims", nodeName))
}
return nil
}

View File

@ -574,6 +574,9 @@ func Test_nodePlugin_Admit(t *testing.T) {
pvcpod, _ := makeTestPod("ns", "mypvcpod", "mynode", true)
pvcpod.Spec.Volumes = []api.Volume{{VolumeSource: api.VolumeSource{PersistentVolumeClaim: &api.PersistentVolumeClaimVolumeSource{ClaimName: "foo"}}}}
claimpod, _ := makeTestPod("ns", "myclaimpod", "mynode", true)
claimpod.Spec.ResourceClaims = []api.PodResourceClaim{{Name: "myclaim", ResourceClaimName: pointer.String("myexternalclaim")}}
tests := []admitTestCase{
// Mirror pods bound to us
{
@ -1055,6 +1058,12 @@ func Test_nodePlugin_Admit(t *testing.T) {
attributes: admission.NewAttributesRecord(pvcpod, nil, podKind, pvcpod.Namespace, pvcpod.Name, podResource, "", admission.Create, &metav1.CreateOptions{}, false, mynode),
err: "reference persistentvolumeclaims",
},
{
name: "forbid create of pod referencing resourceclaim",
podsGetter: noExistingPods,
attributes: admission.NewAttributesRecord(claimpod, nil, podKind, claimpod.Namespace, claimpod.Name, podResource, "", admission.Create, &metav1.CreateOptions{}, false, mynode),
err: "reference resourceclaim",
},
// My node object
{