Skip to content

Commit 357a292

Browse files
pohlyliggitt
andcommitted
DRA e2e: update VAP for a kubelet plugin
This fixes the message (node name and "cluster-scoped" were switched) and simplifies the VAP: - a single matchCondition short circuits completely unless they're a user we care about - variables to extract the userNodeName and objectNodeName once (using optionals to gracefully turn missing claims and fields into empty strings) - leaves very tiny concise validations Co-authored-by: Jordan Liggitt <liggitt@google.com>
1 parent 9f36c8d commit 357a292

File tree

2 files changed

+31
-26
lines changed

2 files changed

+31
-26
lines changed

test/e2e/dra/dra.go

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,7 +1197,16 @@ var _ = framework.SIGDescribe("node")("DRA", feature.DynamicResourceAllocation,
11971197
})
11981198

11991199
// Messages from test-driver/deploy/example/plugin-permissions.yaml
1200-
matchVAPDeniedError := gomega.MatchError(gomega.ContainSubstring("may only modify resourceslices that belong to the node the pod is running on"))
1200+
matchVAPDeniedError := func(nodeName string, slice *resourceapi.ResourceSlice) types.GomegaMatcher {
1201+
subStr := fmt.Sprintf("this user running on node '%s' may not modify ", nodeName)
1202+
switch {
1203+
case slice.Spec.NodeName != "":
1204+
subStr += fmt.Sprintf("resourceslices on node '%s'", slice.Spec.NodeName)
1205+
default:
1206+
subStr += "cluster resourceslices"
1207+
}
1208+
return gomega.MatchError(gomega.ContainSubstring(subStr))
1209+
}
12011210
mustCreate := func(clientSet kubernetes.Interface, clientName string, slice *resourceapi.ResourceSlice) *resourceapi.ResourceSlice {
12021211
ginkgo.GinkgoHelper()
12031212
slice, err := clientSet.ResourceV1alpha3().ResourceSlices().Create(ctx, slice, metav1.CreateOptions{})
@@ -1237,17 +1246,17 @@ var _ = framework.SIGDescribe("node")("DRA", feature.DynamicResourceAllocation,
12371246
}
12381247

12391248
// Create with different clients, keep it in the end.
1240-
mustFailToCreate(realNodeClient, "real plugin", fictionalNodeSlice, matchVAPDeniedError)
1249+
mustFailToCreate(realNodeClient, "real plugin", fictionalNodeSlice, matchVAPDeniedError(realNodeName, fictionalNodeSlice))
12411250
mustCreateAndDelete(fictionalNodeClient, "fictional plugin", fictionalNodeSlice)
12421251
createdFictionalNodeSlice := mustCreate(f.ClientSet, "admin", fictionalNodeSlice)
12431252

12441253
// Update with different clients.
1245-
mustFailToUpdate(realNodeClient, "real plugin", createdFictionalNodeSlice, matchVAPDeniedError)
1254+
mustFailToUpdate(realNodeClient, "real plugin", createdFictionalNodeSlice, matchVAPDeniedError(realNodeName, createdFictionalNodeSlice))
12461255
createdFictionalNodeSlice = mustUpdate(fictionalNodeClient, "fictional plugin", createdFictionalNodeSlice)
12471256
createdFictionalNodeSlice = mustUpdate(f.ClientSet, "admin", createdFictionalNodeSlice)
12481257

12491258
// Delete with different clients.
1250-
mustFailToDelete(realNodeClient, "real plugin", createdFictionalNodeSlice, matchVAPDeniedError)
1259+
mustFailToDelete(realNodeClient, "real plugin", createdFictionalNodeSlice, matchVAPDeniedError(realNodeName, createdFictionalNodeSlice))
12511260
mustDelete(fictionalNodeClient, "fictional plugin", createdFictionalNodeSlice)
12521261

12531262
// Now the same for a slice which is not associated with a node.
@@ -1272,18 +1281,18 @@ var _ = framework.SIGDescribe("node")("DRA", feature.DynamicResourceAllocation,
12721281
})
12731282

12741283
// Create with different clients, keep it in the end.
1275-
mustFailToCreate(realNodeClient, "real plugin", clusterSlice, matchVAPDeniedError)
1276-
mustFailToCreate(fictionalNodeClient, "fictional plugin", clusterSlice, matchVAPDeniedError)
1284+
mustFailToCreate(realNodeClient, "real plugin", clusterSlice, matchVAPDeniedError(realNodeName, clusterSlice))
1285+
mustFailToCreate(fictionalNodeClient, "fictional plugin", clusterSlice, matchVAPDeniedError(fictionalNodeName, clusterSlice))
12771286
createdClusterSlice := mustCreate(f.ClientSet, "admin", clusterSlice)
12781287

