Merge pull request #88242 from jsafrane/cloning-test

Add block cloning test
This commit is contained in:
Kubernetes Prow Robot 2020-02-28 12:54:53 -08:00 committed by GitHub
commit 0046b4cefb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 99 additions and 14 deletions

View File

@ -19,6 +19,7 @@ package testsuites
import ( import (
"context" "context"
"fmt" "fmt"
"sync"
"time" "time"
"github.com/onsi/ginkgo" "github.com/onsi/ginkgo"
@ -74,6 +75,7 @@ func InitProvisioningTestSuite() TestSuite {
Name: "provisioning", Name: "provisioning",
TestPatterns: []testpatterns.TestPattern{ TestPatterns: []testpatterns.TestPattern{
testpatterns.DefaultFsDynamicPV, testpatterns.DefaultFsDynamicPV,
testpatterns.BlockVolModeDynamicPV,
testpatterns.NtfsDynamicPV, testpatterns.NtfsDynamicPV,
}, },
SupportedSizeRange: volume.SizeRange{ SupportedSizeRange: volume.SizeRange{
@ -115,6 +117,10 @@ func (p *provisioningTestSuite) DefineTests(driver TestDriver, pattern testpatte
if pattern.VolType != testpatterns.DynamicPV { if pattern.VolType != testpatterns.DynamicPV {
e2eskipper.Skipf("Suite %q does not support %v", p.tsInfo.Name, pattern.VolType) e2eskipper.Skipf("Suite %q does not support %v", p.tsInfo.Name, pattern.VolType)
} }
if pattern.VolMode == v1.PersistentVolumeBlock && !dInfo.Capabilities[CapBlock] {
e2eskipper.Skipf("Driver %q does not support block volumes - skipping", dInfo.Name)
}
ok := false ok := false
dDriver, ok = driver.(DynamicPVTestDriver) dDriver, ok = driver.(DynamicPVTestDriver)
if !ok { if !ok {
@ -147,10 +153,12 @@ func (p *provisioningTestSuite) DefineTests(driver TestDriver, pattern testpatte
l.pvc = e2epv.MakePersistentVolumeClaim(e2epv.PersistentVolumeClaimConfig{ l.pvc = e2epv.MakePersistentVolumeClaim(e2epv.PersistentVolumeClaimConfig{
ClaimSize: claimSize, ClaimSize: claimSize,
StorageClassName: &(l.sc.Name), StorageClassName: &(l.sc.Name),
VolumeMode: &pattern.VolMode,
}, l.config.Framework.Namespace.Name) }, l.config.Framework.Namespace.Name)
l.sourcePVC = e2epv.MakePersistentVolumeClaim(e2epv.PersistentVolumeClaimConfig{ l.sourcePVC = e2epv.MakePersistentVolumeClaim(e2epv.PersistentVolumeClaimConfig{
ClaimSize: claimSize, ClaimSize: claimSize,
StorageClassName: &(l.sc.Name), StorageClassName: &(l.sc.Name),
VolumeMode: &pattern.VolMode,
}, l.config.Framework.Namespace.Name) }, l.config.Framework.Namespace.Name)
framework.Logf("In creating storage class object and pvc objects for driver - sc: %v, pvc: %v, src-pvc: %v", l.sc, l.pvc, l.sourcePVC) framework.Logf("In creating storage class object and pvc objects for driver - sc: %v, pvc: %v, src-pvc: %v", l.sc, l.pvc, l.sourcePVC)
l.testCase = &StorageClassTest{ l.testCase = &StorageClassTest{
@ -160,6 +168,7 @@ func (p *provisioningTestSuite) DefineTests(driver TestDriver, pattern testpatte
Class: l.sc, Class: l.sc,
ClaimSize: claimSize, ClaimSize: claimSize,
ExpectedSize: claimSize, ExpectedSize: claimSize,
VolumeMode: pattern.VolMode,
} }
} }
@ -175,6 +184,9 @@ func (p *provisioningTestSuite) DefineTests(driver TestDriver, pattern testpatte
if dInfo.SupportedMountOption == nil { if dInfo.SupportedMountOption == nil {
e2eskipper.Skipf("Driver %q does not define supported mount option - skipping", dInfo.Name) e2eskipper.Skipf("Driver %q does not define supported mount option - skipping", dInfo.Name)
} }
if pattern.VolMode == v1.PersistentVolumeBlock {
e2eskipper.Skipf("Block volumes do not support mount options - skipping")
}
init() init()
defer cleanup() defer cleanup()
@ -212,26 +224,85 @@ func (p *provisioningTestSuite) DefineTests(driver TestDriver, pattern testpatte
} }
l.testCase.TestDynamicProvisioning() l.testCase.TestDynamicProvisioning()
}) })
ginkgo.It("should provision storage with pvc data source", func() { ginkgo.It("should provision storage with pvc data source", func() {
if !dInfo.Capabilities[CapPVCDataSource] { if !dInfo.Capabilities[CapPVCDataSource] {
e2eskipper.Skipf("Driver %q does not support cloning - skipping", dInfo.Name) e2eskipper.Skipf("Driver %q does not support cloning - skipping", dInfo.Name)
} }
init() init()
defer cleanup() defer cleanup()
dc := l.config.Framework.DynamicClient testConfig := convertTestConfig(l.config)
dataSource, dataSourceCleanup := preparePVCDataSourceForProvisioning(l.config.ClientNodeSelection, l.cs, dc, l.sourcePVC, l.sc) expectedContent := fmt.Sprintf("Hello from namespace %s", f.Namespace.Name)
dataSource, dataSourceCleanup := preparePVCDataSourceForProvisioning(f, testConfig, l.cs, l.sourcePVC, l.sc, pattern.VolMode, expectedContent)
defer dataSourceCleanup() defer dataSourceCleanup()
l.pvc.Spec.DataSource = dataSource l.pvc.Spec.DataSource = dataSource
l.testCase.PvCheck = func(claim *v1.PersistentVolumeClaim) { l.testCase.PvCheck = func(claim *v1.PersistentVolumeClaim) {
ginkgo.By("checking whether the created volume has the pre-populated data") ginkgo.By("checking whether the created volume has the pre-populated data")
command := fmt.Sprintf("grep '%s' /mnt/test/initialData", claim.Namespace) tests := []volume.Test{
RunInPodWithVolume(l.cs, claim.Namespace, claim.Name, "pvc-datasource-tester", command, l.config.ClientNodeSelection) {
Volume: *createVolumeSource(claim.Name, false /* readOnly */),
Mode: pattern.VolMode,
File: "index.html",
ExpectedContent: expectedContent,
},
}
volume.TestVolumeClient(f, testConfig, nil, "", tests)
} }
l.testCase.TestDynamicProvisioning() l.testCase.TestDynamicProvisioning()
}) })
ginkgo.It("should provision storage with pvc data source in parallel [Slow]", func() {
// Test cloning a single volume multiple times.
if !dInfo.Capabilities[CapPVCDataSource] {
e2eskipper.Skipf("Driver %q does not support cloning - skipping", dInfo.Name)
}
if pattern.VolMode == v1.PersistentVolumeBlock && !dInfo.Capabilities[CapBlock] {
e2eskipper.Skipf("Driver %q does not support block volumes - skipping", dInfo.Name)
}
init()
defer cleanup()
testConfig := convertTestConfig(l.config)
expectedContent := fmt.Sprintf("Hello from namespace %s", f.Namespace.Name)
dataSource, dataSourceCleanup := preparePVCDataSourceForProvisioning(f, testConfig, l.cs, l.sourcePVC, l.sc, pattern.VolMode, expectedContent)
defer dataSourceCleanup()
l.pvc.Spec.DataSource = dataSource
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func(i int) {
defer ginkgo.GinkgoRecover()
defer wg.Done()
ginkgo.By(fmt.Sprintf("Cloning volume nr. %d", i))
// Each go routine must have its own pod prefix
myTestConfig := testConfig
myTestConfig.Prefix = fmt.Sprintf("%s-%d", myTestConfig.Prefix, i)
// Each go routine must have its own testCase copy to store their claim
myTestCase := *l.testCase
myTestCase.Claim = myTestCase.Claim.DeepCopy()
myTestCase.Class = nil // Do not create/delete the storage class in TestDynamicProvisioning, it already exists.
myTestCase.PvCheck = func(claim *v1.PersistentVolumeClaim) {
ginkgo.By(fmt.Sprintf("checking whether the created volume %d has the pre-populated data", i))
tests := []volume.Test{
{
Volume: *createVolumeSource(claim.Name, false /* readOnly */),
Mode: pattern.VolMode,
File: "index.html",
ExpectedContent: expectedContent,
},
}
volume.TestVolumeClient(f, myTestConfig, nil, "", tests)
}
myTestCase.TestDynamicProvisioning()
}(i)
}
wg.Wait()
})
} }
// TestDynamicProvisioning tests dynamic provisioning with specified StorageClassTest // TestDynamicProvisioning tests dynamic provisioning with specified StorageClassTest
@ -701,16 +772,18 @@ func prepareSnapshotDataSourceForProvisioning(
} }
func preparePVCDataSourceForProvisioning( func preparePVCDataSourceForProvisioning(
node e2epod.NodeSelection, f *framework.Framework,
config volume.TestConfig,
client clientset.Interface, client clientset.Interface,
dynamicClient dynamic.Interface,
source *v1.PersistentVolumeClaim, source *v1.PersistentVolumeClaim,
class *storagev1.StorageClass, class *storagev1.StorageClass,
mode v1.PersistentVolumeMode,
injectContent string,
) (*v1.TypedLocalObjectReference, func()) { ) (*v1.TypedLocalObjectReference, func()) {
var err error var err error
if class != nil { if class != nil {
ginkgo.By("[Initialize dataSource]creating a StorageClass " + class.Name) ginkgo.By("[Initialize dataSource]creating a StorageClass " + class.Name)
_, err = client.StorageV1().StorageClasses().Create(context.TODO(), class, metav1.CreateOptions{}) class, err = client.StorageV1().StorageClasses().Create(context.TODO(), class, metav1.CreateOptions{})
framework.ExpectNoError(err) framework.ExpectNoError(err)
} }
@ -718,10 +791,15 @@ func preparePVCDataSourceForProvisioning(
sourcePVC, err := client.CoreV1().PersistentVolumeClaims(source.Namespace).Create(context.TODO(), source, metav1.CreateOptions{}) sourcePVC, err := client.CoreV1().PersistentVolumeClaims(source.Namespace).Create(context.TODO(), source, metav1.CreateOptions{})
framework.ExpectNoError(err) framework.ExpectNoError(err)
// write namespace to the /mnt/test (= the volume). tests := []volume.Test{
ginkgo.By("[Initialize dataSource]write data to volume") {
command := fmt.Sprintf("echo '%s' > /mnt/test/initialData", sourcePVC.GetNamespace()) Volume: *createVolumeSource(sourcePVC.Name, false /* readOnly */),
RunInPodWithVolume(client, sourcePVC.Namespace, sourcePVC.Name, "pvc-datasource-writer", command, node) Mode: mode,
File: "index.html",
ExpectedContent: injectContent,
},
}
volume.InjectContent(f, config, nil, "", tests)
dataSourceRef := &v1.TypedLocalObjectReference{ dataSourceRef := &v1.TypedLocalObjectReference{
Kind: "PersistentVolumeClaim", Kind: "PersistentVolumeClaim",
@ -730,10 +808,17 @@ func preparePVCDataSourceForProvisioning(
cleanupFunc := func() { cleanupFunc := func() {
framework.Logf("deleting source PVC %q/%q", sourcePVC.Namespace, sourcePVC.Name) framework.Logf("deleting source PVC %q/%q", sourcePVC.Namespace, sourcePVC.Name)
err = client.CoreV1().PersistentVolumeClaims(sourcePVC.Namespace).Delete(context.TODO(), sourcePVC.Name, nil) err := client.CoreV1().PersistentVolumeClaims(sourcePVC.Namespace).Delete(context.TODO(), sourcePVC.Name, nil)
if err != nil && !apierrors.IsNotFound(err) { if err != nil && !apierrors.IsNotFound(err) {
framework.Failf("Error deleting source PVC %q. Error: %v", sourcePVC.Name, err) framework.Failf("Error deleting source PVC %q. Error: %v", sourcePVC.Name, err)
} }
if class != nil {
framework.Logf("deleting class %q", class.Name)
err := client.StorageV1().StorageClasses().Delete(context.TODO(), class.Name, nil)
if err != nil && !apierrors.IsNotFound(err) {
framework.Failf("Error deleting storage class %q. Error: %v", class.Name, err)
}
}
} }
return dataSourceRef, cleanupFunc return dataSourceRef, cleanupFunc

View File

@ -65,7 +65,7 @@ spec:
name: csi-data-dir name: csi-data-dir
- name: hostpath - name: hostpath
image: quay.io/k8scsi/hostpathplugin:v1.3.0-rc1 image: quay.io/k8scsi/hostpathplugin:v1.4.0-rc1
args: args:
- "--drivername=hostpath.csi.k8s.io" - "--drivername=hostpath.csi.k8s.io"
- "--v=5" - "--v=5"