Skip to content

Commit 306e0cc

Browse files
committed
Support Claw CR idling
1 parent b57dc7a commit 306e0cc

4 files changed

Lines changed: 119 additions & 1 deletion

File tree

deploy/crds/README.adoc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,7 @@ Copy from a cluster with CNV operator installed
1010
Copy from a cluster with Ansible Automation Platform operator installed
1111

1212
== serving CRDs
13-
Copy from a cluster with Serverless operator installed
13+
Copy from a cluster with Serverless operator installed
14+
15+
== claws CRD
16+
Copy from the claw-operator repo (config/crd/bases/claw.sandbox.redhat.com_claws.yaml)
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
kind: CustomResourceDefinition
2+
apiVersion: apiextensions.k8s.io/v1
3+
metadata:
4+
name: claws.claw.sandbox.redhat.com
5+
spec:
6+
group: claw.sandbox.redhat.com
7+
names:
8+
plural: claws
9+
singular: claw
10+
kind: Claw
11+
listKind: ClawList
12+
scope: Namespaced
13+
versions:
14+
- name: v1alpha1
15+
served: true
16+
storage: true
17+
schema:
18+
openAPIV3Schema:
19+
description: Claw is the Schema for the claws API
20+
type: object
21+
properties:
22+
apiVersion:
23+
type: string
24+
kind:
25+
type: string
26+
metadata:
27+
type: object
28+
spec:
29+
description: Spec defines the desired state of Claw
30+
type: object
31+
properties:
32+
idle:
33+
description: Scale down replicas to put Claw into an idle mode
34+
type: boolean
35+
status:
36+
description: Status defines the observed state of Claw
37+
type: object
38+
x-kubernetes-preserve-unknown-fields: true
39+
subresources:
40+
status: {}

