-
Notifications
You must be signed in to change notification settings - Fork 61
Adding instascale e2e test #271
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
openshift-ci
merged 15 commits into
project-codeflare:main
from
Fiona-Waters:instascale-e2e-tests
Oct 6, 2023
Merged
Changes from 11 commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
126995f
Adding instascale e2e test
Fiona-Waters d1ebfb1
update to test
Fiona-Waters b4d4e4e
refactored to check for specific machine names
Fiona-Waters 72e7f06
updating machine sets functionality
Fiona-Waters 5d193c7
update vendor files
Fiona-Waters 1e4a3f2
refactored test just for machine pools
Fiona-Waters 88d1ceb
moving common instascale test functions to separate file
Fiona-Waters c133dba
addressing feedback
Fiona-Waters 348bd00
fixing PR checks
Fiona-Waters e7a93b6
Refactor Machine pool functions
sutaakar ced9b72
Move OSD cluster ID into codeflare.go
sutaakar 868ff12
addressing feedback
Fiona-Waters 3bdd35c
Add missing licence headers to InstaScale test files
sutaakar a34ea19
skip test if not OSD
Fiona-Waters ff040e3
addressing feedback
Fiona-Waters File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
package e2e | ||
|
||
import ( | ||
. "github.com/onsi/gomega" | ||
mcadv1beta1 "github.com/project-codeflare/multi-cluster-app-dispatcher/pkg/apis/controller/v1beta1" | ||
|
||
batchv1 "k8s.io/api/batch/v1" | ||
corev1 "k8s.io/api/core/v1" | ||
"k8s.io/apimachinery/pkg/api/resource" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
|
||
. "github.com/project-codeflare/codeflare-operator/test/support" | ||
) | ||
|
||
func createInstaScaleJobAppWrapper(test Test, namespace *corev1.Namespace, config *corev1.ConfigMap) (*batchv1.Job, *mcadv1beta1.AppWrapper, error) { | ||
// Batch Job | ||
job := &batchv1.Job{ | ||
TypeMeta: metav1.TypeMeta{ | ||
APIVersion: batchv1.SchemeGroupVersion.String(), | ||
Kind: "Job", | ||
}, | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: "mnist", | ||
Namespace: namespace.Name, | ||
}, | ||
Spec: batchv1.JobSpec{ | ||
Completions: Ptr(int32(1)), | ||
Parallelism: Ptr(int32(1)), | ||
Template: corev1.PodTemplateSpec{ | ||
Spec: corev1.PodSpec{ | ||
Containers: []corev1.Container{ | ||
{ | ||
Name: "job", | ||
Image: GetPyTorchImage(), | ||
Env: []corev1.EnvVar{ | ||
{Name: "PYTHONUSERBASE", Value: "/workdir"}, | ||
}, | ||
Command: []string{"/bin/sh", "-c", "pip install -r /test/requirements.txt && torchrun /test/mnist.py"}, | ||
Args: []string{"$PYTHONUSERBASE"}, | ||
VolumeMounts: []corev1.VolumeMount{ | ||
{ | ||
Name: "test", | ||
MountPath: "/test", | ||
}, | ||
{ | ||
Name: "workdir", | ||
MountPath: "/workdir", | ||
}, | ||
}, | ||
WorkingDir: "/workdir", | ||
}, | ||
}, | ||
Volumes: []corev1.Volume{ | ||
{ | ||
Name: "test", | ||
VolumeSource: corev1.VolumeSource{ | ||
ConfigMap: &corev1.ConfigMapVolumeSource{ | ||
LocalObjectReference: corev1.LocalObjectReference{ | ||
Name: config.Name, | ||
}, | ||
}, | ||
}, | ||
}, | ||
{ | ||
Name: "workdir", | ||
VolumeSource: corev1.VolumeSource{ | ||
EmptyDir: &corev1.EmptyDirVolumeSource{}, | ||
}, | ||
}, | ||
}, | ||
RestartPolicy: corev1.RestartPolicyNever, | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
// create an appwrapper | ||
aw := &mcadv1beta1.AppWrapper{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: "test-instascale", | ||
Namespace: namespace.Name, | ||
Labels: map[string]string{ | ||
"orderedinstance": "g4dn.xlarge", | ||
}, | ||
}, | ||
Spec: mcadv1beta1.AppWrapperSpec{ | ||
AggrResources: mcadv1beta1.AppWrapperResourceList{ | ||
GenericItems: []mcadv1beta1.AppWrapperGenericResource{ | ||
{ | ||
CustomPodResources: []mcadv1beta1.CustomPodResourceTemplate{ | ||
{ | ||
Replicas: 1, | ||
Requests: corev1.ResourceList{ | ||
corev1.ResourceCPU: resource.MustParse("250m"), | ||
corev1.ResourceMemory: resource.MustParse("512Mi"), | ||
"nvidia.com/gpu": resource.MustParse("1"), | ||
}, | ||
Limits: corev1.ResourceList{ | ||
corev1.ResourceCPU: resource.MustParse("500m"), | ||
corev1.ResourceMemory: resource.MustParse("1G"), | ||
"nvidia.com/gpu": resource.MustParse("1"), | ||
}, | ||
}, | ||
{ | ||
Replicas: 1, | ||
Requests: corev1.ResourceList{ | ||
corev1.ResourceCPU: resource.MustParse("250m"), | ||
corev1.ResourceMemory: resource.MustParse("512Mi"), | ||
}, | ||
Limits: corev1.ResourceList{ | ||
corev1.ResourceCPU: resource.MustParse("500m"), | ||
corev1.ResourceMemory: resource.MustParse("1G"), | ||
}, | ||
}, | ||
}, | ||
GenericTemplate: Raw(test, job), | ||
CompletionStatus: "Complete", | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
_, err := test.Client().MCAD().WorkloadV1beta1().AppWrappers(namespace.Name).Create(test.Ctx(), aw, metav1.CreateOptions{}) | ||
test.Expect(err).NotTo(HaveOccurred()) | ||
test.T().Logf("AppWrapper created successfully %s/%s", aw.Namespace, aw.Name) | ||
|
||
test.Eventually(AppWrapper(test, namespace, aw.Name), TestTimeoutGpuProvisioning). | ||
Fiona-Waters marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Should(WithTransform(AppWrapperState, Equal(mcadv1beta1.AppWrapperStateActive))) | ||
|
||
return job, aw, err | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package e2e | ||
|
||
import ( | ||
"testing" | ||
|
||
. "github.com/onsi/gomega" | ||
mcadv1beta1 "github.com/project-codeflare/multi-cluster-app-dispatcher/pkg/apis/controller/v1beta1" | ||
|
||
batchv1 "k8s.io/api/batch/v1" | ||
corev1 "k8s.io/api/core/v1" | ||
|
||
. "github.com/project-codeflare/codeflare-operator/test/support" | ||
) | ||
|
||
func TestInstascaleMachinePool(t *testing.T) { | ||
|
||
Fiona-Waters marked this conversation as resolved.
Show resolved
Hide resolved
|
||
test := With(t) | ||
test.T().Parallel() | ||
|
||
namespace := test.NewTestNamespace() | ||
|
||
// Test configuration | ||
testConfigData := map[string][]byte{ | ||
Fiona-Waters marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// pip requirements | ||
"requirements.txt": ReadFile(test, "mnist_pip_requirements.txt"), | ||
// MNIST training script | ||
"mnist.py": ReadFile(test, "mnist.py"), | ||
} | ||
cm := CreateConfigMap(test, namespace.Name, testConfigData) | ||
|
||
//create OCM connection | ||
connection := CreateOCMConnection(test) | ||
|
||
Fiona-Waters marked this conversation as resolved.
Show resolved
Hide resolved
|
||
defer connection.Close() | ||
|
||
// check existing cluster machine pool resources | ||
// look for machine pool with aw name - expect not to find it | ||
test.Expect(GetMachinePools(test, connection)). | ||
ShouldNot(ContainElement(WithTransform(MachinePoolId, Equal("test-instascale-g4dn-xlarge")))) | ||
|
||
// Setup batch job and AppWrapper | ||
job, aw, err := createInstaScaleJobAppWrapper(test, namespace, cm) | ||
test.Expect(err).NotTo(HaveOccurred()) | ||
|
||
// look for machine pool with aw name - expect to find it | ||
test.Eventually(MachinePools(test, connection), TestTimeoutLong). | ||
Should(ContainElement(WithTransform(MachinePoolId, Equal("test-instascale-g4dn-xlarge")))) | ||
|
||
// Assert that the job has completed | ||
test.T().Logf("Waiting for Job %s/%s to complete", job.Namespace, job.Name) | ||
test.Eventually(Job(test, job.Namespace, job.Name), TestTimeoutLong).Should( | ||
Or( | ||
WithTransform(ConditionStatus(batchv1.JobComplete), Equal(corev1.ConditionTrue)), | ||
WithTransform(ConditionStatus(batchv1.JobFailed), Equal(corev1.ConditionTrue)), | ||
)) | ||
|
||
// Assert the job has completed successfully | ||
test.Expect(GetJob(test, job.Namespace, job.Name)). | ||
To(WithTransform(ConditionStatus(batchv1.JobComplete), Equal(corev1.ConditionTrue))) | ||
Fiona-Waters marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
test.Eventually(AppWrapper(test, namespace, aw.Name), TestTimeoutShort). | ||
Should(WithTransform(AppWrapperState, Equal(mcadv1beta1.AppWrapperStateCompleted))) | ||
|
||
// look for machine pool with aw name - expect not to find it | ||
test.Eventually(MachinePools(test, connection), TestTimeoutLong). | ||
ShouldNot(ContainElement(WithTransform(MachinePoolId, Equal("test-instascale-g4dn-xlarge")))) | ||
|
||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package support | ||
|
||
import ( | ||
"github.com/onsi/gomega" | ||
|
||
ocmsdk "github.com/openshift-online/ocm-sdk-go" | ||
cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1" | ||
) | ||
|
||
func MachinePools(t Test, connection *ocmsdk.Connection) func(g gomega.Gomega) []*cmv1.MachinePool { | ||
Fiona-Waters marked this conversation as resolved.
Show resolved
Hide resolved
|
||
osdClusterId, found := GetOsdClusterId() | ||
t.Expect(found).To(gomega.BeTrue(), "OSD cluster id not found, please configure environment properly") | ||
|
||
return func(g gomega.Gomega) []*cmv1.MachinePool { | ||
machinePoolsListResponse, err := connection.ClustersMgmt().V1().Clusters().Cluster(osdClusterId).MachinePools().List().Send() | ||
g.Expect(err).NotTo(gomega.HaveOccurred()) | ||
return machinePoolsListResponse.Items().Slice() | ||
} | ||
} | ||
|
||
func GetMachinePools(t Test, connection *ocmsdk.Connection) []*cmv1.MachinePool { | ||
t.T().Helper() | ||
return MachinePools(t, connection)(t) | ||
} | ||
|
||
func MachinePoolId(machinePool *cmv1.MachinePool) string { | ||
return machinePool.ID() | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/* | ||
Copyright 2023. | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package support | ||
|
||
import ( | ||
"github.com/onsi/gomega" | ||
|
||
corev1 "k8s.io/api/core/v1" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
) | ||
|
||
func CreateConfigMap(t Test, namespace string, content map[string][]byte) *corev1.ConfigMap { | ||
Fiona-Waters marked this conversation as resolved.
Show resolved
Hide resolved
|
||
configMap := &corev1.ConfigMap{ | ||
TypeMeta: metav1.TypeMeta{ | ||
APIVersion: corev1.SchemeGroupVersion.String(), | ||
Kind: "ConfigMap", | ||
}, | ||
ObjectMeta: metav1.ObjectMeta{ | ||
GenerateName: "config-", | ||
Namespace: namespace, | ||
}, | ||
BinaryData: content, | ||
Immutable: Ptr(true), | ||
} | ||
|
||
configMap, err := t.Client().Core().CoreV1().ConfigMaps(namespace).Create(t.Ctx(), configMap, metav1.CreateOptions{}) | ||
t.Expect(err).NotTo(gomega.HaveOccurred()) | ||
t.T().Logf("Created ConfigMap %s/%s successfully", configMap.Namespace, configMap.Name) | ||
|
||
return configMap | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/* | ||
Copyright 2023. | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package support | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
|
||
"github.com/onsi/gomega" | ||
|
||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
|
||
ocmsdk "github.com/openshift-online/ocm-sdk-go" | ||
) | ||
|
||
func CreateOCMConnection(test Test) *ocmsdk.Connection { | ||
instascaleOCMSecret, err := test.Client().Core().CoreV1().Secrets(GetInstaScaleOcmSecretNamespace()).Get(test.Ctx(), GetInstaScaleOcmSecretName(), metav1.GetOptions{}) | ||
test.Expect(err).NotTo(gomega.HaveOccurred()) | ||
|
||
ocmToken := string(instascaleOCMSecret.Data["token"]) | ||
test.T().Logf("Retrieved Secret %s/%s successfully", instascaleOCMSecret.Namespace, instascaleOCMSecret.Name) | ||
|
||
connection, err := buildOCMConnection(ocmToken) | ||
test.Expect(err).NotTo(gomega.HaveOccurred()) | ||
return connection | ||
} | ||
|
||
func buildOCMConnection(secret string) (*ocmsdk.Connection, error) { | ||
connection, err := ocmsdk.NewConnectionBuilder(). | ||
Tokens(secret). | ||
Build() | ||
if err != nil || connection == nil { | ||
Fiona-Waters marked this conversation as resolved.
Show resolved
Hide resolved
|
||
fmt.Fprintf(os.Stderr, "Can't build connection: %v\n", err) | ||
return nil, err | ||
} | ||
|
||
return connection, nil | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.