Skip to content

Commit

Permalink
test/e2e: Adding tests for multiple PodVM scenario
Browse files Browse the repository at this point in the history
Negative test for multiple PodVM images on libvirt provider with a non existing volume

Fixes #1282

Signed-off-by: Ajay Victor <ajvictor@in.ibm.com>
  • Loading branch information
ajaypvictor committed Oct 8, 2024
1 parent d1a356f commit f451cd9
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 78 deletions.
33 changes: 33 additions & 0 deletions src/cloud-api-adaptor/test/e2e/assessment_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ type TestCase struct {
testInstanceTypes InstanceValidatorFunctions
isNydusSnapshotter bool
FailReason string
alternateImageName string
}

func (tc *TestCase) WithConfigMap(configMap *v1.ConfigMap) *TestCase {
Expand Down Expand Up @@ -135,6 +136,11 @@ func (tc *TestCase) WithInstanceTypes(testInstanceTypes InstanceValidatorFunctio
return tc
}

func (tc *TestCase) WithMultiplePodVM(alternateImageName string) *TestCase {
tc.alternateImageName = alternateImageName
return tc
}

func (pod *ExtraPod) WithTestCommands(TestCommands []TestCommand) *ExtraPod {
pod.testCommands = TestCommands
return pod
Expand Down Expand Up @@ -545,6 +551,33 @@ func (tc *TestCase) Run() {
}

}

if tc.alternateImageName != "" {
var podlist v1.PodList
var podLogString string
expectedSuccessMessage := "Choosing " + tc.alternateImageName
if err := client.Resources("confidential-containers-system").List(ctx, &podlist); err != nil {
t.Fatal(err)
}
for _, pod := range podlist.Items {
if pod.Labels["app"] == "cloud-api-adaptor" {
podLogString, _ = GetPodLog(ctx, client, pod)
break
}
}
if strings.Contains(podLogString, expectedSuccessMessage) {
t.Logf("PodVM was brought up using the alternate PodVM image %s", tc.alternateImageName)
} else {
t.Logf("cloud-api-adaptor pod logs: %s", podLogString)
yamlData, err := yaml.Marshal(tc.pod.Status)
if err != nil {
log.Errorf("Error marshaling pod.Status to JSON: %s", err.Error())
} else {
t.Logf("Current Pod State: %v", string(yamlData))
}
t.Fatal("failed due to unknown reason")
}
}
return ctx
}).
Teardown(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
Expand Down
39 changes: 39 additions & 0 deletions src/cloud-api-adaptor/test/e2e/common_suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,45 @@ func DoTestPodVMwithAnnotationsLargerCPU(t *testing.T, e env.Environment, assert
NewTestCase(t, e, "PodVMwithAnnotationsLargerCPU", assert, "Failed to Create PodVM with Annotations Larger CPU").WithPod(pod).WithInstanceTypes(testInstanceTypes).WithCustomPodState(v1.PodPending).Run()
}

func DoTestCreatePeerPodContainerWithValidAlternateImage(t *testing.T, e env.Environment, assert CloudAssert) {
podName := "annotations-valid-alternate-image"
containerName := "busybox"
imageName := BUSYBOX_IMAGE
alternateImageName := "another-podvm-base.qcow2"
annotationData := map[string]string{
"io.katacontainers.config.hypervisor.image": alternateImageName,
}
pod := NewPod(E2eNamespace, podName, containerName, imageName, WithCommand([]string{"/bin/sh", "-c", "sleep 3600"}), WithAnnotations(annotationData))

NewTestCase(t, e, "PodVMwithAnnotationsValidAlternateImage", assert, "PodVM created with an alternate image").WithPod(pod).WithMultiplePodVM(alternateImageName).Run()
}

func DoTestCreatePeerPodContainerWithInvalidAlternateImage(t *testing.T, e env.Environment, assert CloudAssert) {
podName := "annotations-invalid-alternate-image"
containerName := "busybox"
imageName := BUSYBOX_IMAGE
nonExistingImageName := "non-existing-image"
expectedErrorMessage := "Error in creating volume: Can't retrieve volume " + nonExistingImageName
annotationData := map[string]string{
"io.katacontainers.config.hypervisor.image": nonExistingImageName,
}
pod := NewPod(E2eNamespace, podName, containerName, imageName, WithCommand([]string{"/bin/sh", "-c", "sleep 3600"}), WithAnnotations(annotationData))

testInstanceTypes := InstanceValidatorFunctions{
testSuccessfn: IsStringEmpty,
testFailurefn: func(errorMsg error) bool {
if strings.Contains(errorMsg.Error(), expectedErrorMessage) {
t.Logf("Got Expected Error: %v", errorMsg.Error())
return true
} else {
t.Logf("Failed to Get Expected Error: %v", errorMsg.Error())
return false
}
},
}
NewTestCase(t, e, "PodVMwithAnnotationsInvalidAlternateImage", assert, "Failed to Create PodVM with a non-existent image").WithPod(pod).WithInstanceTypes(testInstanceTypes).WithCustomPodState(v1.PodPending).Run()
}

func DoTestPodToServiceCommunication(t *testing.T, e env.Environment, assert CloudAssert) {
clientPodName := "test-client"
clientContainerName := "busybox"
Expand Down
10 changes: 10 additions & 0 deletions src/cloud-api-adaptor/test/e2e/libvirt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@ func TestLibvirtCreatePeerPodContainerWithExternalIPAccess(t *testing.T) {

}

func TestLibvirtCreatePeerPodContainerWithValidAlternateImage(t *testing.T) {
assert := LibvirtAssert{}
DoTestCreatePeerPodContainerWithValidAlternateImage(t, testEnv, assert)
}

func TestLibvirtCreatePeerPodContainerWithInvalidAlternateImage(t *testing.T) {
assert := LibvirtAssert{}
DoTestCreatePeerPodContainerWithInvalidAlternateImage(t, testEnv, assert)
}

func TestLibvirtCreatePeerPodWithJob(t *testing.T) {
assert := LibvirtAssert{}
DoTestCreatePeerPodWithJob(t, testEnv, assert)
Expand Down
170 changes: 92 additions & 78 deletions src/cloud-api-adaptor/test/provisioner/libvirt/provision_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,17 @@ import (

// LibvirtProvisioner implements the CloudProvisioner interface for Libvirt.
type LibvirtProvisioner struct {
conn *libvirt.Connect // Libvirt connection
network string // Network name
ssh_key_file string // SSH key file used to connect to Libvirt
storage string // Storage pool name
uri string // Libvirt URI
wd string // libvirt's directory path on this repository
volumeName string // Podvm volume name
clusterName string // Cluster name
kbs_image string // KBS Service OCI Image URL
kbs_image_tag string // KBS Service OCI Image Tag
conn *libvirt.Connect // Libvirt connection
network string // Network name
ssh_key_file string // SSH key file used to connect to Libvirt
storage string // Storage pool name
uri string // Libvirt URI
wd string // libvirt's directory path on this repository
volumeName string // Podvm volume name
alternateVolumeName string // Alternate Podvm volume name
clusterName string // Cluster name
kbs_image string // KBS Service OCI Image URL
kbs_image_tag string // KBS Service OCI Image Tag
}

// LibvirtInstallOverlay implements the InstallOverlay interface
Expand Down Expand Up @@ -68,6 +69,9 @@ func NewLibvirtProvisioner(properties map[string]string) (pv.CloudProvisioner, e
vol_name = properties["libvirt_vol_name"]
}

// alternate_vol_name is used for multi-podvm testing.
alternate_vol_name := "another-podvm-base.qcow2"

conn_uri := "qemu:///system"
if properties["libvirt_conn_uri"] != "" {
conn_uri = properties["libvirt_conn_uri"]
Expand All @@ -94,16 +98,17 @@ func NewLibvirtProvisioner(properties map[string]string) (pv.CloudProvisioner, e

// TODO: Check network and storage are not nil?
return &LibvirtProvisioner{
conn: conn,
network: network,
ssh_key_file: ssh_key_file,
storage: storage,
uri: uri,
wd: wd,
volumeName: vol_name,
clusterName: clusterName,
kbs_image: kbs_image,
kbs_image_tag: kbs_image_tag,
conn: conn,
network: network,
ssh_key_file: ssh_key_file,
storage: storage,
uri: uri,
wd: wd,
volumeName: vol_name,
alternateVolumeName: alternate_vol_name,
clusterName: clusterName,
kbs_image: kbs_image,
kbs_image_tag: kbs_image_tag,
}, nil
}

Expand Down Expand Up @@ -152,30 +157,35 @@ func (l *LibvirtProvisioner) CreateVPC(ctx context.Context, cfg *envconf.Config)
return fmt.Errorf("Storage pool '%s' not found. It should be created beforehand", l.storage)
}

// Create the podvm storage volume if it does not exist.
if _, err = sPool.LookupStorageVolByName(l.volumeName); err != nil {
volCfg := libvirtxml.StorageVolume{
Name: l.volumeName,
Capacity: &libvirtxml.StorageVolumeSize{
Unit: "GiB",
Value: 20,
},
Allocation: &libvirtxml.StorageVolumeSize{
Unit: "GiB",
Value: 2,
},
Target: &libvirtxml.StorageVolumeTarget{
Format: &libvirtxml.StorageVolumeTargetFormat{
Type: "qcow2",
// Create two volumes to test the multiple podvm image scenario.
lVolumes := [2]string{l.volumeName, l.alternateVolumeName}

// Create the podvm storage volumes if it does not exist.
for _, volume := range lVolumes {
if _, err = sPool.LookupStorageVolByName(volume); err != nil {
volCfg := libvirtxml.StorageVolume{
Name: volume,
Capacity: &libvirtxml.StorageVolumeSize{
Unit: "GiB",
Value: 20,
},
},
}
xml, err := volCfg.Marshal()
if err != nil {
return err
}
if _, err = sPool.StorageVolCreateXML(xml, libvirt.STORAGE_VOL_CREATE_PREALLOC_METADATA); err != nil {
return err
Allocation: &libvirtxml.StorageVolumeSize{
Unit: "GiB",
Value: 2,
},
Target: &libvirtxml.StorageVolumeTarget{
Format: &libvirtxml.StorageVolumeTargetFormat{
Type: "qcow2",
},
},
}
xml, err := volCfg.Marshal()
if err != nil {
return err
}
if _, err = sPool.StorageVolCreateXML(xml, libvirt.STORAGE_VOL_CREATE_PREALLOC_METADATA); err != nil {
return err
}
}
}
return nil
Expand Down Expand Up @@ -227,52 +237,56 @@ func (l *LibvirtProvisioner) UploadPodvm(imagePath string, ctx context.Context,
}
length := fileStat.Size()

sVol, err := sPool.LookupStorageVolByName(l.volumeName)
if err != nil {
return err
}
lVolumes := [2]string{l.volumeName, l.alternateVolumeName}

stream, err := l.conn.NewStream(0)
if err != nil {
return err
}

if err := sVol.Upload(stream, 0, uint64(length), libvirt.STORAGE_VOL_UPLOAD_SPARSE_STREAM); err != nil {
return err
}
for _, volume := range lVolumes {
sVol, err := sPool.LookupStorageVolByName(volume)
if err != nil {
return err
}

fileByteSlice, err := os.ReadFile(imagePath)
if err != nil {
return err
}
stream, err := l.conn.NewStream(0)
if err != nil {
return err
}

sent := 0
source := func(stream *libvirt.Stream, nbytes int) ([]byte, error) {
tosend := nbytes
if tosend > (len(fileByteSlice) - sent) {
tosend = len(fileByteSlice) - sent
if err := sVol.Upload(stream, 0, uint64(length), libvirt.STORAGE_VOL_UPLOAD_SPARSE_STREAM); err != nil {
return err
}

if tosend == 0 {
return []byte{}, nil
fileByteSlice, err := os.ReadFile(imagePath)
if err != nil {
return err
}

data := fileByteSlice[sent : sent+tosend]
sent += tosend
sent := 0
source := func(stream *libvirt.Stream, nbytes int) ([]byte, error) {
tosend := nbytes
if tosend > (len(fileByteSlice) - sent) {
tosend = len(fileByteSlice) - sent
}

return data, nil
}
if tosend == 0 {
return []byte{}, nil
}

if err := stream.SendAll(source); err != nil {
return err
}
data := fileByteSlice[sent : sent+tosend]
sent += tosend

if err := stream.Finish(); err != nil {
return err
}
return data, nil
}

if err := stream.Free(); err != nil {
return err
if err := stream.SendAll(source); err != nil {
return err
}

if err := stream.Finish(); err != nil {
return err
}

if err := stream.Free(); err != nil {
return err
}
}

return nil
Expand Down

0 comments on commit f451cd9

Please sign in to comment.