12791288
// Update with different clients.
1280-
mustFailToUpdate(realNodeClient, "real plugin", createdClusterSlice, matchVAPDeniedError)
1281-
mustFailToUpdate(fictionalNodeClient, "fictional plugin", createdClusterSlice, matchVAPDeniedError)
1289+
mustFailToUpdate(realNodeClient, "real plugin", createdClusterSlice, matchVAPDeniedError(realNodeName, createdClusterSlice))
1290+
mustFailToUpdate(fictionalNodeClient, "fictional plugin", createdClusterSlice, matchVAPDeniedError(fictionalNodeName, createdClusterSlice))
12821291
createdClusterSlice = mustUpdate(f.ClientSet, "admin", createdClusterSlice)
12831292

12841293
// Delete with different clients.
1285-
mustFailToDelete(realNodeClient, "real plugin", createdClusterSlice, matchVAPDeniedError)
1286-
mustFailToDelete(fictionalNodeClient, "fictional plugin", createdClusterSlice, matchVAPDeniedError)
1294+
mustFailToDelete(realNodeClient, "real plugin", createdClusterSlice, matchVAPDeniedError(realNodeName, createdClusterSlice))
1295+
mustFailToDelete(fictionalNodeClient, "fictional plugin", createdClusterSlice, matchVAPDeniedError(fictionalNodeName, createdClusterSlice))
12871296
mustDelete(f.ClientSet, "admin", createdClusterSlice)
12881297
})
12891298

test/e2e/dra/test-driver/deploy/example/plugin-permissions.yaml

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -50,29 +50,25 @@ spec:
5050
apiVersions: ["v1alpha3"]
5151
operations: ["CREATE", "UPDATE", "DELETE"]
5252
resources: ["resourceslices"]
53-
variables:
54-
- name: hasNodeName
55-
expression: >-
56-
"authentication.kubernetes.io/node-name" in request.userInfo.extra
57-
- name: isKubeletPlugin
53+
matchConditions:
54+
- name: isRestrictedUser
5855
expression: >-
5956
request.userInfo.username == "system:serviceaccount:dra-kubelet-plugin-namespace:dra-kubelet-plugin-service-account"
57+
variables:
58+
- name: userNodeName
59+
expression: >-
60+
request.userInfo.extra[?'authentication.kubernetes.io/node-name'][0].orValue('')
6061
- name: objectNodeName
6162
expression: >-
6263
(request.operation == "DELETE" ? oldObject : object).spec.?nodeName.orValue("")
6364
validations:
64-
- expression: >-
65-
!variables.isKubeletPlugin || variables.hasNodeName
66-
message: This user must have a "authentication.kubernetes.io/node-name" claim. ServiceAccountTokenNodeBindingValidation must be enabled in the cluster.
67-
- expression: >-
68-
!variables.isKubeletPlugin || !variables.hasNodeName ||
69-
variables.objectNodeName == request.userInfo.extra["authentication.kubernetes.io/node-name"][0]
70-
message: This DRA kubelet plugin may only modify resourceslices that belong to the node the pod is running on.
71-
# This is useful for debugging. Can be dropped in a production deployment.
65+
- expression: variables.userNodeName != ""
66+
message: >-
67+
no node association found for user, this user must run in a pod on a node and ServiceAccountTokenPodNodeInfo must be enabled
68+
- expression: variables.userNodeName == variables.objectNodeName
7269
messageExpression: >-
73-
"The DRA kubelet plugin on node " + request.userInfo.extra["authentication.kubernetes.io/node-name"][0] +
74-
" may only modify resourceslices that belong to the node the pod is running on, not " +
75-
(variables.objectNodeName == "" ? variables.objectNodeName : "a cluster-scoped slice") + "."
70+
"this user running on node '"+variables.userNodeName+"' may not modify " +
71+
(variables.objectNodeName == "" ?"cluster resourceslices" : "resourceslices on node '"+variables.objectNodeName+"'")
7672
---
7773
apiVersion: admissionregistration.k8s.io/v1
7874
kind: ValidatingAdmissionPolicyBinding

0 commit comments

Comments
 (0)