Skip to content

Commit 9c0cd6c

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 <[email protected]>
1 parent 7d46d58 commit 9c0cd6c

File tree

2 files changed

+31
-26
lines changed

2 files changed

+31
-26
lines changed

test/e2e/dra/dra.go

+19-10
Original file line numberDiff line numberDiff line change
@@ -1184,7 +1184,16 @@ var _ = framework.SIGDescribe("node")("DRA", feature.DynamicResourceAllocation,
11841184
})
11851185

11861186
// Messages from test-driver/deploy/example/plugin-permissions.yaml
1187-
matchVAPDeniedError := gomega.MatchError(gomega.ContainSubstring("may only modify resourceslices that belong to the node the pod is running on"))
1187+
matchVAPDeniedError := func(nodeName string, slice *resourceapi.ResourceSlice) types.GomegaMatcher {
1188+
subStr := fmt.Sprintf("this user running on node '%s' may not modify ", nodeName)
1189+
switch {
1190+
case slice.Spec.NodeName != "":
1191+
subStr += fmt.Sprintf("resourceslices on node '%s'", slice.Spec.NodeName)
1192+
default:
1193+
subStr += "cluster resourceslices"
1194+
}
1195+
return gomega.MatchError(gomega.ContainSubstring(subStr))
1196+
}
11881197
mustCreate := func(clientSet kubernetes.Interface, clientName string, slice *resourceapi.ResourceSlice) *resourceapi.ResourceSlice {
11891198
ginkgo.GinkgoHelper()
11901199
slice, err := clientSet.ResourceV1alpha3().ResourceSlices().Create(ctx, slice, metav1.CreateOptions{})
@@ -1224,17 +1233,17 @@ var _ = framework.SIGDescribe("node")("DRA", feature.DynamicResourceAllocation,
12241233
}
12251234

12261235
// Create with different clients, keep it in the end.
1227-
mustFailToCreate(realNodeClient, "real plugin", fictionalNodeSlice, matchVAPDeniedError)
1236+
mustFailToCreate(realNodeClient, "real plugin", fictionalNodeSlice, matchVAPDeniedError(realNodeName, fictionalNodeSlice))
12281237
mustCreateAndDelete(fictionalNodeClient, "fictional plugin", fictionalNodeSlice)
12291238
createdFictionalNodeSlice := mustCreate(f.ClientSet, "admin", fictionalNodeSlice)
12301239

12311240
// Update with different clients.
1232-
mustFailToUpdate(realNodeClient, "real plugin", createdFictionalNodeSlice, matchVAPDeniedError)
1241+
mustFailToUpdate(realNodeClient, "real plugin", createdFictionalNodeSlice, matchVAPDeniedError(realNodeName, createdFictionalNodeSlice))
12331242
createdFictionalNodeSlice = mustUpdate(fictionalNodeClient, "fictional plugin", createdFictionalNodeSlice)
12341243
createdFictionalNodeSlice = mustUpdate(f.ClientSet, "admin", createdFictionalNodeSlice)
12351244

12361245
// Delete with different clients.
1237-
mustFailToDelete(realNodeClient, "real plugin", createdFictionalNodeSlice, matchVAPDeniedError)
1246+
mustFailToDelete(realNodeClient, "real plugin", createdFictionalNodeSlice, matchVAPDeniedError(realNodeName, createdFictionalNodeSlice))
12381247
mustDelete(fictionalNodeClient, "fictional plugin", createdFictionalNodeSlice)
12391248

12401249
// Now the same for a slice which is not associated with a node.
@@ -1259,18 +1268,18 @@ var _ = framework.SIGDescribe("node")("DRA", feature.DynamicResourceAllocation,
12591268
})
12601269

12611270
// Create with different clients, keep it in the end.
1262-
mustFailToCreate(realNodeClient, "real plugin", clusterSlice, matchVAPDeniedError)
1263-
mustFailToCreate(fictionalNodeClient, "fictional plugin", clusterSlice, matchVAPDeniedError)
1271+
mustFailToCreate(realNodeClient, "real plugin", clusterSlice, matchVAPDeniedError(realNodeName, clusterSlice))
1272+
mustFailToCreate(fictionalNodeClient, "fictional plugin", clusterSlice, matchVAPDeniedError(fictionalNodeName, clusterSlice))
12641273
createdClusterSlice := mustCreate(f.ClientSet, "admin", clusterSlice)
12651274

12661275
// Update with different clients.
1267-
mustFailToUpdate(realNodeClient, "real plugin", createdClusterSlice, matchVAPDeniedError)
1268-
mustFailToUpdate(fictionalNodeClient, "fictional plugin", createdClusterSlice, matchVAPDeniedError)
1276+
mustFailToUpdate(realNodeClient, "real plugin", createdClusterSlice, matchVAPDeniedError(realNodeName, createdClusterSlice))
1277+
mustFailToUpdate(fictionalNodeClient, "fictional plugin", createdClusterSlice, matchVAPDeniedError(fictionalNodeName, createdClusterSlice))
12691278
createdClusterSlice = mustUpdate(f.ClientSet, "admin", createdClusterSlice)
12701279

12711280
// Delete with different clients.
1272-
mustFailToDelete(realNodeClient, "real plugin", createdClusterSlice, matchVAPDeniedError)
1273-
mustFailToDelete(fictionalNodeClient, "fictional plugin", createdClusterSlice, matchVAPDeniedError)
1281+
mustFailToDelete(realNodeClient, "real plugin", createdClusterSlice, matchVAPDeniedError(realNodeName, createdClusterSlice))
1282+
mustFailToDelete(fictionalNodeClient, "fictional plugin", createdClusterSlice, matchVAPDeniedError(fictionalNodeName, createdClusterSlice))
12741283
mustDelete(f.ClientSet, "admin", createdClusterSlice)
12751284
})
12761285

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

+12-16
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)