Skip to content

Commit

Permalink
ibmcloud: e2e test for flexible instance profiles
Browse files Browse the repository at this point in the history
Added e2e  test cases for flexible instance profiles

Fixes: #1161

Signed-off-by: Sudharshan Muralidharan <sudharshan.muralidharan@ibm.com>
  • Loading branch information
sudharshanibm3 committed Sep 25, 2023
1 parent b9ce353 commit 3680b14
Show file tree
Hide file tree
Showing 7 changed files with 346 additions and 5 deletions.
5 changes: 5 additions & 0 deletions test/e2e/azure_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,8 @@ func (c AzureCloudAssert) HasPodVM(t *testing.T, id string) {
t.Error("PodVM was not created")
}
}

func (c AzureCloudAssert) getInstanceType(t *testing.T, podName string) (string, error) {
// Get Instance Type of PodVM
return "", nil
}
9 changes: 8 additions & 1 deletion test/e2e/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ func withPVCBinding(mountPath string, pvcName string) podOption {
}
}

func withAnnotations(data map[string]string) podOption {
return func(p *corev1.Pod) {
p.ObjectMeta.Annotations = data
}
}

func newPod(namespace string, podName string, containerName string, imageName string, options ...podOption) *corev1.Pod {
runtimeClassName := "kata-remote"
pod := &corev1.Pod{
Expand Down Expand Up @@ -160,5 +166,6 @@ func newPVC(namespace, name, storageClassName, diskSize string, accessModel core

// CloudAssert defines assertions to perform on the cloud provider.
type CloudAssert interface {
HasPodVM(t *testing.T, id string) // Assert there is a PodVM with `id`.
HasPodVM(t *testing.T, id string) // Assert there is a PodVM with `id`.
getInstanceType(t *testing.T, podName string) (string, error) // Get Instance Type of PodVM
}
242 changes: 239 additions & 3 deletions test/e2e/common_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ type testCommand struct {
testCommandStdoutFn func(stdout bytes.Buffer) bool
containerName string
}
type instanceValidatorFunctions struct {
testSuccessfn func(instance string) bool
testFailurefn func(error error) bool
}

type testCase struct {
testing *testing.T
Expand All @@ -62,6 +66,7 @@ type testCase struct {
isAuth bool
AuthImageStatus string
deletionWithin *time.Duration
testInstanceTypes instanceValidatorFunctions
}

func (tc *testCase) withConfigMap(configMap *v1.ConfigMap) *testCase {
Expand Down Expand Up @@ -99,6 +104,11 @@ func (tc *testCase) withTestCommands(testCommands []testCommand) *testCase {
return tc
}

func (tc *testCase) withInstanceTypes(testInstanceTypes instanceValidatorFunctions) *testCase {
tc.testInstanceTypes = testInstanceTypes
return tc
}

func (tc *testCase) withExpectedPodLogString(expectedPodLogString string) *testCase {
tc.expectedPodLogString = expectedPodLogString
return tc
Expand Down Expand Up @@ -231,7 +241,6 @@ func (tc *testCase) run() {
}

if tc.pod != nil {

if tc.imagePullTimer {
if err := client.Resources("confidential-containers-system").List(ctx, &podlist); err != nil {
t.Fatal(err)
Expand All @@ -246,7 +255,6 @@ func (tc *testCase) run() {
break
}
}

}

if tc.expectedPodLogString != "" {
Expand All @@ -264,6 +272,40 @@ func (tc *testCase) run() {
}

t.Logf("PodVM has successfully reached %v state with authenticated Image - %v", tc.AuthImageStatus, os.Getenv("AUTHENTICATED_REGISTRY_IMAGE"))
}

if tc.testInstanceTypes.testSuccessfn != nil && tc.testInstanceTypes.testFailurefn != nil {
if err := client.Resources(tc.pod.Namespace).List(ctx, &podlist); err != nil {
t.Fatal(err)
}

for _, podItem := range podlist.Items {
if podItem.ObjectMeta.Name == tc.pod.Name {
profile, error := tc.assert.getInstanceType(t, tc.pod.Name)
if error != nil {
if error.Error() == "Failed to Create PodVM Instance" {
podEvent, err := podEventExtractor(ctx, client, *tc.pod)
if err != nil {
t.Fatal(err)
}
if !tc.testInstanceTypes.testFailurefn(errors.New(podEvent.EventDescription)) {
t.Fatal(fmt.Errorf("Pod Failed to execute expected error message %v", error.Error()))
}
} else {
t.Fatal(error)
}

}
if profile != "" {
if !tc.testInstanceTypes.testSuccessfn(profile) {
t.Fatal(fmt.Errorf("PodVM Created with Differenct Instance Type %v", profile))
}
}

} else {
t.Fatal("Pod Not Found...")
}
}

}

Expand All @@ -274,7 +316,6 @@ func (tc *testCase) run() {
if len(tc.testCommands) > 0 {
for _, testCommand := range tc.testCommands {
var stdout, stderr bytes.Buffer

for _, podItem := range podlist.Items {
if podItem.ObjectMeta.Name == tc.pod.Name {
//adding sleep time to intialize container and ready for Executing commands
Expand Down Expand Up @@ -400,6 +441,35 @@ func timeExtractor(log string) (string, error) {
return matchString[0], nil
}

type PodEvents struct {
EventType string
EventDescription string
EventReason string
}

func podEventExtractor(ctx context.Context, client klient.Client, pod v1.Pod) (*PodEvents, error) {
clientset, err := kubernetes.NewForConfig(client.RESTConfig())
if err != nil {
return nil, err
}
watcher, err := clientset.CoreV1().Events(pod.Namespace).Watch(ctx, metav1.ListOptions{FieldSelector: fmt.Sprintf("involvedObject.name=%s", pod.Name)})
if err != nil {
return nil, err
}
defer watcher.Stop()
for event := range watcher.ResultChan() {

if event.Object.(*v1.Event).Type == v1.EventTypeWarning {
var newPodEvents PodEvents
newPodEvents.EventType = event.Object.(*v1.Event).Type
newPodEvents.EventDescription = event.Object.(*v1.Event).Message
newPodEvents.EventType = event.Object.(*v1.Event).Reason
return &newPodEvents, nil
}
}
return nil, errors.New("No Events Found in PodVM")
}

func watchImagePullTime(ctx context.Context, client klient.Client, caaPod v1.Pod, Pod v1.Pod) (string, error) {
pullingtime := ""
podLogString := ""
Expand Down Expand Up @@ -870,3 +940,169 @@ func doTestCreatePeerPodWithAuthenticatedImageWithoutCredentials(t *testing.T, a
pod := newPod(namespace, podName, podName, imageName, withRestartPolicy(v1.RestartPolicyNever))
newTestCase(t, "InvalidAuthImagePeerPod", assert, "Peer pod with Authenticated Image with Invalid Credentials has been created").withPod(pod).withAuthenticatedImage().withAuthImageStatus(expectedAuthStatus).withCustomPodState(v1.PodPending).run()
}

func doTestPodVMwithNoAnnotations(t *testing.T, assert CloudAssert, expectedType string) {

namespace := envconf.RandomName("default", 7)
podName := "no-annotations"
containerName := "busybox"
imageName := "busybox:latest"
pod := newPod(namespace, podName, containerName, imageName, withCommand([]string{"/bin/sh", "-c", "sleep 3600"}))
testInstanceTypes := instanceValidatorFunctions{
testSuccessfn: func(instance string) bool {
if instance == expectedType {
log.Infof("PodVM Created with %s Instance type successfully...", instance)
return true
} else {
log.Infof("Failed to Create PodVM with %s Instance type", expectedType)
return false
}
},
testFailurefn: testErrorEmpty,
}
newTestCase(t, "PodVMWithNoAnnotations", assert, "PodVM with No Annotation is created").withPod(pod).withInstanceTypes(testInstanceTypes).run()
}

func doTestPodVMwithAnnotationsInstanceType(t *testing.T, assert CloudAssert, expectedType string) {
namespace := envconf.RandomName("default", 7)
podName := "annotations-instance-type"
containerName := "busybox"
imageName := "busybox:latest"
annotationData := map[string]string{
"io.katacontainers.config.hypervisor.machine_type": expectedType,
}
pod := newPod(namespace, podName, containerName, imageName, withCommand([]string{"/bin/sh", "-c", "sleep 3600"}), withAnnotations(annotationData))

testInstanceTypes := instanceValidatorFunctions{
testSuccessfn: func(instance string) bool {
if instance == expectedType {
log.Infof("PodVM Created with %s Instance type successfully...", instance)
return true
} else {
log.Infof("Failed to Create PodVM with %s Instance type", expectedType)
return false
}
},
testFailurefn: testErrorEmpty,
}
newTestCase(t, "PodVMwithAnnotationsInstanceType", assert, "PodVM with Annotation is created").withPod(pod).withInstanceTypes(testInstanceTypes).run()
}

func doTestPodVMwithAnnotationsCPUMemory(t *testing.T, assert CloudAssert, expectedType string) {
namespace := envconf.RandomName("default", 7)
podName := "annotations-cpu-mem"
containerName := "busybox"
imageName := "busybox:latest"
annotationData := map[string]string{
"io.katacontainers.config.hypervisor.default_vcpus": "2",
"io.katacontainers.config.hypervisor.default_memory": "12288",
}
pod := newPod(namespace, podName, containerName, imageName, withCommand([]string{"/bin/sh", "-c", "sleep 3600"}), withAnnotations(annotationData))

testInstanceTypes := instanceValidatorFunctions{
testSuccessfn: func(instance string) bool {
if instance == expectedType {
log.Infof("PodVM Created with %s Instance type successfully...", instance)
return true
} else {
log.Infof("Failed to Create PodVM with %s Instance type", expectedType)
return false
}
},
testFailurefn: testErrorEmpty,
}
newTestCase(t, "PodVMwithAnnotationsCPUMemory", assert, "PodVM with Annotations CPU Memory is created").withPod(pod).withInstanceTypes(testInstanceTypes).run()
}

func doTestPodVMwithAnnotationsInvalidInstanceType(t *testing.T, assert CloudAssert, expectedType string) {
namespace := envconf.RandomName("default", 7)
podName := "annotations-invalid-instance-type"
containerName := "busybox"
imageName := "busybox:latest"
expectedErrorMessage := `requested instance type ("` + expectedType + `") is not part of supported instance types list`
annotationData := map[string]string{
"io.katacontainers.config.hypervisor.machine_type": expectedType,
}
pod := newPod(namespace, podName, containerName, imageName, withCommand([]string{"/bin/sh", "-c", "sleep 3600"}), withAnnotations(annotationData))
testInstanceTypes := instanceValidatorFunctions{
testSuccessfn: testStringEmpty,
testFailurefn: func(errorMsg error) bool {
if strings.Contains(errorMsg.Error(), expectedErrorMessage) {
log.Infof("Got Expected Error: %v", errorMsg.Error())
return true
} else {
log.Infof("Failed to Get Expected Error: %v", errorMsg.Error())
return false
}
},
}
newTestCase(t, "PodVMwithAnnotationsInvalidInstanceType", assert, "Failed to Create PodVM with Annotations Invalid InstanceType").withPod(pod).withInstanceTypes(testInstanceTypes).withCustomPodState(v1.PodPending).run()
}

func doTestPodVMwithAnnotationsLargerMemory(t *testing.T, assert CloudAssert) {
namespace := envconf.RandomName("default", 7)
podName := "annotations-too-big-mem"
containerName := "busybox"
imageName := "busybox:latest"
expectedErrorMessage := "failed to get instance type based on vCPU and memory annotations: no instance type found for the given vcpus (2) and memory (18432)"
annotationData := map[string]string{
"io.katacontainers.config.hypervisor.default_vcpus": "2",
"io.katacontainers.config.hypervisor.default_memory": "18432",
}
pod := newPod(namespace, podName, containerName, imageName, withCommand([]string{"/bin/sh", "-c", "sleep 3600"}), withAnnotations(annotationData))
testInstanceTypes := instanceValidatorFunctions{
testSuccessfn: testStringEmpty,
testFailurefn: func(errorMsg error) bool {
if strings.Contains(errorMsg.Error(), expectedErrorMessage) {
log.Infof("Got Expected Error: %v", errorMsg.Error())
return true
} else {
log.Infof("Failed to Get Expected Error: %v", errorMsg.Error())
return false
}
},
}
newTestCase(t, "PodVMwithAnnotationsLargerMemory", assert, "Failed to Create PodVM with Annotations Larger Memory").withPod(pod).withInstanceTypes(testInstanceTypes).withCustomPodState(v1.PodPending).run()
}

func doTestPodVMwithAnnotationsLargerCPU(t *testing.T, assert CloudAssert) {
namespace := envconf.RandomName("default", 7)
podName := "annotations-too-big-cpu"
containerName := "busybox"
imageName := "busybox:latest"
expectedErrorMessage := "no instance type found for the given vcpus (3) and memory (12288)"
annotationData := map[string]string{
"io.katacontainers.config.hypervisor.default_vcpus": "3",
"io.katacontainers.config.hypervisor.default_memory": "12288",
}
pod := newPod(namespace, podName, containerName, imageName, withCommand([]string{"/bin/sh", "-c", "sleep 3600"}), withAnnotations(annotationData))
testInstanceTypes := instanceValidatorFunctions{
testSuccessfn: testStringEmpty,
testFailurefn: func(errorMsg error) bool {
if strings.Contains(errorMsg.Error(), expectedErrorMessage) {
log.Infof("Got Expected Error: %v", errorMsg.Error())
return true
} else {
log.Infof("Failed to Get Expected Error: %v", errorMsg.Error())
return false
}
},
}
newTestCase(t, "PodVMwithAnnotationsLargerCPU", assert, "Failed to Create PodVM with Annotations Larger CPU").withPod(pod).withInstanceTypes(testInstanceTypes).withCustomPodState(v1.PodPending).run()
}

func testStringEmpty(data string) bool {
if data == "" {
return true
} else {
return false
}
}

func testErrorEmpty(err error) bool {
if err == nil {
return true
} else {
return false
}
}
Loading

0 comments on commit 3680b14

Please sign in to comment.