test/e2e/parallel/user_workloads_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ func TestIdlerAndPriorityClass(t *testing.T) {
101101
_, err = memberAwait.WaitForAAP(t, "test-idler-aap", idler.Name, clnt.Resource(aapRes), true)
102102
require.NoError(t, err)
103103

104+
// Wait for the Claw resource to be idled (spec.idle: true)
105+
_, err = memberAwait.WaitForClaw(t, "test-idler-claw", idler.Name, clnt.Resource(clawRes), true)
106+
require.NoError(t, err)
107+
104108
// Wait for the InferenceService to be deleted - the expected action to idle
105109
// the workload is by deleting the InferenceService that is old enough.
106110
// The pods are idled as well, which is verified in the previous step - after some time,
@@ -181,6 +185,9 @@ func prepareWorkloads(t *testing.T, memberAwait *wait.MemberAwaitility, namespac
181185
servingRuntimeDeployment := createKServeWorkloads(t, memberAwait, "test-idler-kserve", namespace)
182186
n = n + int(*servingRuntimeDeployment.Spec.Replicas)
183187

188+
clawDeployment := createClaw(t, memberAwait, "test-idler-claw", namespace)
189+
n = n + int(*clawDeployment.Spec.Replicas)
190+
184191
pods, err := memberAwait.WaitForPods(t, namespace, n, append(additionalPodCriteria, wait.PodRunning(),
185192
wait.WithPodLabel("idler", "idler"))...)
186193
require.NoError(t, err)
@@ -208,6 +215,7 @@ func createDeployment(t *testing.T, memberAwait *wait.MemberAwaitility, namespac
208215
}
209216

210217
var aapRes = schema.GroupVersionResource{Group: "aap.ansible.com", Version: "v1alpha1", Resource: "ansibleautomationplatforms"}
218+
var clawRes = schema.GroupVersionResource{Group: "claw.sandbox.redhat.com", Version: "v1alpha1", Resource: "claws"}
211219
var servingRuntimeRes = schema.GroupVersionResource{Group: "serving.kserve.io", Version: "v1alpha1", Resource: "servingruntimes"}
212220
var inferenceServiceRes = schema.GroupVersionResource{Group: "serving.kserve.io", Version: "v1beta1", Resource: "inferenceservices"}
213221
var dataVolumeRes = schema.GroupVersionResource{Group: "cdi.kubevirt.io", Version: "v1beta1", Resource: "datavolumes"}
@@ -244,6 +252,51 @@ func createAAP(t *testing.T, memberAwait *wait.MemberAwaitility, name, namespace
244252
return deployment
245253
}
246254

255+
// createClaw creates an instance of claws.claw.sandbox.redhat.com with one deployment owned by this instance
256+
// returns the underlying deployment
257+
func createClaw(t *testing.T, memberAwait *wait.MemberAwaitility, name, namespace string) *appsv1.Deployment {
258+
clnt, err := dynamic.NewForConfig(memberAwait.RestConfig)
259+
require.NoError(t, err)
260+
261+
claw := clawResource(name)
262+
createdClaw, err := clnt.Resource(clawRes).Namespace(namespace).Create(context.TODO(), claw, metav1.CreateOptions{})
263+
require.NoError(t, err)
264+
265+
replicas := int32(2)
266+
deployment := &appsv1.Deployment{
267+
ObjectMeta: metav1.ObjectMeta{
268+
Name: name,
269+
Namespace: namespace,
270+
},
271+
Spec: appsv1.DeploymentSpec{
272+
Selector: &metav1.LabelSelector{MatchLabels: selectorLabels(name)},
273+
Replicas: &replicas,
274+
Template: podTemplateSpec(name),
275+
},
276+
}
277+
err = controllerutil.SetOwnerReference(createdClaw, deployment, scheme.Scheme)
278+
require.NoError(t, err)
279+
err = memberAwait.Create(t, deployment)
280+
require.NoError(t, err)
281+
282+
return deployment
283+
}
284+
285+
func clawResource(name string) *unstructured.Unstructured {
286+
return &unstructured.Unstructured{
287+
Object: map[string]interface{}{
288+
"apiVersion": "claw.sandbox.redhat.com/v1alpha1",
289+
"kind": "Claw",
290+
"metadata": map[string]interface{}{
291+
"name": name,
292+
},
293+
"spec": map[string]interface{}{
294+
"idle": false,
295+
},
296+
},
297+
}
298+
}
299+
247300
func createReplicaSet(t *testing.T, memberAwait *wait.MemberAwaitility, namespace string) *appsv1.ReplicaSet {
248301
// Standalone ReplicaSet
249302
replicas := int32(2)

testsupport/wait/member.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1541,6 +1541,28 @@ func (a *MemberAwaitility) WaitForAAP(t *testing.T, name, namespace string, aapR
15411541
return aap, err
15421542
}
15431543

1544+
// WaitForClaw waits for the Claw resource to reach the expected idle state (spec.idle)
1545+
func (a *MemberAwaitility) WaitForClaw(t *testing.T, name, namespace string, clawRes dynamic.NamespaceableResourceInterface, expectedIdled bool) (*unstructured.Unstructured, error) {
1546+
t.Logf("waiting for Claw '%s' in namespace '%s'", name, namespace)
1547+
var claw *unstructured.Unstructured
1548+
err := wait.PollUntilContextTimeout(context.TODO(), a.RetryInterval, a.Timeout, true, func(ctx context.Context) (bool, error) {
1549+
var err error
1550+
claw, err = clawRes.Namespace(namespace).Get(context.Background(), name, metav1.GetOptions{})
1551+
if err != nil {
1552+
if errors.IsNotFound(err) {
1553+
return false, nil
1554+
}
1555+
return false, err
1556+
}
1557+
idled, _, err := unstructured.NestedBool(claw.UnstructuredContent(), "spec", "idle")
1558+
if err != nil {
1559+
return true, err
1560+
}
1561+
return expectedIdled == idled, nil
1562+
})
1563+
return claw, err
1564+
}
1565+
15441566
// WaitUntilInferenceServiceDeleted waits for the InferenceService resource to be deleted (idled)
15451567
func (a *MemberAwaitility) WaitUntilInferenceServiceDeleted(t *testing.T, name, namespace string, inferenceServiceRes dynamic.NamespaceableResourceInterface) error {
15461568
t.Logf("waiting for InferenceService '%s' to be deleted in namespace '%s'", name, namespace)

0 commit comments

Comments
 (0)