Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
f9684998
Unverified
Commit
f9684998
authored
Feb 12, 2019
by
Kubernetes Prow Robot
Committed by
GitHub
Feb 12, 2019
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #72002 from pohly/storage-volume-testsuites-concurrency
E2E storage: more tests for different pod/node combinations
parents
64ce2e59
ecc0c4e4
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
395 additions
and
184 deletions
+395
-184
csi_volumes.go
test/e2e/storage/csi_volumes.go
+23
-15
csi.go
test/e2e/storage/drivers/csi.go
+4
-2
regional_pd.go
test/e2e/storage/regional_pd.go
+19
-17
base.go
test/e2e/storage/testsuites/base.go
+23
-24
provisioning.go
test/e2e/storage/testsuites/provisioning.go
+254
-84
snapshottable.go
test/e2e/storage/testsuites/snapshottable.go
+15
-15
testdriver.go
test/e2e/storage/testsuites/testdriver.go
+7
-0
volume_provisioning.go
test/e2e/storage/volume_provisioning.go
+50
-27
No files found.
test/e2e/storage/csi_volumes.go
View file @
f9684998
...
...
@@ -261,9 +261,11 @@ var _ = utils.SIGDescribe("CSI Volumes", func() {
Parameters
:
sc
.
Parameters
,
ClaimSize
:
"1Gi"
,
ExpectedSize
:
"1Gi"
,
NodeName
:
nodeName
,
}
class
,
claim
,
pod
:=
startPausePod
(
cs
,
scTest
,
ns
.
Name
)
nodeSelection
:=
testsuites
.
NodeSelection
{
Name
:
nodeName
,
}
class
,
claim
,
pod
:=
startPausePod
(
cs
,
scTest
,
nodeSelection
,
ns
.
Name
)
if
class
!=
nil
{
defer
cs
.
StorageV1
()
.
StorageClasses
()
.
Delete
(
class
.
Name
,
nil
)
}
...
...
@@ -381,16 +383,16 @@ var _ = utils.SIGDescribe("CSI Volumes", func() {
Parameters
:
sc
.
Parameters
,
ClaimSize
:
"1Gi"
,
ExpectedSize
:
"1Gi"
,
// The mock driver only works when everything runs on a single node.
NodeName
:
nodeName
,
// Provisioner and storage class name must match what's used in
// csi-storageclass.yaml, plus the test-specific suffix.
Provisioner
:
sc
.
Provisioner
,
StorageClassName
:
"csi-mock-sc-"
+
f
.
UniqueName
,
// Mock driver does not provide any persistency.
SkipWriteReadCheck
:
true
,
}
class
,
claim
,
pod
:=
startPausePod
(
cs
,
scTest
,
ns
.
Name
)
nodeSelection
:=
testsuites
.
NodeSelection
{
// The mock driver only works when everything runs on a single node.
Name
:
nodeName
,
}
class
,
claim
,
pod
:=
startPausePod
(
cs
,
scTest
,
nodeSelection
,
ns
.
Name
)
if
class
!=
nil
{
defer
cs
.
StorageV1
()
.
StorageClasses
()
.
Delete
(
class
.
Name
,
nil
)
}
...
...
@@ -429,7 +431,7 @@ func testTopologyPositive(cs clientset.Interface, suffix, namespace string, dela
claim
.
Spec
.
StorageClassName
=
&
class
.
Name
if
delayBinding
{
_
,
node
:=
testsuites
.
TestBindingWaitForFirstConsumer
(
test
,
cs
,
claim
,
class
)
_
,
node
:=
testsuites
.
TestBindingWaitForFirstConsumer
(
test
,
cs
,
claim
,
class
,
nil
/* node selector */
,
false
/* expect unschedulable */
)
Expect
(
node
)
.
ToNot
(
BeNil
(),
"Unexpected nil node found"
)
}
else
{
testsuites
.
TestDynamicProvisioning
(
test
,
cs
,
claim
,
class
)
...
...
@@ -450,16 +452,22 @@ func testTopologyNegative(cs clientset.Interface, suffix, namespace string, dela
test
:=
createGCEPDStorageClassTest
()
test
.
DelayBinding
=
delayBinding
test
.
NodeSelector
=
map
[
string
]
string
{
v1
.
LabelZoneFailureDomain
:
podZone
}
test
.
ExpectUnschedulable
=
true
nodeSelector
:=
map
[
string
]
string
{
v1
.
LabelZoneFailureDomain
:
podZone
}
class
:=
newStorageClass
(
test
,
namespace
,
suffix
)
addSingleCSIZoneAllowedTopologyToStorageClass
(
cs
,
class
,
pvZone
)
claim
:=
newClaim
(
test
,
namespace
,
suffix
)
claim
.
Spec
.
StorageClassName
=
&
class
.
Name
if
delayBinding
{
testsuites
.
TestBindingWaitForFirstConsumer
(
test
,
cs
,
claim
,
class
)
testsuites
.
TestBindingWaitForFirstConsumer
(
test
,
cs
,
claim
,
class
,
nodeSelector
,
true
/* expect unschedulable */
)
}
else
{
test
.
PvCheck
=
func
(
claim
*
v1
.
PersistentVolumeClaim
,
volume
*
v1
.
PersistentVolume
)
{
// Ensure that a pod cannot be scheduled in an unsuitable zone.
pod
:=
testsuites
.
StartInPodWithVolume
(
cs
,
namespace
,
claim
.
Name
,
"pvc-tester-unschedulable"
,
"sleep 100000"
,
testsuites
.
NodeSelection
{
Selector
:
nodeSelector
})
defer
testsuites
.
StopPod
(
cs
,
pod
)
framework
.
ExpectNoError
(
framework
.
WaitForPodNameUnschedulableInNamespace
(
cs
,
pod
.
Name
,
pod
.
Namespace
),
"pod should be unschedulable"
)
}
testsuites
.
TestDynamicProvisioning
(
test
,
cs
,
claim
,
class
)
}
}
...
...
@@ -500,7 +508,7 @@ func getVolumeHandle(cs clientset.Interface, claim *v1.PersistentVolumeClaim) st
return
pv
.
Spec
.
CSI
.
VolumeHandle
}
func
startPausePod
(
cs
clientset
.
Interface
,
t
testsuites
.
StorageClassTest
,
ns
string
)
(
*
storagev1
.
StorageClass
,
*
v1
.
PersistentVolumeClaim
,
*
v1
.
Pod
)
{
func
startPausePod
(
cs
clientset
.
Interface
,
t
testsuites
.
StorageClassTest
,
n
ode
testsuites
.
NodeSelection
,
n
s
string
)
(
*
storagev1
.
StorageClass
,
*
v1
.
PersistentVolumeClaim
,
*
v1
.
Pod
)
{
class
:=
newStorageClass
(
t
,
ns
,
""
)
class
,
err
:=
cs
.
StorageV1
()
.
StorageClasses
()
.
Create
(
class
)
framework
.
ExpectNoError
(
err
,
"Failed to create class : %v"
,
err
)
...
...
@@ -514,6 +522,9 @@ func startPausePod(cs clientset.Interface, t testsuites.StorageClassTest, ns str
GenerateName
:
"pvc-volume-tester-"
,
},
Spec
:
v1
.
PodSpec
{
NodeName
:
node
.
Name
,
NodeSelector
:
node
.
Selector
,
Affinity
:
node
.
Affinity
,
Containers
:
[]
v1
.
Container
{
{
Name
:
"volume-tester"
,
...
...
@@ -541,9 +552,6 @@ func startPausePod(cs clientset.Interface, t testsuites.StorageClassTest, ns str
},
}
if
len
(
t
.
NodeName
)
!=
0
{
pod
.
Spec
.
NodeName
=
t
.
NodeName
}
pod
,
err
=
cs
.
CoreV1
()
.
Pods
(
ns
)
.
Create
(
pod
)
framework
.
ExpectNoError
(
err
,
"Failed to create pod: %v"
,
err
)
return
class
,
claim
,
pod
...
...
test/e2e/storage/drivers/csi.go
View file @
f9684998
...
...
@@ -84,7 +84,7 @@ var _ testsuites.SnapshottableTestDriver = &hostpathCSIDriver{}
// InitHostPathCSIDriver returns hostpathCSIDriver that implements TestDriver interface
func
InitHostPathCSIDriver
(
config
testsuites
.
TestConfig
)
testsuites
.
TestDriver
{
return
initHostPathCSIDriver
(
"csi-hostpath"
,
config
,
map
[
testsuites
.
Capability
]
bool
{
testsuites
.
CapPersistence
:
true
,
testsuites
.
CapDataSource
:
true
},
map
[
testsuites
.
Capability
]
bool
{
testsuites
.
CapPersistence
:
true
,
testsuites
.
CapDataSource
:
true
,
testsuites
.
CapMultiPODs
:
true
},
"test/e2e/testing-manifests/storage-csi/driver-registrar/rbac.yaml"
,
"test/e2e/testing-manifests/storage-csi/external-attacher/rbac.yaml"
,
"test/e2e/testing-manifests/storage-csi/external-provisioner/rbac.yaml"
,
...
...
@@ -259,7 +259,7 @@ func (m *mockCSIDriver) CleanupDriver() {
// InitHostPathV0CSIDriver returns a variant of hostpathCSIDriver with different manifests.
func
InitHostPathV0CSIDriver
(
config
testsuites
.
TestConfig
)
testsuites
.
TestDriver
{
return
initHostPathCSIDriver
(
"csi-hostpath-v0"
,
config
,
map
[
testsuites
.
Capability
]
bool
{
testsuites
.
CapPersistence
:
true
},
map
[
testsuites
.
Capability
]
bool
{
testsuites
.
CapPersistence
:
true
,
testsuites
.
CapMultiPODs
:
true
},
"test/e2e/testing-manifests/storage-csi/driver-registrar/rbac.yaml"
,
"test/e2e/testing-manifests/storage-csi/external-attacher/rbac.yaml"
,
"test/e2e/testing-manifests/storage-csi/external-provisioner/rbac.yaml"
,
...
...
@@ -297,6 +297,7 @@ func InitGcePDCSIDriver(config testsuites.TestConfig) testsuites.TestDriver {
testsuites
.
CapPersistence
:
true
,
testsuites
.
CapFsGroup
:
true
,
testsuites
.
CapExec
:
true
,
testsuites
.
CapMultiPODs
:
true
,
},
Config
:
config
,
...
...
@@ -409,6 +410,7 @@ func InitGcePDExternalCSIDriver(config testsuites.TestConfig) testsuites.TestDri
testsuites
.
CapPersistence
:
true
,
testsuites
.
CapFsGroup
:
true
,
testsuites
.
CapExec
:
true
,
testsuites
.
CapMultiPODs
:
true
,
},
Config
:
config
,
...
...
test/e2e/storage/regional_pd.go
View file @
f9684998
...
...
@@ -108,12 +108,14 @@ func testVolumeProvisioning(c clientset.Interface, ns string) {
},
ClaimSize
:
"1.5Gi"
,
ExpectedSize
:
"2Gi"
,
PvCheck
:
func
(
volume
*
v1
.
PersistentVolume
)
error
{
err
:=
checkGCEPD
(
volume
,
"pd-standard"
)
if
err
!=
nil
{
return
err
}
return
verifyZonesInPV
(
volume
,
sets
.
NewString
(
cloudZones
...
),
true
/* match */
)
PvCheck
:
func
(
claim
*
v1
.
PersistentVolumeClaim
,
volume
*
v1
.
PersistentVolume
)
{
var
err
error
err
=
checkGCEPD
(
volume
,
"pd-standard"
)
Expect
(
err
)
.
NotTo
(
HaveOccurred
(),
"checkGCEPD"
)
err
=
verifyZonesInPV
(
volume
,
sets
.
NewString
(
cloudZones
...
),
true
/* match */
)
Expect
(
err
)
.
NotTo
(
HaveOccurred
(),
"verifyZonesInPV"
)
testsuites
.
PVWriteReadSingleNodeCheck
(
c
,
claim
,
volume
,
testsuites
.
NodeSelection
{})
},
},
{
...
...
@@ -126,16 +128,16 @@ func testVolumeProvisioning(c clientset.Interface, ns string) {
},
ClaimSize
:
"1.5Gi"
,
ExpectedSize
:
"2Gi"
,
PvCheck
:
func
(
volume
*
v1
.
PersistentVolume
)
error
{
err
:=
checkGCEPD
(
volume
,
"pd-standard"
)
if
err
!=
nil
{
return
err
}
PvCheck
:
func
(
claim
*
v1
.
PersistentVolumeClaim
,
volume
*
v1
.
PersistentVolume
)
{
var
err
error
err
=
checkGCEPD
(
volume
,
"pd-standard"
)
Expect
(
err
)
.
NotTo
(
HaveOccurred
(),
"checkGCEPD"
)
zones
,
err
:=
framework
.
GetClusterZones
(
c
)
if
err
!=
nil
{
return
err
}
return
verifyZonesInPV
(
volume
,
zones
,
false
/* match */
)
Expect
(
err
)
.
NotTo
(
HaveOccurred
(),
"GetClusterZones"
)
err
=
verifyZonesInPV
(
volume
,
zones
,
false
/* match */
)
Expect
(
err
)
.
NotTo
(
HaveOccurred
(),
"verifyZonesInPV"
)
testsuites
.
PVWriteReadSingleNodeCheck
(
c
,
claim
,
volume
,
testsuites
.
NodeSelection
{})
},
},
}
...
...
@@ -317,7 +319,7 @@ func testRegionalDelayedBinding(c clientset.Interface, ns string, pvcCount int)
claim
.
Spec
.
StorageClassName
=
&
class
.
Name
claims
=
append
(
claims
,
claim
)
}
pvs
,
node
:=
testsuites
.
TestBindingWaitForFirstConsumerMultiPVC
(
test
,
c
,
claims
,
class
)
pvs
,
node
:=
testsuites
.
TestBindingWaitForFirstConsumerMultiPVC
(
test
,
c
,
claims
,
class
,
nil
/* node selector */
,
false
/* expect unschedulable */
)
if
node
==
nil
{
framework
.
Failf
(
"unexpected nil node found"
)
}
...
...
@@ -374,7 +376,7 @@ func testRegionalAllowedTopologiesWithDelayedBinding(c clientset.Interface, ns s
claim
.
Spec
.
StorageClassName
=
&
class
.
Name
claims
=
append
(
claims
,
claim
)
}
pvs
,
node
:=
testsuites
.
TestBindingWaitForFirstConsumerMultiPVC
(
test
,
c
,
claims
,
class
)
pvs
,
node
:=
testsuites
.
TestBindingWaitForFirstConsumerMultiPVC
(
test
,
c
,
claims
,
class
,
nil
/* node selector */
,
false
/* expect unschedulable */
)
if
node
==
nil
{
framework
.
Failf
(
"unexpected nil node found"
)
}
...
...
test/e2e/storage/testsuites/base.go
View file @
f9684998
...
...
@@ -91,7 +91,7 @@ func skipUnsupportedTest(suite TestSuite, driver TestDriver, pattern testpattern
var
isSupported
bool
// 1. Check if Whether SnapshotType is supported by driver from its interface
// if isSupported,
so it must be a snapshot test case, we just return.
// if isSupported,
we still execute the driver and suite tests
if
len
(
pattern
.
SnapshotType
)
>
0
{
switch
pattern
.
SnapshotType
{
case
testpatterns
.
DynamicCreatedSnapshot
:
...
...
@@ -102,31 +102,30 @@ func skipUnsupportedTest(suite TestSuite, driver TestDriver, pattern testpattern
if
!
isSupported
{
framework
.
Skipf
(
"Driver %s doesn't support snapshot type %v -- skipping"
,
dInfo
.
Name
,
pattern
.
SnapshotType
)
}
return
}
// 2. Check if Whether volType is supported by driver from its interface
switch
pattern
.
VolType
{
case
testpatterns
.
InlineVolume
:
_
,
isSupported
=
driver
.
(
InlineVolumeTestDriver
)
case
testpatterns
.
PreprovisionedPV
:
_
,
isSupported
=
driver
.
(
PreprovisionedPVTestDriver
)
case
testpatterns
.
DynamicPV
:
_
,
isSupported
=
driver
.
(
DynamicPVTestDriver
)
default
:
isSupported
=
false
}
}
else
{
// 2. Check if Whether volType is supported by driver from its interface
switch
pattern
.
VolType
{
case
testpatterns
.
InlineVolume
:
_
,
isSupported
=
driver
.
(
InlineVolumeTestDriver
)
case
testpatterns
.
PreprovisionedPV
:
_
,
isSupported
=
driver
.
(
PreprovisionedPVTestDriver
)
case
testpatterns
.
DynamicPV
:
_
,
isSupported
=
driver
.
(
DynamicPVTestDriver
)
default
:
isSupported
=
false
}
if
!
isSupported
{
framework
.
Skipf
(
"Driver %s doesn't support %v -- skipping"
,
dInfo
.
Name
,
pattern
.
VolType
)
}
if
!
isSupported
{
framework
.
Skipf
(
"Driver %s doesn't support %v -- skipping"
,
dInfo
.
Name
,
pattern
.
VolType
)
}
// 3. Check if fsType is supported
if
!
dInfo
.
SupportedFsType
.
Has
(
pattern
.
FsType
)
{
framework
.
Skipf
(
"Driver %s doesn't support %v -- skipping"
,
dInfo
.
Name
,
pattern
.
FsType
)
}
if
pattern
.
FsType
==
"xfs"
&&
framework
.
NodeOSDistroIs
(
"gci"
)
{
framework
.
Skipf
(
"Distro doesn't support xfs -- skipping"
)
// 3. Check if fsType is supported
if
!
dInfo
.
SupportedFsType
.
Has
(
pattern
.
FsType
)
{
framework
.
Skipf
(
"Driver %s doesn't support %v -- skipping"
,
dInfo
.
Name
,
pattern
.
FsType
)
}
if
pattern
.
FsType
==
"xfs"
&&
framework
.
NodeOSDistroIs
(
"gci"
)
{
framework
.
Skipf
(
"Distro doesn't support xfs -- skipping"
)
}
}
// 4. Check with driver specific logic
...
...
test/e2e/storage/testsuites/provisioning.go
View file @
f9684998
...
...
@@ -18,6 +18,7 @@ package testsuites
import
(
"fmt"
"sync"
"time"
.
"github.com/onsi/ginkgo"
...
...
@@ -37,22 +38,19 @@ import (
imageutils
"k8s.io/kubernetes/test/utils/image"
)
// StorageClassTest represents parameters to be used by provisioning tests
// StorageClassTest represents parameters to be used by provisioning tests.
// Not all parameters are used by all tests.
type
StorageClassTest
struct
{
Name
string
CloudProviders
[]
string
Provisioner
string
StorageClassName
string
Parameters
map
[
string
]
string
DelayBinding
bool
ClaimSize
string
ExpectedSize
string
PvCheck
func
(
volume
*
v1
.
PersistentVolume
)
error
NodeName
string
SkipWriteReadCheck
bool
VolumeMode
*
v1
.
PersistentVolumeMode
NodeSelector
map
[
string
]
string
// NodeSelector for the pod
ExpectUnschedulable
bool
// Whether the test pod is expected to be unschedulable
Name
string
CloudProviders
[]
string
Provisioner
string
StorageClassName
string
Parameters
map
[
string
]
string
DelayBinding
bool
ClaimSize
string
ExpectedSize
string
PvCheck
func
(
claim
*
v1
.
PersistentVolumeClaim
,
volume
*
v1
.
PersistentVolume
)
VolumeMode
*
v1
.
PersistentVolumeMode
}
type
provisioningTestSuite
struct
{
...
...
@@ -90,16 +88,13 @@ func createProvisioningTestInput(driver TestDriver, pattern testpatterns.TestPat
ClaimSize
:
resource
.
claimSize
,
ExpectedSize
:
resource
.
claimSize
,
},
cs
:
driver
.
GetDriverInfo
()
.
Config
.
Framework
.
ClientSet
,
dc
:
driver
.
GetDriverInfo
()
.
Config
.
Framework
.
DynamicClient
,
pvc
:
resource
.
pvc
,
sc
:
resource
.
sc
,
vsc
:
resource
.
vsc
,
dInfo
:
driver
.
GetDriverInfo
(),
}
if
driver
.
GetDriverInfo
()
.
Config
.
ClientNodeName
!=
""
{
input
.
testCase
.
NodeName
=
driver
.
GetDriverInfo
()
.
Config
.
ClientNodeName
cs
:
driver
.
GetDriverInfo
()
.
Config
.
Framework
.
ClientSet
,
dc
:
driver
.
GetDriverInfo
()
.
Config
.
Framework
.
DynamicClient
,
pvc
:
resource
.
pvc
,
sc
:
resource
.
sc
,
vsc
:
resource
.
vsc
,
dInfo
:
driver
.
GetDriverInfo
(),
nodeName
:
driver
.
GetDriverInfo
()
.
Config
.
ClientNodeName
,
}
return
resource
,
input
...
...
@@ -182,10 +177,17 @@ type provisioningTestInput struct {
sc
*
storage
.
StorageClass
vsc
*
unstructured
.
Unstructured
dInfo
*
DriverInfo
nodeName
string
}
func
testProvisioning
(
input
*
provisioningTestInput
)
{
// common checker for most of the test cases below
pvcheck
:=
func
(
claim
*
v1
.
PersistentVolumeClaim
,
volume
*
v1
.
PersistentVolume
)
{
PVWriteReadSingleNodeCheck
(
input
.
cs
,
claim
,
volume
,
NodeSelection
{
Name
:
input
.
nodeName
})
}
It
(
"should provision storage with defaults"
,
func
()
{
input
.
testCase
.
PvCheck
=
pvcheck
TestDynamicProvisioning
(
input
.
testCase
,
input
.
cs
,
input
.
pvc
,
input
.
sc
)
})
...
...
@@ -195,6 +197,26 @@ func testProvisioning(input *provisioningTestInput) {
}
input
.
sc
.
MountOptions
=
input
.
dInfo
.
SupportedMountOption
.
Union
(
input
.
dInfo
.
RequiredMountOption
)
.
List
()
input
.
testCase
.
PvCheck
=
pvcheck
TestDynamicProvisioning
(
input
.
testCase
,
input
.
cs
,
input
.
pvc
,
input
.
sc
)
})
It
(
"should access volume from different nodes"
,
func
()
{
// The assumption is that if the test hasn't been
// locked onto a single node, then the driver is
// usable on all of them *and* supports accessing a volume
// from any node.
if
input
.
nodeName
!=
""
{
framework
.
Skipf
(
"Driver %q only supports testing on one node - skipping"
,
input
.
dInfo
.
Name
)
}
// Ensure that we actually have more than one node.
nodes
:=
framework
.
GetReadySchedulableNodesOrDie
(
input
.
cs
)
if
len
(
nodes
.
Items
)
<=
1
{
framework
.
Skipf
(
"need more than one node - skipping"
)
}
input
.
testCase
.
PvCheck
=
func
(
claim
*
v1
.
PersistentVolumeClaim
,
volume
*
v1
.
PersistentVolume
)
{
PVMultiNodeCheck
(
input
.
cs
,
claim
,
volume
,
NodeSelection
{
Name
:
input
.
nodeName
})
}
TestDynamicProvisioning
(
input
.
testCase
,
input
.
cs
,
input
.
pvc
,
input
.
sc
)
})
...
...
@@ -204,7 +226,6 @@ func testProvisioning(input *provisioningTestInput) {
}
block
:=
v1
.
PersistentVolumeBlock
input
.
testCase
.
VolumeMode
=
&
block
input
.
testCase
.
SkipWriteReadCheck
=
true
input
.
pvc
.
Spec
.
VolumeMode
=
&
block
TestDynamicProvisioning
(
input
.
testCase
,
input
.
cs
,
input
.
pvc
,
input
.
sc
)
})
...
...
@@ -214,11 +235,59 @@ func testProvisioning(input *provisioningTestInput) {
framework
.
Skipf
(
"Driver %q does not support populate data from snapshot - skipping"
,
input
.
dInfo
.
Name
)
}
input
.
testCase
.
SkipWriteReadCheck
=
true
dataSource
,
cleanupFunc
:=
prepareDataSourceForProvisioning
(
input
.
testCase
,
input
.
cs
,
input
.
dc
,
input
.
pvc
,
input
.
sc
,
input
.
vsc
)
dataSource
,
cleanupFunc
:=
prepareDataSourceForProvisioning
(
NodeSelection
{
Name
:
input
.
nodeName
},
input
.
cs
,
input
.
dc
,
input
.
pvc
,
input
.
sc
,
input
.
vsc
)
defer
cleanupFunc
()
input
.
pvc
.
Spec
.
DataSource
=
dataSource
input
.
testCase
.
PvCheck
=
func
(
claim
*
v1
.
PersistentVolumeClaim
,
volume
*
v1
.
PersistentVolume
)
{
By
(
"checking whether the created volume has the pre-populated data"
)
command
:=
fmt
.
Sprintf
(
"grep '%s' /mnt/test/initialData"
,
claim
.
Namespace
)
RunInPodWithVolume
(
input
.
cs
,
claim
.
Namespace
,
claim
.
Name
,
"pvc-snapshot-tester"
,
command
,
NodeSelection
{
Name
:
input
.
nodeName
})
}
TestDynamicProvisioning
(
input
.
testCase
,
input
.
cs
,
input
.
pvc
,
input
.
sc
)
})
It
(
"should allow concurrent writes on the same node"
,
func
()
{
if
!
input
.
dInfo
.
Capabilities
[
CapMultiPODs
]
{
framework
.
Skipf
(
"Driver %q does not support multiple concurrent pods - skipping"
,
input
.
dInfo
.
Name
)
}
input
.
testCase
.
PvCheck
=
func
(
claim
*
v1
.
PersistentVolumeClaim
,
volume
*
v1
.
PersistentVolume
)
{
// We start two pods concurrently on the same node,
// using the same PVC. Both wait for other to create a
// file before returning. The pods are forced onto the
// same node via pod affinity.
wg
:=
sync
.
WaitGroup
{}
wg
.
Add
(
2
)
firstPodName
:=
"pvc-tester-first"
secondPodName
:=
"pvc-tester-second"
run
:=
func
(
podName
,
command
string
)
{
defer
GinkgoRecover
()
defer
wg
.
Done
()
node
:=
NodeSelection
{
Name
:
input
.
nodeName
,
}
if
podName
==
secondPodName
{
node
.
Affinity
=
&
v1
.
Affinity
{
PodAffinity
:
&
v1
.
PodAffinity
{
RequiredDuringSchedulingIgnoredDuringExecution
:
[]
v1
.
PodAffinityTerm
{
{
LabelSelector
:
&
metav1
.
LabelSelector
{
MatchLabels
:
map
[
string
]
string
{
// Set by RunInPodWithVolume.
"app"
:
firstPodName
,
},
},
TopologyKey
:
"kubernetes.io/hostname"
,
},
},
},
}
}
RunInPodWithVolume
(
input
.
cs
,
claim
.
Namespace
,
claim
.
Name
,
podName
,
command
,
node
)
}
go
run
(
firstPodName
,
"touch /mnt/test/first && while ! [ -f /mnt/test/second ]; do sleep 1; done"
)
go
run
(
secondPodName
,
"touch /mnt/test/second && while ! [ -f /mnt/test/first ]; do sleep 1; done"
)
wg
.
Wait
()
}
TestDynamicProvisioning
(
input
.
testCase
,
input
.
cs
,
input
.
pvc
,
input
.
sc
)
})
}
...
...
@@ -291,35 +360,7 @@ func TestDynamicProvisioning(t StorageClassTest, client clientset.Interface, cla
// Run the checker
if
t
.
PvCheck
!=
nil
{
err
=
t
.
PvCheck
(
pv
)
Expect
(
err
)
.
NotTo
(
HaveOccurred
())
}
if
claim
.
Spec
.
DataSource
!=
nil
{
By
(
"checking the created volume whether has the pre-populated data"
)
command
:=
fmt
.
Sprintf
(
"grep '%s' /mnt/test/initialData"
,
claim
.
Namespace
)
runInPodWithVolume
(
client
,
claim
.
Namespace
,
claim
.
Name
,
t
.
NodeName
,
command
,
t
.
NodeSelector
,
t
.
ExpectUnschedulable
)
}
if
!
t
.
SkipWriteReadCheck
{
// We start two pods:
// - The first writes 'hello word' to the /mnt/test (= the volume).
// - The second one runs grep 'hello world' on /mnt/test.
// If both succeed, Kubernetes actually allocated something that is
// persistent across pods.
By
(
"checking the created volume is writable and has the PV's mount options"
)
command
:=
"echo 'hello world' > /mnt/test/data"
// We give the first pod the secondary responsibility of checking the volume has
// been mounted with the PV's mount options, if the PV was provisioned with any
for
_
,
option
:=
range
pv
.
Spec
.
MountOptions
{
// Get entry, get mount options at 6th word, replace brackets with commas
command
+=
fmt
.
Sprintf
(
" && ( mount | grep 'on /mnt/test' | awk '{print $6}' | sed 's/^(/,/; s/)$/,/' | grep -q ,%s, )"
,
option
)
}
command
+=
" || (mount | grep 'on /mnt/test'; false)"
runInPodWithVolume
(
client
,
claim
.
Namespace
,
claim
.
Name
,
t
.
NodeName
,
command
,
t
.
NodeSelector
,
t
.
ExpectUnschedulable
)
By
(
"checking the created volume is readable and retains data"
)
runInPodWithVolume
(
client
,
claim
.
Namespace
,
claim
.
Name
,
t
.
NodeName
,
"grep 'hello world' /mnt/test/data"
,
t
.
NodeSelector
,
t
.
ExpectUnschedulable
)
t
.
PvCheck
(
claim
,
pv
)
}
By
(
fmt
.
Sprintf
(
"deleting claim %q/%q"
,
claim
.
Namespace
,
claim
.
Name
))
...
...
@@ -340,15 +381,125 @@ func TestDynamicProvisioning(t StorageClassTest, client clientset.Interface, cla
return
pv
}
func
TestBindingWaitForFirstConsumer
(
t
StorageClassTest
,
client
clientset
.
Interface
,
claim
*
v1
.
PersistentVolumeClaim
,
class
*
storage
.
StorageClass
)
(
*
v1
.
PersistentVolume
,
*
v1
.
Node
)
{
pvs
,
node
:=
TestBindingWaitForFirstConsumerMultiPVC
(
t
,
client
,
[]
*
v1
.
PersistentVolumeClaim
{
claim
},
class
)
// PVWriteReadSingleNodeCheck checks that a PV retains data on a single node.
//
// It starts two pods:
// - The first pod writes 'hello word' to the /mnt/test (= the volume) on one node.
// - The second pod runs grep 'hello world' on /mnt/test on the same node.
//
// The node is selected by Kubernetes when scheduling the first
// pod. It's then selected via its name for the second pod.
//
// If both succeed, Kubernetes actually allocated something that is
// persistent across pods.
//
// This is a common test that can be called from a StorageClassTest.PvCheck.
func
PVWriteReadSingleNodeCheck
(
client
clientset
.
Interface
,
claim
*
v1
.
PersistentVolumeClaim
,
volume
*
v1
.
PersistentVolume
,
node
NodeSelection
)
{
By
(
fmt
.
Sprintf
(
"checking the created volume is writable and has the PV's mount options on node %+v"
,
node
))
command
:=
"echo 'hello world' > /mnt/test/data"
// We give the first pod the secondary responsibility of checking the volume has
// been mounted with the PV's mount options, if the PV was provisioned with any
for
_
,
option
:=
range
volume
.
Spec
.
MountOptions
{
// Get entry, get mount options at 6th word, replace brackets with commas
command
+=
fmt
.
Sprintf
(
" && ( mount | grep 'on /mnt/test' | awk '{print $6}' | sed 's/^(/,/; s/)$/,/' | grep -q ,%s, )"
,
option
)
}
command
+=
" || (mount | grep 'on /mnt/test'; false)"
pod
:=
StartInPodWithVolume
(
client
,
claim
.
Namespace
,
claim
.
Name
,
"pvc-volume-tester-writer"
,
command
,
node
)
defer
func
()
{
// pod might be nil now.
StopPod
(
client
,
pod
)
}()
framework
.
ExpectNoError
(
framework
.
WaitForPodSuccessInNamespaceSlow
(
client
,
pod
.
Name
,
pod
.
Namespace
))
runningPod
,
err
:=
client
.
CoreV1
()
.
Pods
(
pod
.
Namespace
)
.
Get
(
pod
.
Name
,
metav1
.
GetOptions
{})
Expect
(
err
)
.
NotTo
(
HaveOccurred
(),
"get pod"
)
actualNodeName
:=
runningPod
.
Spec
.
NodeName
StopPod
(
client
,
pod
)
pod
=
nil
// Don't stop twice.
By
(
fmt
.
Sprintf
(
"checking the created volume is readable and retains data on the same node %q"
,
actualNodeName
))
command
=
"grep 'hello world' /mnt/test/data"
RunInPodWithVolume
(
client
,
claim
.
Namespace
,
claim
.
Name
,
"pvc-volume-tester-reader"
,
command
,
NodeSelection
{
Name
:
actualNodeName
})
}
// PVMultiNodeCheck checks that a PV retains data when moved between nodes.
//
// It starts these pods:
// - The first pod writes 'hello word' to the /mnt/test (= the volume) on one node.
// - The second pod runs grep 'hello world' on /mnt/test on another node.
//
// The first node is selected by Kubernetes when scheduling the first pod. The second pod uses the same criteria, except that a special anti-affinity
// for the first node gets added. This test can only pass if the cluster has more than one
// suitable node. The caller has to ensure that.
//
// If all succeeds, Kubernetes actually allocated something that is
// persistent across pods and across nodes.
//
// This is a common test that can be called from a StorageClassTest.PvCheck.
func
PVMultiNodeCheck
(
client
clientset
.
Interface
,
claim
*
v1
.
PersistentVolumeClaim
,
volume
*
v1
.
PersistentVolume
,
node
NodeSelection
)
{
Expect
(
node
.
Name
)
.
To
(
Equal
(
""
),
"this test only works when not locked onto a single node"
)
var
pod
*
v1
.
Pod
defer
func
()
{
// passing pod = nil is okay.
StopPod
(
client
,
pod
)
}()
By
(
fmt
.
Sprintf
(
"checking the created volume is writable and has the PV's mount options on node %+v"
,
node
))
command
:=
"echo 'hello world' > /mnt/test/data"
pod
=
StartInPodWithVolume
(
client
,
claim
.
Namespace
,
claim
.
Name
,
"pvc-writer-node1"
,
command
,
node
)
framework
.
ExpectNoError
(
framework
.
WaitForPodSuccessInNamespaceSlow
(
client
,
pod
.
Name
,
pod
.
Namespace
))
runningPod
,
err
:=
client
.
CoreV1
()
.
Pods
(
pod
.
Namespace
)
.
Get
(
pod
.
Name
,
metav1
.
GetOptions
{})
Expect
(
err
)
.
NotTo
(
HaveOccurred
(),
"get pod"
)
actualNodeName
:=
runningPod
.
Spec
.
NodeName
StopPod
(
client
,
pod
)
pod
=
nil
// Don't stop twice.
// Add node-anti-affinity.
secondNode
:=
node
if
secondNode
.
Affinity
==
nil
{
secondNode
.
Affinity
=
&
v1
.
Affinity
{}
}
if
secondNode
.
Affinity
.
NodeAffinity
==
nil
{
secondNode
.
Affinity
.
NodeAffinity
=
&
v1
.
NodeAffinity
{}
}
if
secondNode
.
Affinity
.
NodeAffinity
.
RequiredDuringSchedulingIgnoredDuringExecution
==
nil
{
secondNode
.
Affinity
.
NodeAffinity
.
RequiredDuringSchedulingIgnoredDuringExecution
=
&
v1
.
NodeSelector
{}
}
secondNode
.
Affinity
.
NodeAffinity
.
RequiredDuringSchedulingIgnoredDuringExecution
.
NodeSelectorTerms
=
append
(
secondNode
.
Affinity
.
NodeAffinity
.
RequiredDuringSchedulingIgnoredDuringExecution
.
NodeSelectorTerms
,
v1
.
NodeSelectorTerm
{
// https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity warns
// that "the value of kubernetes.io/hostname may be the same as the Node name in some environments and a different value in other environments".
// So this might be cleaner:
// MatchFields: []v1.NodeSelectorRequirement{
// {Key: "name", Operator: v1.NodeSelectorOpNotIn, Values: []string{actualNodeName}},
// },
// However, "name", "Name", "ObjectMeta.Name" all got rejected with "not a valid field selector key".
MatchExpressions
:
[]
v1
.
NodeSelectorRequirement
{
{
Key
:
"kubernetes.io/hostname"
,
Operator
:
v1
.
NodeSelectorOpNotIn
,
Values
:
[]
string
{
actualNodeName
}},
},
})
By
(
fmt
.
Sprintf
(
"checking the created volume is readable and retains data on another node %+v"
,
secondNode
))
command
=
"grep 'hello world' /mnt/test/data"
pod
=
StartInPodWithVolume
(
client
,
claim
.
Namespace
,
claim
.
Name
,
"pvc-reader-node2"
,
command
,
secondNode
)
framework
.
ExpectNoError
(
framework
.
WaitForPodSuccessInNamespaceSlow
(
client
,
pod
.
Name
,
pod
.
Namespace
))
runningPod
,
err
=
client
.
CoreV1
()
.
Pods
(
pod
.
Namespace
)
.
Get
(
pod
.
Name
,
metav1
.
GetOptions
{})
Expect
(
err
)
.
NotTo
(
HaveOccurred
(),
"get pod"
)
Expect
(
runningPod
.
Spec
.
NodeName
)
.
NotTo
(
Equal
(
actualNodeName
),
"second pod should have run on a different node"
)
StopPod
(
client
,
pod
)
pod
=
nil
}
func
TestBindingWaitForFirstConsumer
(
t
StorageClassTest
,
client
clientset
.
Interface
,
claim
*
v1
.
PersistentVolumeClaim
,
class
*
storage
.
StorageClass
,
nodeSelector
map
[
string
]
string
,
expectUnschedulable
bool
)
(
*
v1
.
PersistentVolume
,
*
v1
.
Node
)
{
pvs
,
node
:=
TestBindingWaitForFirstConsumerMultiPVC
(
t
,
client
,
[]
*
v1
.
PersistentVolumeClaim
{
claim
},
class
,
nodeSelector
,
expectUnschedulable
)
if
pvs
==
nil
{
return
nil
,
node
}
return
pvs
[
0
],
node
}
func
TestBindingWaitForFirstConsumerMultiPVC
(
t
StorageClassTest
,
client
clientset
.
Interface
,
claims
[]
*
v1
.
PersistentVolumeClaim
,
class
*
storage
.
StorageClass
)
([]
*
v1
.
PersistentVolume
,
*
v1
.
Node
)
{
func
TestBindingWaitForFirstConsumerMultiPVC
(
t
StorageClassTest
,
client
clientset
.
Interface
,
claims
[]
*
v1
.
PersistentVolumeClaim
,
class
*
storage
.
StorageClass
,
nodeSelector
map
[
string
]
string
,
expectUnschedulable
bool
)
([]
*
v1
.
PersistentVolume
,
*
v1
.
Node
)
{
var
err
error
Expect
(
len
(
claims
))
.
ToNot
(
Equal
(
0
))
namespace
:=
claims
[
0
]
.
Namespace
...
...
@@ -391,8 +542,8 @@ func TestBindingWaitForFirstConsumerMultiPVC(t StorageClassTest, client clientse
By
(
"creating a pod referring to the claims"
)
// Create a pod referring to the claim and wait for it to get to running
var
pod
*
v1
.
Pod
if
t
.
E
xpectUnschedulable
{
pod
,
err
=
framework
.
CreateUnschedulablePod
(
client
,
namespace
,
t
.
N
odeSelector
,
createdClaims
,
true
/* isPrivileged */
,
""
/* command */
)
if
e
xpectUnschedulable
{
pod
,
err
=
framework
.
CreateUnschedulablePod
(
client
,
namespace
,
n
odeSelector
,
createdClaims
,
true
/* isPrivileged */
,
""
/* command */
)
}
else
{
pod
,
err
=
framework
.
CreatePod
(
client
,
namespace
,
nil
/* nodeSelector */
,
createdClaims
,
true
/* isPrivileged */
,
""
/* command */
)
}
...
...
@@ -401,7 +552,7 @@ func TestBindingWaitForFirstConsumerMultiPVC(t StorageClassTest, client clientse
framework
.
DeletePodOrFail
(
client
,
pod
.
Namespace
,
pod
.
Name
)
framework
.
WaitForPodToDisappear
(
client
,
pod
.
Namespace
,
pod
.
Name
,
labels
.
Everything
(),
framework
.
Poll
,
framework
.
PodDeleteTimeout
)
}()
if
t
.
E
xpectUnschedulable
{
if
e
xpectUnschedulable
{
// Verify that no claims are provisioned.
verifyPVCsPending
(
client
,
createdClaims
)
return
nil
,
nil
...
...
@@ -429,17 +580,40 @@ func TestBindingWaitForFirstConsumerMultiPVC(t StorageClassTest, client clientse
return
pvs
,
node
}
// runInPodWithVolume runs a command in a pod with given claim mounted to /mnt directory.
func
runInPodWithVolume
(
c
clientset
.
Interface
,
ns
,
claimName
,
nodeName
,
command
string
,
nodeSelector
map
[
string
]
string
,
unschedulable
bool
)
{
// NodeSelection specifies where to run a pod, using a combination of fixed node name,
// node selector and/or affinity.
type
NodeSelection
struct
{
Name
string
Selector
map
[
string
]
string
Affinity
*
v1
.
Affinity
}
// RunInPodWithVolume runs a command in a pod with given claim mounted to /mnt directory.
// It starts, checks, collects output and stops it.
func
RunInPodWithVolume
(
c
clientset
.
Interface
,
ns
,
claimName
,
podName
,
command
string
,
node
NodeSelection
)
{
pod
:=
StartInPodWithVolume
(
c
,
ns
,
claimName
,
podName
,
command
,
node
)
defer
StopPod
(
c
,
pod
)
framework
.
ExpectNoError
(
framework
.
WaitForPodSuccessInNamespaceSlow
(
c
,
pod
.
Name
,
pod
.
Namespace
))
}
// StartInPodWithVolume starts a command in a pod with given claim mounted to /mnt directory
// The caller is responsible for checking the pod and deleting it.
func
StartInPodWithVolume
(
c
clientset
.
Interface
,
ns
,
claimName
,
podName
,
command
string
,
node
NodeSelection
)
*
v1
.
Pod
{
pod
:=
&
v1
.
Pod
{
TypeMeta
:
metav1
.
TypeMeta
{
Kind
:
"Pod"
,
APIVersion
:
"v1"
,
},
ObjectMeta
:
metav1
.
ObjectMeta
{
GenerateName
:
"pvc-volume-tester-"
,
GenerateName
:
podName
+
"-"
,
Labels
:
map
[
string
]
string
{
"app"
:
podName
,
},
},
Spec
:
v1
.
PodSpec
{
NodeName
:
node
.
Name
,
NodeSelector
:
node
.
Selector
,
Affinity
:
node
.
Affinity
,
Containers
:
[]
v1
.
Container
{
{
Name
:
"volume-tester"
,
...
...
@@ -466,30 +640,26 @@ func runInPodWithVolume(c clientset.Interface, ns, claimName, nodeName, command
},
},
},
NodeSelector
:
nodeSelector
,
},
}
if
len
(
nodeName
)
!=
0
{
pod
.
Spec
.
NodeName
=
nodeName
}
pod
,
err
:=
c
.
CoreV1
()
.
Pods
(
ns
)
.
Create
(
pod
)
framework
.
ExpectNoError
(
err
,
"Failed to create pod: %v"
,
err
)
defer
func
()
{
body
,
err
:=
c
.
CoreV1
()
.
Pods
(
ns
)
.
GetLogs
(
pod
.
Name
,
&
v1
.
PodLogOptions
{})
.
Do
()
.
Raw
()
if
err
!=
nil
{
framework
.
Logf
(
"Error getting logs for pod %s: %v"
,
pod
.
Name
,
err
)
}
else
{
framework
.
Logf
(
"Pod %s has the following logs: %s"
,
pod
.
Name
,
body
)
}
framework
.
DeletePodOrFail
(
c
,
ns
,
pod
.
Name
)
}()
return
pod
}
if
unschedulable
{
framework
.
ExpectNoError
(
framework
.
WaitForPodNameUnschedulableInNamespace
(
c
,
pod
.
Name
,
pod
.
Namespace
))
// StopPod first tries to log the output of the pod's container, then deletes the pod.
func
StopPod
(
c
clientset
.
Interface
,
pod
*
v1
.
Pod
)
{
if
pod
==
nil
{
return
}
body
,
err
:=
c
.
CoreV1
()
.
Pods
(
pod
.
Namespace
)
.
GetLogs
(
pod
.
Name
,
&
v1
.
PodLogOptions
{})
.
Do
()
.
Raw
()
if
err
!=
nil
{
framework
.
Logf
(
"Error getting logs for pod %s: %v"
,
pod
.
Name
,
err
)
}
else
{
framework
.
ExpectNoError
(
framework
.
WaitForPodSuccessInNamespaceSlow
(
c
,
pod
.
Name
,
pod
.
Namespace
)
)
framework
.
Logf
(
"Pod %s has the following logs: %s"
,
pod
.
Name
,
body
)
}
framework
.
DeletePodOrFail
(
c
,
pod
.
Namespace
,
pod
.
Name
)
}
func
verifyPVCsPending
(
client
clientset
.
Interface
,
pvcs
[]
*
v1
.
PersistentVolumeClaim
)
{
...
...
@@ -502,7 +672,7 @@ func verifyPVCsPending(client clientset.Interface, pvcs []*v1.PersistentVolumeCl
}
func
prepareDataSourceForProvisioning
(
t
StorageClassTest
,
node
NodeSelection
,
client
clientset
.
Interface
,
dynamicClient
dynamic
.
Interface
,
initClaim
*
v1
.
PersistentVolumeClaim
,
...
...
@@ -530,7 +700,7 @@ func prepareDataSourceForProvisioning(
// write namespace to the /mnt/test (= the volume).
By
(
"[Initialize dataSource]write data to volume"
)
command
:=
fmt
.
Sprintf
(
"echo '%s' > /mnt/test/initialData"
,
updatedClaim
.
GetNamespace
())
runInPodWithVolume
(
client
,
updatedClaim
.
Namespace
,
updatedClaim
.
Name
,
t
.
NodeName
,
command
,
t
.
NodeSelector
,
t
.
ExpectUnschedulabl
e
)
RunInPodWithVolume
(
client
,
updatedClaim
.
Namespace
,
updatedClaim
.
Name
,
"pvc-snapshot-writer"
,
command
,
nod
e
)
By
(
"[Initialize dataSource]creating a SnapshotClass"
)
snapshotClass
,
err
=
dynamicClient
.
Resource
(
snapshotClassGVR
)
.
Create
(
snapshotClass
,
metav1
.
CreateOptions
{})
...
...
test/e2e/storage/testsuites/snapshottable.go
View file @
f9684998
...
...
@@ -80,6 +80,10 @@ func (s *snapshottableTestSuite) getTestSuiteInfo() TestSuiteInfo {
}
func
(
s
*
snapshottableTestSuite
)
skipUnsupportedTest
(
pattern
testpatterns
.
TestPattern
,
driver
TestDriver
)
{
dInfo
:=
driver
.
GetDriverInfo
()
if
!
dInfo
.
Capabilities
[
CapDataSource
]
{
framework
.
Skipf
(
"Driver %q does not support snapshots - skipping"
,
dInfo
.
Name
)
}
}
func
createSnapshottableTestInput
(
driver
TestDriver
,
pattern
testpatterns
.
TestPattern
)
(
snapshottableTestResource
,
snapshottableTestInput
)
{
...
...
@@ -87,18 +91,17 @@ func createSnapshottableTestInput(driver TestDriver, pattern testpatterns.TestPa
resource
:=
snapshottableTestResource
{}
resource
.
setupResource
(
driver
,
pattern
)
dInfo
:=
driver
.
GetDriverInfo
()
input
:=
snapshottableTestInput
{
testCase
:
SnapshotClassTest
{},
cs
:
driver
.
GetDriverInfo
()
.
Config
.
Framework
.
ClientSet
,
dc
:
driver
.
GetDriverInfo
()
.
Config
.
Framework
.
DynamicClient
,
pvc
:
resource
.
pvc
,
sc
:
resource
.
sc
,
vsc
:
resource
.
vsc
,
dInfo
:
driver
.
GetDriverInfo
(),
}
if
driver
.
GetDriverInfo
()
.
Config
.
ClientNodeName
!=
""
{
input
.
testCase
.
NodeName
=
driver
.
GetDriverInfo
()
.
Config
.
ClientNodeName
testCase
:
SnapshotClassTest
{
NodeName
:
dInfo
.
Config
.
ClientNodeName
,
},
cs
:
dInfo
.
Config
.
Framework
.
ClientSet
,
dc
:
dInfo
.
Config
.
Framework
.
DynamicClient
,
pvc
:
resource
.
pvc
,
sc
:
resource
.
sc
,
vsc
:
resource
.
vsc
,
dInfo
:
dInfo
,
}
return
resource
,
input
...
...
@@ -187,10 +190,7 @@ type snapshottableTestInput struct {
}
func
testSnapshot
(
input
*
snapshottableTestInput
)
{
It
(
"should create snapshot with defaults"
,
func
()
{
if
input
.
dInfo
.
Name
==
"csi-hostpath-v0"
{
framework
.
Skipf
(
"skip test when using driver csi-hostpath-v0 - skipping"
)
}
It
(
"should create snapshot with defaults [Feature:VolumeSnapshotDataSource]"
,
func
()
{
TestCreateSnapshot
(
input
.
testCase
,
input
.
cs
,
input
.
dc
,
input
.
pvc
,
input
.
sc
,
input
.
vsc
)
})
}
...
...
test/e2e/storage/testsuites/testdriver.go
View file @
f9684998
...
...
@@ -97,6 +97,13 @@ const (
CapFsGroup
Capability
=
"fsGroup"
// volume ownership via fsGroup
CapExec
Capability
=
"exec"
// exec a file in the volume
CapDataSource
Capability
=
"dataSource"
// support populate data from snapshot
// multiple pods on a node can use the same volume concurrently;
// for CSI, see:
// - https://github.com/container-storage-interface/spec/pull/150
// - https://github.com/container-storage-interface/spec/issues/178
// - NodeStageVolume in the spec
CapMultiPODs
Capability
=
"multipods"
)
// DriverInfo represents a combination of parameters to be used in implementation of TestDriver
...
...
test/e2e/storage/volume_provisioning.go
View file @
f9684998
...
...
@@ -226,7 +226,7 @@ func testZonalDelayedBinding(c clientset.Interface, ns string, specifyAllowedTop
claim
.
Spec
.
StorageClassName
=
&
class
.
Name
claims
=
append
(
claims
,
claim
)
}
pvs
,
node
:=
testsuites
.
TestBindingWaitForFirstConsumerMultiPVC
(
test
,
c
,
claims
,
class
)
pvs
,
node
:=
testsuites
.
TestBindingWaitForFirstConsumerMultiPVC
(
test
,
c
,
claims
,
class
,
nil
/* node selector */
,
false
/* expect unschedulable */
)
if
node
==
nil
{
framework
.
Failf
(
"unexpected nil node found"
)
}
...
...
@@ -273,8 +273,10 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() {
},
ClaimSize
:
"1.5Gi"
,
ExpectedSize
:
"2Gi"
,
PvCheck
:
func
(
volume
*
v1
.
PersistentVolume
)
error
{
return
checkGCEPD
(
volume
,
"pd-ssd"
)
PvCheck
:
func
(
claim
*
v1
.
PersistentVolumeClaim
,
volume
*
v1
.
PersistentVolume
)
{
err
:=
checkGCEPD
(
volume
,
"pd-ssd"
)
Expect
(
err
)
.
NotTo
(
HaveOccurred
(),
"checkGCEPD pd-ssd"
)
testsuites
.
PVWriteReadSingleNodeCheck
(
c
,
claim
,
volume
,
testsuites
.
NodeSelection
{})
},
},
{
...
...
@@ -286,8 +288,10 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() {
},
ClaimSize
:
"1.5Gi"
,
ExpectedSize
:
"2Gi"
,
PvCheck
:
func
(
volume
*
v1
.
PersistentVolume
)
error
{
return
checkGCEPD
(
volume
,
"pd-standard"
)
PvCheck
:
func
(
claim
*
v1
.
PersistentVolumeClaim
,
volume
*
v1
.
PersistentVolume
)
{
err
:=
checkGCEPD
(
volume
,
"pd-standard"
)
Expect
(
err
)
.
NotTo
(
HaveOccurred
(),
"checkGCEPD pd-standard"
)
testsuites
.
PVWriteReadSingleNodeCheck
(
c
,
claim
,
volume
,
testsuites
.
NodeSelection
{})
},
},
// AWS
...
...
@@ -301,8 +305,10 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() {
},
ClaimSize
:
"1.5Gi"
,
ExpectedSize
:
"2Gi"
,
PvCheck
:
func
(
volume
*
v1
.
PersistentVolume
)
error
{
return
checkAWSEBS
(
volume
,
"gp2"
,
false
)
PvCheck
:
func
(
claim
*
v1
.
PersistentVolumeClaim
,
volume
*
v1
.
PersistentVolume
)
{
err
:=
checkAWSEBS
(
volume
,
"gp2"
,
false
)
Expect
(
err
)
.
NotTo
(
HaveOccurred
(),
"checkAWSEBS gp2"
)
testsuites
.
PVWriteReadSingleNodeCheck
(
c
,
claim
,
volume
,
testsuites
.
NodeSelection
{})
},
},
{
...
...
@@ -315,8 +321,10 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() {
},
ClaimSize
:
"3.5Gi"
,
ExpectedSize
:
"4Gi"
,
// 4 GiB is minimum for io1
PvCheck
:
func
(
volume
*
v1
.
PersistentVolume
)
error
{
return
checkAWSEBS
(
volume
,
"io1"
,
false
)
PvCheck
:
func
(
claim
*
v1
.
PersistentVolumeClaim
,
volume
*
v1
.
PersistentVolume
)
{
err
:=
checkAWSEBS
(
volume
,
"io1"
,
false
)
Expect
(
err
)
.
NotTo
(
HaveOccurred
(),
"checkAWSEBS io1"
)
testsuites
.
PVWriteReadSingleNodeCheck
(
c
,
claim
,
volume
,
testsuites
.
NodeSelection
{})
},
},
{
...
...
@@ -328,8 +336,10 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() {
},
ClaimSize
:
"500Gi"
,
// minimum for sc1
ExpectedSize
:
"500Gi"
,
PvCheck
:
func
(
volume
*
v1
.
PersistentVolume
)
error
{
return
checkAWSEBS
(
volume
,
"sc1"
,
false
)
PvCheck
:
func
(
claim
*
v1
.
PersistentVolumeClaim
,
volume
*
v1
.
PersistentVolume
)
{
err
:=
checkAWSEBS
(
volume
,
"sc1"
,
false
)
Expect
(
err
)
.
NotTo
(
HaveOccurred
(),
"checkAWSEBS sc1"
)
testsuites
.
PVWriteReadSingleNodeCheck
(
c
,
claim
,
volume
,
testsuites
.
NodeSelection
{})
},
},
{
...
...
@@ -341,8 +351,10 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() {
},
ClaimSize
:
"500Gi"
,
// minimum for st1
ExpectedSize
:
"500Gi"
,
PvCheck
:
func
(
volume
*
v1
.
PersistentVolume
)
error
{
return
checkAWSEBS
(
volume
,
"st1"
,
false
)
PvCheck
:
func
(
claim
*
v1
.
PersistentVolumeClaim
,
volume
*
v1
.
PersistentVolume
)
{
err
:=
checkAWSEBS
(
volume
,
"st1"
,
false
)
Expect
(
err
)
.
NotTo
(
HaveOccurred
(),
"checkAWSEBS st1"
)
testsuites
.
PVWriteReadSingleNodeCheck
(
c
,
claim
,
volume
,
testsuites
.
NodeSelection
{})
},
},
{
...
...
@@ -354,8 +366,10 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() {
},
ClaimSize
:
"1Gi"
,
ExpectedSize
:
"1Gi"
,
PvCheck
:
func
(
volume
*
v1
.
PersistentVolume
)
error
{
return
checkAWSEBS
(
volume
,
"gp2"
,
true
)
PvCheck
:
func
(
claim
*
v1
.
PersistentVolumeClaim
,
volume
*
v1
.
PersistentVolume
)
{
err
:=
checkAWSEBS
(
volume
,
"gp2"
,
true
)
Expect
(
err
)
.
NotTo
(
HaveOccurred
(),
"checkAWSEBS gp2 encrypted"
)
testsuites
.
PVWriteReadSingleNodeCheck
(
c
,
claim
,
volume
,
testsuites
.
NodeSelection
{})
},
},
// OpenStack generic tests (works on all OpenStack deployments)
...
...
@@ -366,7 +380,9 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() {
Parameters
:
map
[
string
]
string
{},
ClaimSize
:
"1.5Gi"
,
ExpectedSize
:
"2Gi"
,
PvCheck
:
nil
,
// there is currently nothing to check on OpenStack
PvCheck
:
func
(
claim
*
v1
.
PersistentVolumeClaim
,
volume
*
v1
.
PersistentVolume
)
{
testsuites
.
PVWriteReadSingleNodeCheck
(
c
,
claim
,
volume
,
testsuites
.
NodeSelection
{})
},
},
{
Name
:
"Cinder volume with empty volume type and zone on OpenStack"
,
...
...
@@ -378,7 +394,9 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() {
},
ClaimSize
:
"1.5Gi"
,
ExpectedSize
:
"2Gi"
,
PvCheck
:
nil
,
// there is currently nothing to check on OpenStack
PvCheck
:
func
(
claim
*
v1
.
PersistentVolumeClaim
,
volume
*
v1
.
PersistentVolume
)
{
testsuites
.
PVWriteReadSingleNodeCheck
(
c
,
claim
,
volume
,
testsuites
.
NodeSelection
{})
},
},
// vSphere generic test
{
...
...
@@ -388,7 +406,9 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() {
Parameters
:
map
[
string
]
string
{},
ClaimSize
:
"1.5Gi"
,
ExpectedSize
:
"1.5Gi"
,
PvCheck
:
nil
,
PvCheck
:
func
(
claim
*
v1
.
PersistentVolumeClaim
,
volume
*
v1
.
PersistentVolume
)
{
testsuites
.
PVWriteReadSingleNodeCheck
(
c
,
claim
,
volume
,
testsuites
.
NodeSelection
{})
},
},
// Azure
{
...
...
@@ -398,7 +418,9 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() {
Parameters
:
map
[
string
]
string
{},
ClaimSize
:
"1Gi"
,
ExpectedSize
:
"1Gi"
,
PvCheck
:
nil
,
PvCheck
:
func
(
claim
*
v1
.
PersistentVolumeClaim
,
volume
*
v1
.
PersistentVolume
)
{
testsuites
.
PVWriteReadSingleNodeCheck
(
c
,
claim
,
volume
,
testsuites
.
NodeSelection
{})
},
},
}
...
...
@@ -451,8 +473,10 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() {
},
ClaimSize
:
"1Gi"
,
ExpectedSize
:
"1Gi"
,
PvCheck
:
func
(
volume
*
v1
.
PersistentVolume
)
error
{
return
checkGCEPD
(
volume
,
"pd-standard"
)
PvCheck
:
func
(
claim
*
v1
.
PersistentVolumeClaim
,
volume
*
v1
.
PersistentVolume
)
{
err
:=
checkGCEPD
(
volume
,
"pd-standard"
)
Expect
(
err
)
.
NotTo
(
HaveOccurred
(),
"checkGCEPD"
)
testsuites
.
PVWriteReadSingleNodeCheck
(
c
,
claim
,
volume
,
testsuites
.
NodeSelection
{})
},
}
class
:=
newStorageClass
(
test
,
ns
,
"reclaimpolicy"
)
...
...
@@ -793,12 +817,11 @@ var _ = utils.SIGDescribe("Dynamic Provisioning", func() {
serverUrl
:=
"https://"
+
pod
.
Status
.
PodIP
+
":8081"
By
(
"creating a StorageClass"
)
test
:=
testsuites
.
StorageClassTest
{
Name
:
"Gluster Dynamic provisioner test"
,
Provisioner
:
"kubernetes.io/glusterfs"
,
ClaimSize
:
"2Gi"
,
ExpectedSize
:
"2Gi"
,
Parameters
:
map
[
string
]
string
{
"resturl"
:
serverUrl
},
SkipWriteReadCheck
:
true
,
Name
:
"Gluster Dynamic provisioner test"
,
Provisioner
:
"kubernetes.io/glusterfs"
,
ClaimSize
:
"2Gi"
,
ExpectedSize
:
"2Gi"
,
Parameters
:
map
[
string
]
string
{
"resturl"
:
serverUrl
},
}
suffix
:=
fmt
.
Sprintf
(
"glusterdptest"
)
class
:=
newStorageClass
(
test
,
ns
,
suffix
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment