Multiple volumes for e2e tests

Allow mounting of multiple volumes in volume e2e tests.
This commit is contained in:
Jan Safranek 2016-12-19 10:33:38 +01:00
parent 16f7cd189c
commit 2970761cf1

View File

@ -72,7 +72,15 @@ type VolumeTestConfig struct {
serverArgs []string serverArgs []string
// Volumes needed to be mounted to the server container from the host // Volumes needed to be mounted to the server container from the host
// map <host (source) path> -> <container (dst.) path> // map <host (source) path> -> <container (dst.) path>
volumes map[string]string serverVolumes map[string]string
}
// VolumeTest contains a volumes to mount into a client pod and its
// expected content.
type VolumeTest struct {
volume v1.VolumeSource
file string
expectedContent string
} }
// Starts a container specified by config.serverImage and exports all // Starts a container specified by config.serverImage and exports all
@ -94,12 +102,12 @@ func startVolumeServer(client clientset.Interface, config VolumeTestConfig) *v1.
} }
} }
volumeCount := len(config.volumes) volumeCount := len(config.serverVolumes)
volumes := make([]v1.Volume, volumeCount) volumes := make([]v1.Volume, volumeCount)
mounts := make([]v1.VolumeMount, volumeCount) mounts := make([]v1.VolumeMount, volumeCount)
i := 0 i := 0
for src, dst := range config.volumes { for src, dst := range config.serverVolumes {
mountName := fmt.Sprintf("path%d", i) mountName := fmt.Sprintf("path%d", i)
volumes[i].Name = mountName volumes[i].Name = mountName
volumes[i].VolumeSource.HostPath = &v1.HostPathVolumeSource{ volumes[i].VolumeSource.HostPath = &v1.HostPathVolumeSource{
@ -193,8 +201,10 @@ func volumeTestCleanup(f *framework.Framework, config VolumeTestConfig) {
} }
// Start a client pod using given VolumeSource (exported by startVolumeServer()) // Start a client pod using given VolumeSource (exported by startVolumeServer())
// and check that the pod sees the data from the server pod. // and check that the pod sees expected data, e.g. from the server pod.
func testVolumeClient(client clientset.Interface, config VolumeTestConfig, volume v1.VolumeSource, fsGroup *int64, expectedContent string) { // Multiple VolumeTests can be specified to mount multiple volumes to a single
// pod.
func testVolumeClient(client clientset.Interface, config VolumeTestConfig, fsGroup *int64, tests []VolumeTest) {
By(fmt.Sprint("starting ", config.prefix, " client")) By(fmt.Sprint("starting ", config.prefix, " client"))
clientPod := &v1.Pod{ clientPod := &v1.Pod{
TypeMeta: metav1.TypeMeta{ TypeMeta: metav1.TypeMeta{
@ -219,14 +229,9 @@ func testVolumeClient(client clientset.Interface, config VolumeTestConfig, volum
Command: []string{ Command: []string{
"/bin/sh", "/bin/sh",
"-c", "-c",
"while true ; do cat /opt/index.html ; sleep 2 ; ls -altrh /opt/ ; sleep 2 ; done ", "while true ; do cat /opt/0/index.html ; sleep 2 ; ls -altrh /opt/ ; sleep 2 ; done ",
},
VolumeMounts: []v1.VolumeMount{
{
Name: config.prefix + "-volume",
MountPath: "/opt/",
},
}, },
VolumeMounts: []v1.VolumeMount{},
}, },
}, },
SecurityContext: &v1.PodSecurityContext{ SecurityContext: &v1.PodSecurityContext{
@ -234,12 +239,7 @@ func testVolumeClient(client clientset.Interface, config VolumeTestConfig, volum
Level: "s0:c0,c1", Level: "s0:c0,c1",
}, },
}, },
Volumes: []v1.Volume{ Volumes: []v1.Volume{},
{
Name: config.prefix + "-volume",
VolumeSource: volume,
},
},
}, },
} }
podsNamespacer := client.Core().Pods(config.namespace) podsNamespacer := client.Core().Pods(config.namespace)
@ -247,6 +247,18 @@ func testVolumeClient(client clientset.Interface, config VolumeTestConfig, volum
if fsGroup != nil { if fsGroup != nil {
clientPod.Spec.SecurityContext.FSGroup = fsGroup clientPod.Spec.SecurityContext.FSGroup = fsGroup
} }
for i, test := range tests {
volumeName := fmt.Sprintf("%s-%s-%d", config.prefix, "volume", i)
clientPod.Spec.Containers[0].VolumeMounts = append(clientPod.Spec.Containers[0].VolumeMounts, v1.VolumeMount{
Name: volumeName,
MountPath: fmt.Sprintf("/opt/%d", i),
})
clientPod.Spec.Volumes = append(clientPod.Spec.Volumes, v1.Volume{
Name: volumeName,
VolumeSource: test.volume,
})
}
clientPod, err := podsNamespacer.Create(clientPod) clientPod, err := podsNamespacer.Create(clientPod)
if err != nil { if err != nil {
framework.Failf("Failed to create %s pod: %v", clientPod.Name, err) framework.Failf("Failed to create %s pod: %v", clientPod.Name, err)
@ -254,13 +266,15 @@ func testVolumeClient(client clientset.Interface, config VolumeTestConfig, volum
framework.ExpectNoError(framework.WaitForPodRunningInNamespace(client, clientPod)) framework.ExpectNoError(framework.WaitForPodRunningInNamespace(client, clientPod))
By("Checking that text file contents are perfect.") By("Checking that text file contents are perfect.")
_, err = framework.LookForStringInPodExec(config.namespace, clientPod.Name, []string{"cat", "/opt/index.html"}, expectedContent, time.Minute) for i, test := range tests {
Expect(err).NotTo(HaveOccurred(), "failed: finding the contents of the mounted file.") fileName := fmt.Sprintf("/opt/%d/%s", i, test.file)
_, err = framework.LookForStringInPodExec(config.namespace, clientPod.Name, []string{"cat", fileName}, test.expectedContent, time.Minute)
Expect(err).NotTo(HaveOccurred(), "failed: finding the contents of the mounted file %s.", fileName)
}
if fsGroup != nil { if fsGroup != nil {
By("Checking fsGroup is correct.") By("Checking fsGroup is correct.")
_, err = framework.LookForStringInPodExec(config.namespace, clientPod.Name, []string{"ls", "-ld", "/opt"}, strconv.Itoa(int(*fsGroup)), time.Minute) _, err = framework.LookForStringInPodExec(config.namespace, clientPod.Name, []string{"ls", "-ld", "/opt/0"}, strconv.Itoa(int(*fsGroup)), time.Minute)
Expect(err).NotTo(HaveOccurred(), "failed: getting the right priviliges in the file %v", int(*fsGroup)) Expect(err).NotTo(HaveOccurred(), "failed: getting the right priviliges in the file %v", int(*fsGroup))
} }
} }
@ -383,15 +397,21 @@ var _ = framework.KubeDescribe("Volumes [Feature:Volumes]", func() {
serverIP := pod.Status.PodIP serverIP := pod.Status.PodIP
framework.Logf("NFS server IP address: %v", serverIP) framework.Logf("NFS server IP address: %v", serverIP)
volume := v1.VolumeSource{ tests := []VolumeTest{
NFS: &v1.NFSVolumeSource{ {
Server: serverIP, volume: v1.VolumeSource{
Path: "/", NFS: &v1.NFSVolumeSource{
ReadOnly: true, Server: serverIP,
Path: "/",
ReadOnly: true,
},
},
file: "index.html",
// Must match content of test/images/volumes-tester/nfs/index.html
expectedContent: "Hello from NFS!",
}, },
} }
// Must match content of test/images/volumes-tester/nfs/index.html testVolumeClient(cs, config, nil, tests)
testVolumeClient(cs, config, volume, nil, "Hello from NFS!")
}) })
}) })
@ -456,16 +476,22 @@ var _ = framework.KubeDescribe("Volumes [Feature:Volumes]", func() {
framework.Failf("Failed to create endpoints for Gluster server: %v", err) framework.Failf("Failed to create endpoints for Gluster server: %v", err)
} }
volume := v1.VolumeSource{ tests := []VolumeTest{
Glusterfs: &v1.GlusterfsVolumeSource{ {
EndpointsName: config.prefix + "-server", volume: v1.VolumeSource{
// 'test_vol' comes from test/images/volumes-tester/gluster/run_gluster.sh Glusterfs: &v1.GlusterfsVolumeSource{
Path: "test_vol", EndpointsName: config.prefix + "-server",
ReadOnly: true, // 'test_vol' comes from test/images/volumes-tester/gluster/run_gluster.sh
Path: "test_vol",
ReadOnly: true,
},
},
file: "index.html",
// Must match content of test/images/volumes-tester/gluster/index.html
expectedContent: "Hello from GlusterFS!",
}, },
} }
// Must match content of test/images/volumes-tester/gluster/index.html testVolumeClient(cs, config, nil, tests)
testVolumeClient(cs, config, volume, nil, "Hello from GlusterFS!")
}) })
}) })
@ -485,7 +511,7 @@ var _ = framework.KubeDescribe("Volumes [Feature:Volumes]", func() {
prefix: "iscsi", prefix: "iscsi",
serverImage: "gcr.io/google_containers/volume-iscsi:0.1", serverImage: "gcr.io/google_containers/volume-iscsi:0.1",
serverPorts: []int{3260}, serverPorts: []int{3260},
volumes: map[string]string{ serverVolumes: map[string]string{
// iSCSI container needs to insert modules from the host // iSCSI container needs to insert modules from the host
"/lib/modules": "/lib/modules", "/lib/modules": "/lib/modules",
}, },
@ -500,19 +526,24 @@ var _ = framework.KubeDescribe("Volumes [Feature:Volumes]", func() {
serverIP := pod.Status.PodIP serverIP := pod.Status.PodIP
framework.Logf("iSCSI server IP address: %v", serverIP) framework.Logf("iSCSI server IP address: %v", serverIP)
volume := v1.VolumeSource{ tests := []VolumeTest{
ISCSI: &v1.ISCSIVolumeSource{ {
TargetPortal: serverIP + ":3260", volume: v1.VolumeSource{
// from test/images/volumes-tester/iscsi/initiatorname.iscsi ISCSI: &v1.ISCSIVolumeSource{
IQN: "iqn.2003-01.org.linux-iscsi.f21.x8664:sn.4b0aae584f7c", TargetPortal: serverIP + ":3260",
Lun: 0, // from test/images/volumes-tester/iscsi/initiatorname.iscsi
FSType: "ext2", IQN: "iqn.2003-01.org.linux-iscsi.f21.x8664:sn.4b0aae584f7c",
Lun: 0,
FSType: "ext2",
},
},
file: "index.html",
// Must match content of test/images/volumes-tester/iscsi/block.tar.gz
expectedContent: "Hello from iSCSI",
}, },
} }
fsGroup := int64(1234) fsGroup := int64(1234)
// Must match content of test/images/volumes-tester/iscsi/block.tar.gz testVolumeClient(cs, config, &fsGroup, tests)
testVolumeClient(cs, config, volume, &fsGroup, "Hello from iSCSI")
}) })
}) })
@ -527,7 +558,7 @@ var _ = framework.KubeDescribe("Volumes [Feature:Volumes]", func() {
prefix: "rbd", prefix: "rbd",
serverImage: "gcr.io/google_containers/volume-rbd:0.1", serverImage: "gcr.io/google_containers/volume-rbd:0.1",
serverPorts: []int{6789}, serverPorts: []int{6789},
volumes: map[string]string{ serverVolumes: map[string]string{
// iSCSI container needs to insert modules from the host // iSCSI container needs to insert modules from the host
"/lib/modules": "/lib/modules", "/lib/modules": "/lib/modules",
"/sys": "/sys", "/sys": "/sys",
@ -571,23 +602,27 @@ var _ = framework.KubeDescribe("Volumes [Feature:Volumes]", func() {
framework.Failf("Failed to create secrets for Ceph RBD: %v", err) framework.Failf("Failed to create secrets for Ceph RBD: %v", err)
} }
volume := v1.VolumeSource{ tests := []VolumeTest{
RBD: &v1.RBDVolumeSource{ {
CephMonitors: []string{serverIP}, volume: v1.VolumeSource{
RBDPool: "rbd", RBD: &v1.RBDVolumeSource{
RBDImage: "foo", CephMonitors: []string{serverIP},
RadosUser: "admin", RBDPool: "rbd",
SecretRef: &v1.LocalObjectReference{ RBDImage: "foo",
Name: config.prefix + "-secret", RadosUser: "admin",
SecretRef: &v1.LocalObjectReference{
Name: config.prefix + "-secret",
},
FSType: "ext2",
},
}, },
FSType: "ext2", file: "index.html",
// Must match content of test/images/volumes-tester/rbd/create_block.sh
expectedContent: "Hello from RBD",
}, },
} }
fsGroup := int64(1234) fsGroup := int64(1234)
testVolumeClient(cs, config, &fsGroup, tests)
// Must match content of test/images/volumes-tester/gluster/index.html
testVolumeClient(cs, config, volume, &fsGroup, "Hello from RBD")
}) })
}) })
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
@ -644,16 +679,22 @@ var _ = framework.KubeDescribe("Volumes [Feature:Volumes]", func() {
framework.Failf("unable to create test secret %s: %v", secret.Name, err) framework.Failf("unable to create test secret %s: %v", secret.Name, err)
} }
volume := v1.VolumeSource{ tests := []VolumeTest{
CephFS: &v1.CephFSVolumeSource{ {
Monitors: []string{serverIP + ":6789"}, volume: v1.VolumeSource{
User: "kube", CephFS: &v1.CephFSVolumeSource{
SecretRef: &v1.LocalObjectReference{Name: config.prefix + "-secret"}, Monitors: []string{serverIP + ":6789"},
ReadOnly: true, User: "kube",
SecretRef: &v1.LocalObjectReference{Name: config.prefix + "-secret"},
ReadOnly: true,
},
},
file: "index.html",
// Must match content of test/images/volumes-tester/ceph/index.html
expectedContent: "Hello Ceph!",
}, },
} }
// Must match content of contrib/for-tests/volumes-ceph/ceph/index.html testVolumeClient(cs, config, nil, tests)
testVolumeClient(cs, config, volume, nil, "Hello Ceph!")
}) })
}) })
@ -714,21 +755,27 @@ var _ = framework.KubeDescribe("Volumes [Feature:Volumes]", func() {
volumeTestCleanup(f, config) volumeTestCleanup(f, config)
} }
}() }()
volume := v1.VolumeSource{
Cinder: &v1.CinderVolumeSource{ tests := []VolumeTest{
VolumeID: volumeID, {
FSType: "ext3", volume: v1.VolumeSource{
ReadOnly: false, Cinder: &v1.CinderVolumeSource{
VolumeID: volumeID,
FSType: "ext3",
ReadOnly: false,
},
},
file: "index.html",
// Randomize index.html to make sure we don't see the
// content from previous test runs.
expectedContent: "Hello from Cinder from namespace " + volumeName,
}, },
} }
// Insert index.html into the test volume with some random content injectHtml(cs, config, tests[0].volume, tests[0].expectedContent)
// to make sure we don't see the content from previous test runs.
content := "Hello from Cinder from namespace " + volumeName
injectHtml(cs, config, volume, content)
fsGroup := int64(1234) fsGroup := int64(1234)
testVolumeClient(cs, config, volume, &fsGroup, content) testVolumeClient(cs, config, &fsGroup, tests)
}) })
}) })
@ -758,21 +805,27 @@ var _ = framework.KubeDescribe("Volumes [Feature:Volumes]", func() {
volumeTestCleanup(f, config) volumeTestCleanup(f, config)
} }
}() }()
volume := v1.VolumeSource{
GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ tests := []VolumeTest{
PDName: volumeName, {
FSType: "ext3", volume: v1.VolumeSource{
ReadOnly: false, GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
PDName: volumeName,
FSType: "ext3",
ReadOnly: false,
},
},
file: "index.html",
// Randomize index.html to make sure we don't see the
// content from previous test runs.
expectedContent: "Hello from GCE from namespace " + volumeName,
}, },
} }
// Insert index.html into the test volume with some random content injectHtml(cs, config, tests[0].volume, tests[0].expectedContent)
// to make sure we don't see the content from previous test runs.
content := "Hello from GCE PD from namespace " + volumeName
injectHtml(cs, config, volume, content)
fsGroup := int64(1234) fsGroup := int64(1234)
testVolumeClient(cs, config, volume, &fsGroup, content) testVolumeClient(cs, config, &fsGroup, tests)
}) })
}) })
}) })