mirror of
https://github.com/kubernetes/kubernetes.git
synced 2026-05-28 04:04:39 -04:00
node: fix graph populator fast-path to check ExtendedResourceClaimStatus
Pods using DRAExtendedResource (e.g. nvidia.com/gpu) have no Spec.ResourceClaims, so ResourceClaimStatuses stays nil. The updatePod fast-path skipped AddPod when only ExtendedResourceClaimStatus changed, leaving the synthesized claim→pod→node edge out of the authorization graph. Add PodExtendedStatusEqual to the fast-path guard, matching what the scheduler event handler already does in events.go.
This commit is contained in:
parent
47f9904374
commit
2490cfa4f5
2 changed files with 102 additions and 1 deletions
|
|
@ -111,7 +111,8 @@ func (g *graphPopulator) updatePod(oldObj, obj interface{}) {
|
|||
hasNewEphemeralContainers := len(pod.Spec.EphemeralContainers) > len(oldPod.Spec.EphemeralContainers)
|
||||
if (pod.Spec.NodeName == oldPod.Spec.NodeName) && (pod.UID == oldPod.UID) &&
|
||||
!hasNewEphemeralContainers &&
|
||||
resourceclaim.PodStatusEqual(oldPod.Status.ResourceClaimStatuses, pod.Status.ResourceClaimStatuses) {
|
||||
resourceclaim.PodStatusEqual(oldPod.Status.ResourceClaimStatuses, pod.Status.ResourceClaimStatuses) &&
|
||||
resourceclaim.PodExtendedStatusEqual(oldPod.Status.ExtendedResourceClaimStatus, pod.Status.ExtendedResourceClaimStatus) {
|
||||
// Node and uid are unchanged, all object references in the pod spec are immutable respectively unmodified (claim statuses).
|
||||
klog.V(5).Infof("updatePod %s/%s, node unchanged", pod.Namespace, pod.Name)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -1058,6 +1058,106 @@ func TestNodeAuthorizerAddEphemeralContainers(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestNodeAuthorizerUpdateExtendedResourceClaim checks that a node gains
|
||||
// authorization to read its pod's synthesized ResourceClaim once the scheduler
|
||||
// writes ExtendedResourceClaimStatus into the pod — even when the pod carries
|
||||
// no standard Spec.ResourceClaims entries.
|
||||
//
|
||||
// Background: the graph populator's updatePod has a fast-path that skips
|
||||
// AddPod when the pod's node assignment, UID, ephemeral containers, and
|
||||
// ResourceClaimStatuses are all unchanged. For pods that use the
|
||||
// DRAExtendedResource path (e.g. a plain nvidia.com/gpu request),
|
||||
// ResourceClaimStatuses is nil both before and after the scheduler writes
|
||||
// the synthesized claim name, so the fast-path would fire prematurely and
|
||||
// the claim→pod→node edge would never be added to the authorization graph.
|
||||
func TestNodeAuthorizerUpdateExtendedResourceClaim(t *testing.T) {
|
||||
g := NewGraph()
|
||||
identifier := nodeidentifier.NewDefaultNodeIdentifier()
|
||||
authz := NewAuthorizer(g, identifier, bootstrappolicy.NodeRules())
|
||||
|
||||
node1 := &user.DefaultInfo{Name: "system:node:node1", Groups: []string{"system:nodes"}}
|
||||
|
||||
// The pod has been bound to node1, but the scheduler has not yet written
|
||||
// ExtendedResourceClaimStatus. There are no standard Spec.ResourceClaims,
|
||||
// so ResourceClaimStatuses stays nil throughout.
|
||||
pod := &corev1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod1",
|
||||
Namespace: "ns1",
|
||||
UID: "pod1uid",
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
NodeName: "node1",
|
||||
},
|
||||
}
|
||||
|
||||
p := &graphPopulator{}
|
||||
p.graph = g
|
||||
p.addPod(pod)
|
||||
|
||||
// Before the scheduler writes ExtendedResourceClaimStatus, the synthesized
|
||||
// claim is not in the graph and node1 should have no opinion on it.
|
||||
decision, _, err := authz.Authorize(context.Background(), authorizer.AttributesRecord{
|
||||
User: node1,
|
||||
ResourceRequest: true,
|
||||
Verb: "get",
|
||||
Resource: "resourceclaims",
|
||||
APIGroup: "resource.k8s.io",
|
||||
Namespace: "ns1",
|
||||
Name: "extended-claim-1",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if decision != authorizer.DecisionNoOpinion {
|
||||
t.Errorf("before ExtendedResourceClaimStatus is populated: want NoOpinion, got %v", decision)
|
||||
}
|
||||
|
||||
// The scheduler creates the ResourceClaim and records its name in the pod
|
||||
// status. updatePod must recognize that ExtendedResourceClaimStatus changed
|
||||
// and rebuild the graph edge rather than taking the fast-path early exit.
|
||||
updatedPod := pod.DeepCopy()
|
||||
updatedPod.Status.ExtendedResourceClaimStatus = &corev1.PodExtendedResourceClaimStatus{
|
||||
ResourceClaimName: "extended-claim-1",
|
||||
}
|
||||
p.updatePod(pod, updatedPod)
|
||||
|
||||
// The node that hosts the pod should now be permitted to read the claim.
|
||||
decision, _, err = authz.Authorize(context.Background(), authorizer.AttributesRecord{
|
||||
User: node1,
|
||||
ResourceRequest: true,
|
||||
Verb: "get",
|
||||
Resource: "resourceclaims",
|
||||
APIGroup: "resource.k8s.io",
|
||||
Namespace: "ns1",
|
||||
Name: "extended-claim-1",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if decision != authorizer.DecisionAllow {
|
||||
t.Errorf("after ExtendedResourceClaimStatus is populated: want Allow, got %v", decision)
|
||||
}
|
||||
|
||||
// A node that does not host the pod must not gain access to the claim.
|
||||
node2 := &user.DefaultInfo{Name: "system:node:node2", Groups: []string{"system:nodes"}}
|
||||
decision, _, err = authz.Authorize(context.Background(), authorizer.AttributesRecord{
|
||||
User: node2,
|
||||
ResourceRequest: true,
|
||||
Verb: "get",
|
||||
Resource: "resourceclaims",
|
||||
APIGroup: "resource.k8s.io",
|
||||
Namespace: "ns1",
|
||||
Name: "extended-claim-1",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if decision != authorizer.DecisionNoOpinion {
|
||||
t.Errorf("node2 should not access a claim belonging to node1's pod: want NoOpinion, got %v", decision)
|
||||
}
|
||||
}
|
||||
|
||||
type sampleDataOpts struct {
|
||||
nodes int
|
||||
namespaces int
|
||||
|
|
|
|||
Loading…
Reference in a new issue