Skip to content

Commit 793d403

Browse files
Merge pull request #31064 from sabujmaity/feat/OCPNODE-4108-add-dra-example-e2e
OCPNODE-4108: add E2E tests for upstream dra-example-driver
2 parents cc8b969 + 212d420 commit 793d403

8 files changed

Lines changed: 1400 additions & 0 deletions

File tree

test/extended/include.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import (
4242
_ "github.com/openshift/origin/test/extended/machines"
4343
_ "github.com/openshift/origin/test/extended/networking"
4444
_ "github.com/openshift/origin/test/extended/node"
45+
_ "github.com/openshift/origin/test/extended/node/dra/example"
4546
_ "github.com/openshift/origin/test/extended/node/dra/nvidia"
4647
_ "github.com/openshift/origin/test/extended/node/node_e2e"
4748
_ "github.com/openshift/origin/test/extended/node_tuning"
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package common
2+
3+
import (
4+
"context"
5+
6+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
7+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
8+
"k8s.io/apimachinery/pkg/runtime"
9+
"k8s.io/apimachinery/pkg/runtime/schema"
10+
"k8s.io/client-go/dynamic"
11+
"k8s.io/utils/ptr"
12+
)
13+
14+
var (
15+
DeviceClassGVR = schema.GroupVersionResource{
16+
Group: "resource.k8s.io",
17+
Version: "v1",
18+
Resource: "deviceclasses",
19+
}
20+
ResourceClaimGVR = schema.GroupVersionResource{
21+
Group: "resource.k8s.io",
22+
Version: "v1",
23+
Resource: "resourceclaims",
24+
}
25+
ResourceClaimTemplateGVR = schema.GroupVersionResource{
26+
Group: "resource.k8s.io",
27+
Version: "v1",
28+
Resource: "resourceclaimtemplates",
29+
}
30+
)
31+
32+
// ConvertToUnstructured converts a typed object to Unstructured
33+
func ConvertToUnstructured(obj interface{}) (*unstructured.Unstructured, error) {
34+
unstructuredObj := &unstructured.Unstructured{}
35+
content, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
36+
if err != nil {
37+
return nil, err
38+
}
39+
unstructuredObj.Object = content
40+
return unstructuredObj, nil
41+
}
42+
43+
// CreateDeviceClass creates a DeviceClass
44+
func CreateDeviceClass(ctx context.Context, client dynamic.Interface, deviceClass interface{}) error {
45+
unstructuredObj, err := ConvertToUnstructured(deviceClass)
46+
if err != nil {
47+
return err
48+
}
49+
_, err = client.Resource(DeviceClassGVR).Create(ctx, unstructuredObj, metav1.CreateOptions{})
50+
return err
51+
}
52+
53+
// DeleteDeviceClass deletes a DeviceClass
54+
func DeleteDeviceClass(ctx context.Context, client dynamic.Interface, name string) error {
55+
return client.Resource(DeviceClassGVR).Delete(ctx, name, metav1.DeleteOptions{
56+
GracePeriodSeconds: ptr.To[int64](0),
57+
})
58+
}
59+
60+
// CreateResourceClaim creates a ResourceClaim
61+
func CreateResourceClaim(ctx context.Context, client dynamic.Interface, namespace string, claim interface{}) error {
62+
unstructuredObj, err := ConvertToUnstructured(claim)
63+
if err != nil {
64+
return err
65+
}
66+
_, err = client.Resource(ResourceClaimGVR).Namespace(namespace).Create(ctx, unstructuredObj, metav1.CreateOptions{})
67+
return err
68+
}
69+
70+
// DeleteResourceClaim deletes a ResourceClaim
71+
func DeleteResourceClaim(ctx context.Context, client dynamic.Interface, namespace, name string) error {
72+
return client.Resource(ResourceClaimGVR).Namespace(namespace).Delete(ctx, name, metav1.DeleteOptions{
73+
GracePeriodSeconds: ptr.To[int64](0),
74+
})
75+
}
76+
77+
// CreateResourceClaimTemplate creates a ResourceClaimTemplate
78+
func CreateResourceClaimTemplate(ctx context.Context, client dynamic.Interface, namespace string, template interface{}) error {
79+
unstructuredObj, err := ConvertToUnstructured(template)
80+
if err != nil {
81+
return err
82+
}
83+
_, err = client.Resource(ResourceClaimTemplateGVR).Namespace(namespace).Create(ctx, unstructuredObj, metav1.CreateOptions{})
84+
return err
85+
}
86+
87+
// DeleteResourceClaimTemplate deletes a ResourceClaimTemplate
88+
func DeleteResourceClaimTemplate(ctx context.Context, client dynamic.Interface, namespace, name string) error {
89+
return client.Resource(ResourceClaimTemplateGVR).Namespace(namespace).Delete(ctx, name, metav1.DeleteOptions{
90+
GracePeriodSeconds: ptr.To[int64](0),
91+
})
92+
}
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
package common
2+
3+
import (
4+
"fmt"
5+
6+
corev1 "k8s.io/api/core/v1"
7+
resourceapi "k8s.io/api/resource/v1"
8+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9+
"k8s.io/utils/ptr"
10+
)
11+
12+
// DriverConfig holds driver-specific parameters for building DRA test resources
13+
type DriverConfig struct {
14+
DriverName string
15+
DefaultClass string
16+
RequestName string
17+
ContainerImage string
18+
ContainerCommand []string
19+
LongRunCommand []string
20+
}
21+
22+
// ResourceBuilder helps build DRA resource objects
23+
type ResourceBuilder struct {
24+
namespace string
25+
config DriverConfig
26+
}
27+
28+
// NewResourceBuilder creates a new builder
29+
func NewResourceBuilder(namespace string, config DriverConfig) *ResourceBuilder {
30+
return &ResourceBuilder{namespace: namespace, config: config}
31+
}
32+
33+
// BuildDeviceClass creates a DeviceClass for the configured driver
34+
func (rb *ResourceBuilder) BuildDeviceClass(name string) *resourceapi.DeviceClass {
35+
if name == "" {
36+
name = rb.config.DefaultClass
37+
}
38+
39+
return &resourceapi.DeviceClass{
40+
ObjectMeta: metav1.ObjectMeta{
41+
Name: name,
42+
},
43+
Spec: resourceapi.DeviceClassSpec{
44+
Selectors: []resourceapi.DeviceSelector{
45+
{
46+
CEL: &resourceapi.CELDeviceSelector{
47+
Expression: fmt.Sprintf("device.driver == %q", rb.config.DriverName),
48+
},
49+
},
50+
},
51+
},
52+
}
53+
}
54+
55+
// BuildResourceClaim creates a ResourceClaim requesting devices
56+
func (rb *ResourceBuilder) BuildResourceClaim(name, deviceClassName string, count int) *resourceapi.ResourceClaim {
57+
if count <= 0 {
58+
panic(fmt.Sprintf("BuildResourceClaim: count must be > 0, got %d", count))
59+
}
60+
if deviceClassName == "" {
61+
deviceClassName = rb.config.DefaultClass
62+
}
63+
64+
return &resourceapi.ResourceClaim{
65+
ObjectMeta: metav1.ObjectMeta{
66+
Name: name,
67+
Namespace: rb.namespace,
68+
},
69+
Spec: resourceapi.ResourceClaimSpec{
70+
Devices: resourceapi.DeviceClaim{
71+
Requests: []resourceapi.DeviceRequest{
72+
{
73+
Name: rb.config.RequestName,
74+
Exactly: &resourceapi.ExactDeviceRequest{
75+
DeviceClassName: deviceClassName,
76+
Count: int64(count),
77+
},
78+
},
79+
},
80+
},
81+
},
82+
}
83+
}
84+
85+
// BuildPodWithClaim creates a Pod that uses a ResourceClaim
86+
func (rb *ResourceBuilder) BuildPodWithClaim(name, claimName, img string) *corev1.Pod {
87+
if img == "" {
88+
img = rb.config.ContainerImage
89+
}
90+
91+
return &corev1.Pod{
92+
ObjectMeta: metav1.ObjectMeta{
93+
Name: name,
94+
Namespace: rb.namespace,
95+
},
96+
Spec: corev1.PodSpec{
97+
RestartPolicy: corev1.RestartPolicyNever,
98+
Containers: []corev1.Container{
99+
{
100+
Name: "test-container",
101+
Image: img,
102+
Command: rb.config.ContainerCommand,
103+
Resources: corev1.ResourceRequirements{
104+
Claims: []corev1.ResourceClaim{
105+
{
106+
Name: rb.config.RequestName,
107+
},
108+
},
109+
},
110+
SecurityContext: &corev1.SecurityContext{
111+
AllowPrivilegeEscalation: ptr.To(false),
112+
Capabilities: &corev1.Capabilities{
113+
Drop: []corev1.Capability{"ALL"},
114+
},
115+
},
116+
},
117+
},
118+
ResourceClaims: []corev1.PodResourceClaim{
119+
{
120+
Name: rb.config.RequestName,
121+
ResourceClaimName: &claimName,
122+
},
123+
},
124+
},
125+
}
126+
}
127+
128+
// BuildLongRunningPodWithClaim creates a long-running Pod for testing
129+
func (rb *ResourceBuilder) BuildLongRunningPodWithClaim(name, claimName, img string) *corev1.Pod {
130+
pod := rb.BuildPodWithClaim(name, claimName, img)
131+
pod.Spec.Containers[0].Command = rb.config.LongRunCommand
132+
return pod
133+
}
134+
135+
// BuildPodWithInlineClaim creates a Pod with inline ResourceClaim
136+
func (rb *ResourceBuilder) BuildPodWithInlineClaim(name string) *corev1.Pod {
137+
templateName := name + "-template"
138+
pod := rb.BuildPodWithClaim(name, "", "")
139+
pod.Spec.ResourceClaims[0].ResourceClaimName = nil
140+
pod.Spec.ResourceClaims[0].ResourceClaimTemplateName = &templateName
141+
return pod
142+
}
143+
144+
// BuildResourceClaimTemplate creates a ResourceClaimTemplate
145+
func (rb *ResourceBuilder) BuildResourceClaimTemplate(name, deviceClassName string, count int) *resourceapi.ResourceClaimTemplate {
146+
if count <= 0 {
147+
panic(fmt.Sprintf("BuildResourceClaimTemplate: count must be > 0, got %d", count))
148+
}
149+
if deviceClassName == "" {
150+
deviceClassName = rb.config.DefaultClass
151+
}
152+
153+
return &resourceapi.ResourceClaimTemplate{
154+
ObjectMeta: metav1.ObjectMeta{
155+
Name: name,
156+
Namespace: rb.namespace,
157+
},
158+
Spec: resourceapi.ResourceClaimTemplateSpec{
159+
Spec: resourceapi.ResourceClaimSpec{
160+
Devices: resourceapi.DeviceClaim{
161+
Requests: []resourceapi.DeviceRequest{
162+
{
163+
Name: rb.config.RequestName,
164+
Exactly: &resourceapi.ExactDeviceRequest{
165+
DeviceClassName: deviceClassName,
166+
Count: int64(count),
167+
},
168+
},
169+
},
170+
},
171+
},
172+
},
173+
}
174+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
approvers:
2+
- sairameshv
3+
- harche
4+
- haircommander
5+
- rphillips
6+
- mrunalp
7+
8+
reviewers:
9+
- sairameshv
10+
- harche
11+
- haircommander
12+
- rphillips
13+
- mrunalp
14+
15+
labels:
16+
- sig/scheduling
17+
- area/dra

0 commit comments

Comments
 (0)