mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-19 00:31:00 +00:00
Merge pull request #78000 from mkimuram/issue/77999
Move volume_expand tests to storage e2e testsuites
This commit is contained in:
commit
b1bea169f5
@ -23,7 +23,6 @@ go_library(
|
||||
"pvc_protection.go",
|
||||
"regional_pd.go",
|
||||
"subpath.go",
|
||||
"volume_expand.go",
|
||||
"volume_limits.go",
|
||||
"volume_metrics.go",
|
||||
"volume_provisioning.go",
|
||||
|
@ -439,7 +439,7 @@ var _ = utils.SIGDescribe("CSI mock volume", func() {
|
||||
|
||||
ginkgo.By("Expanding current pvc")
|
||||
newSize := resource.MustParse("6Gi")
|
||||
pvc, err = expandPVCSize(pvc, newSize, m.cs)
|
||||
pvc, err = testsuites.ExpandPVCSize(pvc, newSize, m.cs)
|
||||
framework.ExpectNoError(err, "While updating pvc for more size")
|
||||
gomega.Expect(pvc).NotTo(gomega.BeNil())
|
||||
|
||||
@ -448,18 +448,18 @@ var _ = utils.SIGDescribe("CSI mock volume", func() {
|
||||
e2elog.Failf("error updating pvc size %q", pvc.Name)
|
||||
}
|
||||
if test.expectFailure {
|
||||
err = waitForResizingCondition(pvc, m.cs, csiResizingConditionWait)
|
||||
err = testsuites.WaitForResizingCondition(pvc, m.cs, csiResizingConditionWait)
|
||||
framework.ExpectError(err, "unexpected resizing condition on PVC")
|
||||
return
|
||||
}
|
||||
|
||||
ginkgo.By("Waiting for persistent volume resize to finish")
|
||||
err = waitForControllerVolumeResize(pvc, m.cs, csiResizeWaitPeriod)
|
||||
err = testsuites.WaitForControllerVolumeResize(pvc, m.cs, csiResizeWaitPeriod)
|
||||
framework.ExpectNoError(err, "While waiting for CSI PV resize to finish")
|
||||
|
||||
checkPVCSize := func() {
|
||||
ginkgo.By("Waiting for PVC resize to finish")
|
||||
pvc, err = waitForFSResize(pvc, m.cs)
|
||||
pvc, err = testsuites.WaitForFSResize(pvc, m.cs)
|
||||
framework.ExpectNoError(err, "while waiting for PVC resize to finish")
|
||||
|
||||
pvcConditions := pvc.Status.Conditions
|
||||
@ -530,7 +530,7 @@ var _ = utils.SIGDescribe("CSI mock volume", func() {
|
||||
|
||||
ginkgo.By("Expanding current pvc")
|
||||
newSize := resource.MustParse("6Gi")
|
||||
pvc, err = expandPVCSize(pvc, newSize, m.cs)
|
||||
pvc, err = testsuites.ExpandPVCSize(pvc, newSize, m.cs)
|
||||
framework.ExpectNoError(err, "While updating pvc for more size")
|
||||
gomega.Expect(pvc).NotTo(gomega.BeNil())
|
||||
|
||||
@ -540,11 +540,11 @@ var _ = utils.SIGDescribe("CSI mock volume", func() {
|
||||
}
|
||||
|
||||
ginkgo.By("Waiting for persistent volume resize to finish")
|
||||
err = waitForControllerVolumeResize(pvc, m.cs, csiResizeWaitPeriod)
|
||||
err = testsuites.WaitForControllerVolumeResize(pvc, m.cs, csiResizeWaitPeriod)
|
||||
framework.ExpectNoError(err, "While waiting for PV resize to finish")
|
||||
|
||||
ginkgo.By("Waiting for PVC resize to finish")
|
||||
pvc, err = waitForFSResize(pvc, m.cs)
|
||||
pvc, err = testsuites.WaitForFSResize(pvc, m.cs)
|
||||
framework.ExpectNoError(err, "while waiting for PVC to finish")
|
||||
|
||||
pvcConditions := pvc.Status.Conditions
|
||||
|
@ -1152,11 +1152,13 @@ func InitGcePdDriver() testsuites.TestDriver {
|
||||
SupportedFsType: supportedTypes,
|
||||
SupportedMountOption: sets.NewString("debug", "nouid32"),
|
||||
Capabilities: map[testsuites.Capability]bool{
|
||||
testsuites.CapPersistence: true,
|
||||
testsuites.CapFsGroup: true,
|
||||
testsuites.CapBlock: true,
|
||||
testsuites.CapExec: true,
|
||||
testsuites.CapMultiPODs: true,
|
||||
testsuites.CapPersistence: true,
|
||||
testsuites.CapFsGroup: true,
|
||||
testsuites.CapBlock: true,
|
||||
testsuites.CapExec: true,
|
||||
testsuites.CapMultiPODs: true,
|
||||
testsuites.CapControllerExpansion: true,
|
||||
testsuites.CapNodeExpansion: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -1527,11 +1529,13 @@ func InitAwsDriver() testsuites.TestDriver {
|
||||
),
|
||||
SupportedMountOption: sets.NewString("debug", "nouid32"),
|
||||
Capabilities: map[testsuites.Capability]bool{
|
||||
testsuites.CapPersistence: true,
|
||||
testsuites.CapFsGroup: true,
|
||||
testsuites.CapBlock: true,
|
||||
testsuites.CapExec: true,
|
||||
testsuites.CapMultiPODs: true,
|
||||
testsuites.CapPersistence: true,
|
||||
testsuites.CapFsGroup: true,
|
||||
testsuites.CapBlock: true,
|
||||
testsuites.CapExec: true,
|
||||
testsuites.CapMultiPODs: true,
|
||||
testsuites.CapControllerExpansion: true,
|
||||
testsuites.CapNodeExpansion: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
1
test/e2e/storage/external/external.go
vendored
1
test/e2e/storage/external/external.go
vendored
@ -47,6 +47,7 @@ var csiTestSuites = []func() testsuites.TestSuite{
|
||||
testsuites.InitVolumeIOTestSuite,
|
||||
testsuites.InitVolumeModeTestSuite,
|
||||
testsuites.InitVolumesTestSuite,
|
||||
testsuites.InitVolumeExpandTestSuite,
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
@ -19,6 +19,7 @@ package storage
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/onsi/ginkgo"
|
||||
"github.com/onsi/gomega"
|
||||
@ -35,6 +36,11 @@ import (
|
||||
"k8s.io/kubernetes/test/e2e/storage/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
// total time to wait for cloudprovider or file system resize to finish
|
||||
totalResizeWaitPeriod = 5 * time.Minute
|
||||
)
|
||||
|
||||
var _ = utils.SIGDescribe("Mounted flexvolume expand[Slow]", func() {
|
||||
var (
|
||||
c clientset.Interface
|
||||
@ -83,7 +89,7 @@ var _ = utils.SIGDescribe("Mounted flexvolume expand[Slow]", func() {
|
||||
Provisioner: "flex-expand",
|
||||
}
|
||||
|
||||
resizableSc, err = createStorageClass(test, ns, "resizing", c)
|
||||
resizableSc, err = c.StorageV1().StorageClasses().Create(newStorageClass(test, ns, "resizing"))
|
||||
if err != nil {
|
||||
fmt.Printf("storage class creation error: %v\n", err)
|
||||
}
|
||||
@ -151,7 +157,7 @@ var _ = utils.SIGDescribe("Mounted flexvolume expand[Slow]", func() {
|
||||
|
||||
ginkgo.By("Expanding current pvc")
|
||||
newSize := resource.MustParse("6Gi")
|
||||
pvc, err = expandPVCSize(pvc, newSize, c)
|
||||
pvc, err = testsuites.ExpandPVCSize(pvc, newSize, c)
|
||||
framework.ExpectNoError(err, "While updating pvc for more size")
|
||||
gomega.Expect(pvc).NotTo(gomega.BeNil())
|
||||
|
||||
@ -161,7 +167,7 @@ var _ = utils.SIGDescribe("Mounted flexvolume expand[Slow]", func() {
|
||||
}
|
||||
|
||||
ginkgo.By("Waiting for cloudprovider resize to finish")
|
||||
err = waitForControllerVolumeResize(pvc, c, totalResizeWaitPeriod)
|
||||
err = testsuites.WaitForControllerVolumeResize(pvc, c, totalResizeWaitPeriod)
|
||||
framework.ExpectNoError(err, "While waiting for pvc resize to finish")
|
||||
|
||||
ginkgo.By("Getting a pod from deployment")
|
||||
@ -178,7 +184,7 @@ var _ = utils.SIGDescribe("Mounted flexvolume expand[Slow]", func() {
|
||||
framework.ExpectNoError(err, "While waiting for pod to be recreated")
|
||||
|
||||
ginkgo.By("Waiting for file system resize to finish")
|
||||
pvc, err = waitForFSResize(pvc, c)
|
||||
pvc, err = testsuites.WaitForFSResize(pvc, c)
|
||||
framework.ExpectNoError(err, "while waiting for fs resize to finish")
|
||||
|
||||
pvcConditions := pvc.Status.Conditions
|
||||
|
@ -81,7 +81,7 @@ var _ = utils.SIGDescribe("Mounted flexvolume volume expand [Slow] [Feature:Expa
|
||||
Provisioner: "flex-expand",
|
||||
}
|
||||
|
||||
resizableSc, err = createStorageClass(test, ns, "resizing", c)
|
||||
resizableSc, err = c.StorageV1().StorageClasses().Create(newStorageClass(test, ns, "resizing"))
|
||||
if err != nil {
|
||||
fmt.Printf("storage class creation error: %v\n", err)
|
||||
}
|
||||
@ -155,7 +155,7 @@ var _ = utils.SIGDescribe("Mounted flexvolume volume expand [Slow] [Feature:Expa
|
||||
|
||||
ginkgo.By("Expanding current pvc")
|
||||
newSize := resource.MustParse("6Gi")
|
||||
pvc, err = expandPVCSize(pvc, newSize, c)
|
||||
pvc, err = testsuites.ExpandPVCSize(pvc, newSize, c)
|
||||
framework.ExpectNoError(err, "While updating pvc for more size")
|
||||
gomega.Expect(pvc).NotTo(gomega.BeNil())
|
||||
|
||||
@ -165,11 +165,11 @@ var _ = utils.SIGDescribe("Mounted flexvolume volume expand [Slow] [Feature:Expa
|
||||
}
|
||||
|
||||
ginkgo.By("Waiting for cloudprovider resize to finish")
|
||||
err = waitForControllerVolumeResize(pvc, c, totalResizeWaitPeriod)
|
||||
err = testsuites.WaitForControllerVolumeResize(pvc, c, totalResizeWaitPeriod)
|
||||
framework.ExpectNoError(err, "While waiting for pvc resize to finish")
|
||||
|
||||
ginkgo.By("Waiting for file system resize to finish")
|
||||
pvc, err = waitForFSResize(pvc, c)
|
||||
pvc, err = testsuites.WaitForFSResize(pvc, c)
|
||||
framework.ExpectNoError(err, "while waiting for fs resize to finish")
|
||||
|
||||
pvcConditions := pvc.Status.Conditions
|
||||
|
@ -56,6 +56,7 @@ var testSuites = []func() testsuites.TestSuite{
|
||||
testsuites.InitSubPathTestSuite,
|
||||
testsuites.InitProvisioningTestSuite,
|
||||
testsuites.InitMultiVolumeTestSuite,
|
||||
testsuites.InitVolumeExpandTestSuite,
|
||||
}
|
||||
|
||||
// This executes testSuites for in-tree volumes.
|
||||
|
@ -81,7 +81,7 @@ var _ = utils.SIGDescribe("Mounted volume expand", func() {
|
||||
AllowVolumeExpansion: true,
|
||||
DelayBinding: true,
|
||||
}
|
||||
resizableSc, err = createStorageClass(test, ns, "resizing", c)
|
||||
resizableSc, err = c.StorageV1().StorageClasses().Create(newStorageClass(test, ns, "resizing"))
|
||||
framework.ExpectNoError(err, "Error creating resizable storage class")
|
||||
gomega.Expect(*resizableSc.AllowVolumeExpansion).To(gomega.BeTrue())
|
||||
|
||||
@ -128,7 +128,7 @@ var _ = utils.SIGDescribe("Mounted volume expand", func() {
|
||||
|
||||
ginkgo.By("Expanding current pvc")
|
||||
newSize := resource.MustParse("6Gi")
|
||||
pvc, err = expandPVCSize(pvc, newSize, c)
|
||||
pvc, err = testsuites.ExpandPVCSize(pvc, newSize, c)
|
||||
framework.ExpectNoError(err, "While updating pvc for more size")
|
||||
gomega.Expect(pvc).NotTo(gomega.BeNil())
|
||||
|
||||
@ -138,7 +138,7 @@ var _ = utils.SIGDescribe("Mounted volume expand", func() {
|
||||
}
|
||||
|
||||
ginkgo.By("Waiting for cloudprovider resize to finish")
|
||||
err = waitForControllerVolumeResize(pvc, c, totalResizeWaitPeriod)
|
||||
err = testsuites.WaitForControllerVolumeResize(pvc, c, totalResizeWaitPeriod)
|
||||
framework.ExpectNoError(err, "While waiting for pvc resize to finish")
|
||||
|
||||
ginkgo.By("Getting a pod from deployment")
|
||||
@ -155,7 +155,7 @@ var _ = utils.SIGDescribe("Mounted volume expand", func() {
|
||||
framework.ExpectNoError(err, "While waiting for pod to be recreated")
|
||||
|
||||
ginkgo.By("Waiting for file system resize to finish")
|
||||
pvc, err = waitForFSResize(pvc, c)
|
||||
pvc, err = testsuites.WaitForFSResize(pvc, c)
|
||||
framework.ExpectNoError(err, "while waiting for fs resize to finish")
|
||||
|
||||
pvcConditions := pvc.Status.Conditions
|
||||
|
@ -7,6 +7,7 @@ go_library(
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/storage/v1:go_default_library",
|
||||
"//test/e2e/framework/volume:go_default_library",
|
||||
],
|
||||
)
|
||||
|
@ -18,6 +18,7 @@ package testpatterns
|
||||
|
||||
import (
|
||||
"k8s.io/api/core/v1"
|
||||
storagev1 "k8s.io/api/storage/v1"
|
||||
"k8s.io/kubernetes/test/e2e/framework/volume"
|
||||
)
|
||||
|
||||
@ -55,12 +56,14 @@ var (
|
||||
|
||||
// TestPattern represents a combination of parameters to be tested in a TestSuite
|
||||
type TestPattern struct {
|
||||
Name string // Name of TestPattern
|
||||
FeatureTag string // featureTag for the TestSuite
|
||||
VolType TestVolType // Volume type of the volume
|
||||
FsType string // Fstype of the volume
|
||||
VolMode v1.PersistentVolumeMode // PersistentVolumeMode of the volume
|
||||
SnapshotType TestSnapshotType // Snapshot type of the snapshot
|
||||
Name string // Name of TestPattern
|
||||
FeatureTag string // featureTag for the TestSuite
|
||||
VolType TestVolType // Volume type of the volume
|
||||
FsType string // Fstype of the volume
|
||||
VolMode v1.PersistentVolumeMode // PersistentVolumeMode of the volume
|
||||
SnapshotType TestSnapshotType // Snapshot type of the snapshot
|
||||
BindingMode storagev1.VolumeBindingMode // VolumeBindingMode of the volume
|
||||
AllowExpansion bool // AllowVolumeExpansion flag of the StorageClass
|
||||
}
|
||||
|
||||
var (
|
||||
@ -195,7 +198,7 @@ var (
|
||||
VolType: PreprovisionedPV,
|
||||
VolMode: v1.PersistentVolumeBlock,
|
||||
}
|
||||
// BlockVolModeDynamicPV is TestPattern for "Dynamic PV (block)(immediate bind)"
|
||||
// BlockVolModeDynamicPV is TestPattern for "Dynamic PV (block)"
|
||||
BlockVolModeDynamicPV = TestPattern{
|
||||
Name: "Dynamic PV (block volmode)",
|
||||
VolType: DynamicPV,
|
||||
@ -209,4 +212,22 @@ var (
|
||||
Name: "Dynamic Snapshot",
|
||||
SnapshotType: DynamicCreatedSnapshot,
|
||||
}
|
||||
|
||||
// Definitions for volume expansion case
|
||||
|
||||
// DefaultFsDynamicPVAllowExpansion is TestPattern for "Dynamic PV (default fs)(allowExpansion)"
|
||||
DefaultFsDynamicPVAllowExpansion = TestPattern{
|
||||
Name: "Dynamic PV (default fs)(allowExpansion)",
|
||||
VolType: DynamicPV,
|
||||
BindingMode: storagev1.VolumeBindingWaitForFirstConsumer,
|
||||
AllowExpansion: true,
|
||||
}
|
||||
// BlockVolModeDynamicPVAllowExpansion is TestPattern for "Dynamic PV (block volmode)(allowExpansion)"
|
||||
BlockVolModeDynamicPVAllowExpansion = TestPattern{
|
||||
Name: "Dynamic PV (block volmode)(allowExpansion)",
|
||||
VolType: DynamicPV,
|
||||
VolMode: v1.PersistentVolumeBlock,
|
||||
BindingMode: storagev1.VolumeBindingWaitForFirstConsumer,
|
||||
AllowExpansion: true,
|
||||
}
|
||||
)
|
||||
|
@ -10,6 +10,7 @@ go_library(
|
||||
"snapshottable.go",
|
||||
"subpath.go",
|
||||
"testdriver.go",
|
||||
"volume_expand.go",
|
||||
"volume_io.go",
|
||||
"volumemode.go",
|
||||
"volumes.go",
|
||||
|
@ -186,23 +186,21 @@ func createGenericVolumeTestResource(driver TestDriver, config *PerTestConfig, p
|
||||
dInfo := driver.GetDriverInfo()
|
||||
f := config.Framework
|
||||
cs := f.ClientSet
|
||||
fsType := pattern.FsType
|
||||
volType := pattern.VolType
|
||||
|
||||
// Create volume for pre-provisioned volume tests
|
||||
r.volume = CreateVolume(driver, config, volType)
|
||||
r.volume = CreateVolume(driver, config, pattern.VolType)
|
||||
|
||||
switch volType {
|
||||
switch pattern.VolType {
|
||||
case testpatterns.InlineVolume:
|
||||
e2elog.Logf("Creating resource for inline volume")
|
||||
if iDriver, ok := driver.(InlineVolumeTestDriver); ok {
|
||||
r.volSource = iDriver.GetVolumeSource(false, fsType, r.volume)
|
||||
r.volSource = iDriver.GetVolumeSource(false, pattern.FsType, r.volume)
|
||||
r.volType = dInfo.Name
|
||||
}
|
||||
case testpatterns.PreprovisionedPV:
|
||||
e2elog.Logf("Creating resource for pre-provisioned PV")
|
||||
if pDriver, ok := driver.(PreprovisionedPVTestDriver); ok {
|
||||
pvSource, volumeNodeAffinity := pDriver.GetPersistentVolumeSource(false, fsType, r.volume)
|
||||
pvSource, volumeNodeAffinity := pDriver.GetPersistentVolumeSource(false, pattern.FsType, r.volume)
|
||||
if pvSource != nil {
|
||||
r.volSource, r.pv, r.pvc = createVolumeSourceWithPVCPV(f, dInfo.Name, pvSource, volumeNodeAffinity, false, pattern.VolMode)
|
||||
}
|
||||
@ -212,7 +210,14 @@ func createGenericVolumeTestResource(driver TestDriver, config *PerTestConfig, p
|
||||
e2elog.Logf("Creating resource for dynamic PV")
|
||||
if dDriver, ok := driver.(DynamicPVTestDriver); ok {
|
||||
claimSize := dDriver.GetClaimSize()
|
||||
r.sc = dDriver.GetDynamicProvisionStorageClass(r.config, fsType)
|
||||
r.sc = dDriver.GetDynamicProvisionStorageClass(r.config, pattern.FsType)
|
||||
|
||||
if pattern.BindingMode != "" {
|
||||
r.sc.VolumeBindingMode = &pattern.BindingMode
|
||||
}
|
||||
if pattern.AllowExpansion != false {
|
||||
r.sc.AllowVolumeExpansion = &pattern.AllowExpansion
|
||||
}
|
||||
|
||||
ginkgo.By("creating a StorageClass " + r.sc.Name)
|
||||
var err error
|
||||
@ -226,11 +231,11 @@ func createGenericVolumeTestResource(driver TestDriver, config *PerTestConfig, p
|
||||
r.volType = fmt.Sprintf("%s-dynamicPV", dInfo.Name)
|
||||
}
|
||||
default:
|
||||
e2elog.Failf("genericVolumeTestResource doesn't support: %s", volType)
|
||||
e2elog.Failf("genericVolumeTestResource doesn't support: %s", pattern.VolType)
|
||||
}
|
||||
|
||||
if r.volSource == nil {
|
||||
framework.Skipf("Driver %s doesn't support %v -- skipping", dInfo.Name, volType)
|
||||
framework.Skipf("Driver %s doesn't support %v -- skipping", dInfo.Name, pattern.VolType)
|
||||
}
|
||||
|
||||
return &r
|
||||
@ -239,10 +244,9 @@ func createGenericVolumeTestResource(driver TestDriver, config *PerTestConfig, p
|
||||
// cleanupResource cleans up genericVolumeTestResource
|
||||
func (r *genericVolumeTestResource) cleanupResource() {
|
||||
f := r.config.Framework
|
||||
volType := r.pattern.VolType
|
||||
|
||||
if r.pvc != nil || r.pv != nil {
|
||||
switch volType {
|
||||
switch r.pattern.VolType {
|
||||
case testpatterns.PreprovisionedPV:
|
||||
ginkgo.By("Deleting pv and pvc")
|
||||
if errs := framework.PVPVCCleanup(f.ClientSet, f.Namespace.Name, r.pv, r.pvc); len(errs) != 0 {
|
||||
|
@ -127,7 +127,9 @@ const (
|
||||
// - NodeStageVolume in the spec
|
||||
CapMultiPODs Capability = "multipods"
|
||||
|
||||
CapRWX Capability = "RWX" // support ReadWriteMany access modes
|
||||
CapRWX Capability = "RWX" // support ReadWriteMany access modes
|
||||
CapControllerExpansion Capability = "controllerExpansion" // support volume expansion for controller
|
||||
CapNodeExpansion Capability = "nodeExpansion" // support volume expansion for node
|
||||
)
|
||||
|
||||
// DriverInfo represents static information about a TestDriver.
|
||||
|
344
test/e2e/storage/testsuites/volume_expand.go
Normal file
344
test/e2e/storage/testsuites/volume_expand.go
Normal file
@ -0,0 +1,344 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package testsuites
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/onsi/ginkgo"
|
||||
"github.com/onsi/gomega"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
e2elog "k8s.io/kubernetes/test/e2e/framework/log"
|
||||
"k8s.io/kubernetes/test/e2e/storage/testpatterns"
|
||||
)
|
||||
|
||||
const (
|
||||
resizePollInterval = 2 * time.Second
|
||||
// total time to wait for cloudprovider or file system resize to finish
|
||||
totalResizeWaitPeriod = 10 * time.Minute
|
||||
)
|
||||
|
||||
type volumeExpandTestSuite struct {
|
||||
tsInfo TestSuiteInfo
|
||||
}
|
||||
|
||||
var _ TestSuite = &volumeExpandTestSuite{}
|
||||
|
||||
// InitVolumeExpandTestSuite returns volumeExpandTestSuite that implements TestSuite interface
|
||||
func InitVolumeExpandTestSuite() TestSuite {
|
||||
return &volumeExpandTestSuite{
|
||||
tsInfo: TestSuiteInfo{
|
||||
name: "volume-expand",
|
||||
testPatterns: []testpatterns.TestPattern{
|
||||
testpatterns.DefaultFsDynamicPV,
|
||||
testpatterns.BlockVolModeDynamicPV,
|
||||
testpatterns.DefaultFsDynamicPVAllowExpansion,
|
||||
testpatterns.BlockVolModeDynamicPVAllowExpansion,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (v *volumeExpandTestSuite) getTestSuiteInfo() TestSuiteInfo {
|
||||
return v.tsInfo
|
||||
}
|
||||
|
||||
func (v *volumeExpandTestSuite) defineTests(driver TestDriver, pattern testpatterns.TestPattern) {
|
||||
type local struct {
|
||||
config *PerTestConfig
|
||||
testCleanup func()
|
||||
|
||||
resource *genericVolumeTestResource
|
||||
pod *v1.Pod
|
||||
pod2 *v1.Pod
|
||||
|
||||
intreeOps opCounts
|
||||
migratedOps opCounts
|
||||
}
|
||||
var l local
|
||||
|
||||
ginkgo.BeforeEach(func() {
|
||||
// Check preconditions.
|
||||
if !driver.GetDriverInfo().Capabilities[CapBlock] && pattern.VolMode == v1.PersistentVolumeBlock {
|
||||
framework.Skipf("Driver %q does not support block volume mode - skipping", driver.GetDriverInfo().Name)
|
||||
}
|
||||
if !driver.GetDriverInfo().Capabilities[CapControllerExpansion] {
|
||||
framework.Skipf("Driver %q does not support volume expansion - skipping", driver.GetDriverInfo().Name)
|
||||
}
|
||||
})
|
||||
|
||||
// This intentionally comes after checking the preconditions because it
|
||||
// registers its own BeforeEach which creates the namespace. Beware that it
|
||||
// also registers an AfterEach which renders f unusable. Any code using
|
||||
// f must run inside an It or Context callback.
|
||||
f := framework.NewDefaultFramework("volume-expand")
|
||||
|
||||
init := func() {
|
||||
l = local{}
|
||||
|
||||
// Now do the more expensive test initialization.
|
||||
l.config, l.testCleanup = driver.PrepareTest(f)
|
||||
l.intreeOps, l.migratedOps = getMigrationVolumeOpCounts(f.ClientSet, driver.GetDriverInfo().InTreePluginName)
|
||||
l.resource = createGenericVolumeTestResource(driver, l.config, pattern)
|
||||
}
|
||||
|
||||
cleanup := func() {
|
||||
if l.pod != nil {
|
||||
ginkgo.By("Deleting pod")
|
||||
err := framework.DeletePodWithWait(f, f.ClientSet, l.pod)
|
||||
framework.ExpectNoError(err, "while deleting pod")
|
||||
l.pod = nil
|
||||
}
|
||||
|
||||
if l.pod2 != nil {
|
||||
ginkgo.By("Deleting pod2")
|
||||
err := framework.DeletePodWithWait(f, f.ClientSet, l.pod2)
|
||||
framework.ExpectNoError(err, "while deleting pod2")
|
||||
l.pod2 = nil
|
||||
}
|
||||
|
||||
if l.resource != nil {
|
||||
l.resource.cleanupResource()
|
||||
l.resource = nil
|
||||
}
|
||||
|
||||
if l.testCleanup != nil {
|
||||
l.testCleanup()
|
||||
l.testCleanup = nil
|
||||
}
|
||||
|
||||
validateMigrationVolumeOpCounts(f.ClientSet, driver.GetDriverInfo().InTreePluginName, l.intreeOps, l.migratedOps)
|
||||
}
|
||||
|
||||
if !pattern.AllowExpansion {
|
||||
ginkgo.It("should not allow expansion of pvcs without AllowVolumeExpansion property", func() {
|
||||
init()
|
||||
defer cleanup()
|
||||
|
||||
var err error
|
||||
gomega.Expect(l.resource.sc.AllowVolumeExpansion).To(gomega.BeNil())
|
||||
ginkgo.By("Expanding non-expandable pvc")
|
||||
currentPvcSize := l.resource.pvc.Spec.Resources.Requests[v1.ResourceStorage]
|
||||
newSize := currentPvcSize.DeepCopy()
|
||||
newSize.Add(resource.MustParse("1Gi"))
|
||||
e2elog.Logf("currentPvcSize %v, newSize %v", currentPvcSize, newSize)
|
||||
l.resource.pvc, err = ExpandPVCSize(l.resource.pvc, newSize, f.ClientSet)
|
||||
framework.ExpectError(err, "While updating non-expandable PVC")
|
||||
})
|
||||
} else {
|
||||
ginkgo.It("Verify if offline PVC expansion works", func() {
|
||||
init()
|
||||
defer cleanup()
|
||||
|
||||
var err error
|
||||
ginkgo.By("Creating a pod with dynamically provisioned volume")
|
||||
l.pod, err = framework.CreateSecPodWithNodeSelection(f.ClientSet, f.Namespace.Name, []*v1.PersistentVolumeClaim{l.resource.pvc}, false, "", false, false, framework.SELinuxLabel, nil, framework.NodeSelection{Name: l.config.ClientNodeName}, framework.PodStartTimeout)
|
||||
defer func() {
|
||||
err = framework.DeletePodWithWait(f, f.ClientSet, l.pod)
|
||||
framework.ExpectNoError(err, "while cleaning up pod already deleted in resize test")
|
||||
}()
|
||||
framework.ExpectNoError(err, "While creating pods for resizing")
|
||||
|
||||
ginkgo.By("Deleting the previously created pod")
|
||||
err = framework.DeletePodWithWait(f, f.ClientSet, l.pod)
|
||||
framework.ExpectNoError(err, "while deleting pod for resizing")
|
||||
|
||||
// We expand the PVC while no pod is using it to ensure offline expansion
|
||||
ginkgo.By("Expanding current pvc")
|
||||
currentPvcSize := l.resource.pvc.Spec.Resources.Requests[v1.ResourceStorage]
|
||||
newSize := currentPvcSize.DeepCopy()
|
||||
newSize.Add(resource.MustParse("1Gi"))
|
||||
e2elog.Logf("currentPvcSize %v, newSize %v", currentPvcSize, newSize)
|
||||
l.resource.pvc, err = ExpandPVCSize(l.resource.pvc, newSize, f.ClientSet)
|
||||
framework.ExpectNoError(err, "While updating pvc for more size")
|
||||
gomega.Expect(l.resource.pvc).NotTo(gomega.BeNil())
|
||||
|
||||
pvcSize := l.resource.pvc.Spec.Resources.Requests[v1.ResourceStorage]
|
||||
if pvcSize.Cmp(newSize) != 0 {
|
||||
e2elog.Failf("error updating pvc size %q", l.resource.pvc.Name)
|
||||
}
|
||||
|
||||
ginkgo.By("Waiting for cloudprovider resize to finish")
|
||||
err = WaitForControllerVolumeResize(l.resource.pvc, f.ClientSet, totalResizeWaitPeriod)
|
||||
framework.ExpectNoError(err, "While waiting for pvc resize to finish")
|
||||
|
||||
ginkgo.By("Checking for conditions on pvc")
|
||||
l.resource.pvc, err = f.ClientSet.CoreV1().PersistentVolumeClaims(f.Namespace.Name).Get(l.resource.pvc.Name, metav1.GetOptions{})
|
||||
framework.ExpectNoError(err, "While fetching pvc after controller resize")
|
||||
|
||||
if pattern.VolMode == v1.PersistentVolumeBlock || !l.resource.driver.GetDriverInfo().Capabilities[CapNodeExpansion] {
|
||||
pvcConditions := l.resource.pvc.Status.Conditions
|
||||
framework.ExpectEqual(len(pvcConditions), 0, "pvc should not have conditions")
|
||||
} else {
|
||||
inProgressConditions := l.resource.pvc.Status.Conditions
|
||||
framework.ExpectEqual(len(inProgressConditions), 1, "pvc must have file system resize pending condition")
|
||||
framework.ExpectEqual(inProgressConditions[0].Type, v1.PersistentVolumeClaimFileSystemResizePending, "pvc must have fs resizing condition")
|
||||
}
|
||||
|
||||
ginkgo.By("Creating a new pod with same volume")
|
||||
l.pod2, err = framework.CreateSecPodWithNodeSelection(f.ClientSet, f.Namespace.Name, []*v1.PersistentVolumeClaim{l.resource.pvc}, false, "", false, false, framework.SELinuxLabel, nil, framework.NodeSelection{Name: l.config.ClientNodeName}, framework.PodStartTimeout)
|
||||
defer func() {
|
||||
err = framework.DeletePodWithWait(f, f.ClientSet, l.pod2)
|
||||
framework.ExpectNoError(err, "while cleaning up pod before exiting resizing test")
|
||||
}()
|
||||
framework.ExpectNoError(err, "while recreating pod for resizing")
|
||||
|
||||
ginkgo.By("Waiting for file system resize to finish")
|
||||
l.resource.pvc, err = WaitForFSResize(l.resource.pvc, f.ClientSet)
|
||||
framework.ExpectNoError(err, "while waiting for fs resize to finish")
|
||||
|
||||
pvcConditions := l.resource.pvc.Status.Conditions
|
||||
framework.ExpectEqual(len(pvcConditions), 0, "pvc should not have conditions")
|
||||
})
|
||||
|
||||
ginkgo.It("should resize volume when PVC is edited while pod is using it", func() {
|
||||
init()
|
||||
defer cleanup()
|
||||
|
||||
var err error
|
||||
ginkgo.By("Creating a pod with dynamically provisioned volume")
|
||||
l.pod, err = framework.CreateSecPodWithNodeSelection(f.ClientSet, f.Namespace.Name, []*v1.PersistentVolumeClaim{l.resource.pvc}, false, "", false, false, framework.SELinuxLabel, nil, framework.NodeSelection{Name: l.config.ClientNodeName}, framework.PodStartTimeout)
|
||||
defer func() {
|
||||
err = framework.DeletePodWithWait(f, f.ClientSet, l.pod)
|
||||
framework.ExpectNoError(err, "while cleaning up pod already deleted in resize test")
|
||||
}()
|
||||
framework.ExpectNoError(err, "While creating pods for resizing")
|
||||
|
||||
// We expand the PVC while no pod is using it to ensure offline expansion
|
||||
ginkgo.By("Expanding current pvc")
|
||||
currentPvcSize := l.resource.pvc.Spec.Resources.Requests[v1.ResourceStorage]
|
||||
newSize := currentPvcSize.DeepCopy()
|
||||
newSize.Add(resource.MustParse("1Gi"))
|
||||
e2elog.Logf("currentPvcSize %v, newSize %v", currentPvcSize, newSize)
|
||||
l.resource.pvc, err = ExpandPVCSize(l.resource.pvc, newSize, f.ClientSet)
|
||||
framework.ExpectNoError(err, "While updating pvc for more size")
|
||||
gomega.Expect(l.resource.pvc).NotTo(gomega.BeNil())
|
||||
|
||||
pvcSize := l.resource.pvc.Spec.Resources.Requests[v1.ResourceStorage]
|
||||
if pvcSize.Cmp(newSize) != 0 {
|
||||
e2elog.Failf("error updating pvc size %q", l.resource.pvc.Name)
|
||||
}
|
||||
|
||||
ginkgo.By("Waiting for cloudprovider resize to finish")
|
||||
err = WaitForControllerVolumeResize(l.resource.pvc, f.ClientSet, totalResizeWaitPeriod)
|
||||
framework.ExpectNoError(err, "While waiting for pvc resize to finish")
|
||||
|
||||
ginkgo.By("Waiting for file system resize to finish")
|
||||
l.resource.pvc, err = WaitForFSResize(l.resource.pvc, f.ClientSet)
|
||||
framework.ExpectNoError(err, "while waiting for fs resize to finish")
|
||||
|
||||
pvcConditions := l.resource.pvc.Status.Conditions
|
||||
framework.ExpectEqual(len(pvcConditions), 0, "pvc should not have conditions")
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// ExpandPVCSize expands PVC size
|
||||
func ExpandPVCSize(origPVC *v1.PersistentVolumeClaim, size resource.Quantity, c clientset.Interface) (*v1.PersistentVolumeClaim, error) {
|
||||
pvcName := origPVC.Name
|
||||
updatedPVC := origPVC.DeepCopy()
|
||||
|
||||
waitErr := wait.PollImmediate(resizePollInterval, 30*time.Second, func() (bool, error) {
|
||||
var err error
|
||||
updatedPVC, err = c.CoreV1().PersistentVolumeClaims(origPVC.Namespace).Get(pvcName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error fetching pvc %q for resizing with %v", pvcName, err)
|
||||
}
|
||||
|
||||
updatedPVC.Spec.Resources.Requests[v1.ResourceStorage] = size
|
||||
updatedPVC, err = c.CoreV1().PersistentVolumeClaims(origPVC.Namespace).Update(updatedPVC)
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
e2elog.Logf("Error updating pvc %s with %v", pvcName, err)
|
||||
return false, nil
|
||||
})
|
||||
return updatedPVC, waitErr
|
||||
}
|
||||
|
||||
// WaitForResizingCondition waits for the pvc condition to be PersistentVolumeClaimResizing
|
||||
func WaitForResizingCondition(pvc *v1.PersistentVolumeClaim, c clientset.Interface, duration time.Duration) error {
|
||||
waitErr := wait.PollImmediate(resizePollInterval, duration, func() (bool, error) {
|
||||
var err error
|
||||
updatedPVC, err := c.CoreV1().PersistentVolumeClaims(pvc.Namespace).Get(pvc.Name, metav1.GetOptions{})
|
||||
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error fetching pvc %q for checking for resize status : %v", pvc.Name, err)
|
||||
}
|
||||
|
||||
pvcConditions := updatedPVC.Status.Conditions
|
||||
if len(pvcConditions) > 0 {
|
||||
if pvcConditions[0].Type == v1.PersistentVolumeClaimResizing {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
return waitErr
|
||||
}
|
||||
|
||||
// WaitForControllerVolumeResize waits for the controller resize to be finished
|
||||
func WaitForControllerVolumeResize(pvc *v1.PersistentVolumeClaim, c clientset.Interface, duration time.Duration) error {
|
||||
pvName := pvc.Spec.VolumeName
|
||||
return wait.PollImmediate(resizePollInterval, duration, func() (bool, error) {
|
||||
pvcSize := pvc.Spec.Resources.Requests[v1.ResourceStorage]
|
||||
|
||||
pv, err := c.CoreV1().PersistentVolumes().Get(pvName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error fetching pv %q for resizing %v", pvName, err)
|
||||
}
|
||||
|
||||
pvSize := pv.Spec.Capacity[v1.ResourceStorage]
|
||||
|
||||
// If pv size is greater or equal to requested size that means controller resize is finished.
|
||||
if pvSize.Cmp(pvcSize) >= 0 {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
}
|
||||
|
||||
// WaitForFSResize waits for the filesystem in the pv to be resized
|
||||
func WaitForFSResize(pvc *v1.PersistentVolumeClaim, c clientset.Interface) (*v1.PersistentVolumeClaim, error) {
|
||||
var updatedPVC *v1.PersistentVolumeClaim
|
||||
waitErr := wait.PollImmediate(resizePollInterval, totalResizeWaitPeriod, func() (bool, error) {
|
||||
var err error
|
||||
updatedPVC, err = c.CoreV1().PersistentVolumeClaims(pvc.Namespace).Get(pvc.Name, metav1.GetOptions{})
|
||||
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error fetching pvc %q for checking for resize status : %v", pvc.Name, err)
|
||||
}
|
||||
|
||||
pvcSize := updatedPVC.Spec.Resources.Requests[v1.ResourceStorage]
|
||||
pvcStatusSize := updatedPVC.Status.Capacity[v1.ResourceStorage]
|
||||
|
||||
//If pvc's status field size is greater than or equal to pvc's size then done
|
||||
if pvcStatusSize.Cmp(pvcSize) >= 0 {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
return updatedPVC, waitErr
|
||||
}
|
@ -1,334 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/onsi/ginkgo"
|
||||
"github.com/onsi/gomega"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
storagev1 "k8s.io/api/storage/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
e2elog "k8s.io/kubernetes/test/e2e/framework/log"
|
||||
"k8s.io/kubernetes/test/e2e/storage/testsuites"
|
||||
"k8s.io/kubernetes/test/e2e/storage/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
resizePollInterval = 2 * time.Second
|
||||
// total time to wait for cloudprovider or file system resize to finish
|
||||
totalResizeWaitPeriod = 20 * time.Minute
|
||||
)
|
||||
|
||||
var _ = utils.SIGDescribe("Volume expand", func() {
|
||||
var (
|
||||
c clientset.Interface
|
||||
ns string
|
||||
err error
|
||||
pvc *v1.PersistentVolumeClaim
|
||||
storageClassVar *storagev1.StorageClass
|
||||
)
|
||||
|
||||
f := framework.NewDefaultFramework("volume-expand")
|
||||
ginkgo.BeforeEach(func() {
|
||||
framework.SkipUnlessProviderIs("aws", "gce")
|
||||
c = f.ClientSet
|
||||
ns = f.Namespace.Name
|
||||
framework.ExpectNoError(framework.WaitForAllNodesSchedulable(c, framework.TestContext.NodeSchedulableTimeout))
|
||||
})
|
||||
|
||||
setupFunc := func(allowExpansion bool, blockVolume bool) (*v1.PersistentVolumeClaim, *storagev1.StorageClass, error) {
|
||||
test := testsuites.StorageClassTest{
|
||||
Name: "default",
|
||||
ClaimSize: "2Gi",
|
||||
}
|
||||
if allowExpansion {
|
||||
test.AllowVolumeExpansion = true
|
||||
}
|
||||
if blockVolume {
|
||||
test.VolumeMode = v1.PersistentVolumeBlock
|
||||
}
|
||||
|
||||
sc, err := createStorageClass(test, ns, "resizing", c)
|
||||
framework.ExpectNoError(err, "Error creating storage class for resizing")
|
||||
|
||||
tPVC := newClaim(test, ns, "default")
|
||||
tPVC.Spec.StorageClassName = &sc.Name
|
||||
tPVC, err = c.CoreV1().PersistentVolumeClaims(tPVC.Namespace).Create(tPVC)
|
||||
if err != nil {
|
||||
return nil, sc, err
|
||||
}
|
||||
return tPVC, sc, nil
|
||||
}
|
||||
|
||||
ginkgo.AfterEach(func() {
|
||||
framework.ExpectNoError(framework.DeletePersistentVolumeClaim(c, pvc.Name, pvc.Namespace))
|
||||
framework.ExpectNoError(c.StorageV1().StorageClasses().Delete(storageClassVar.Name, nil))
|
||||
})
|
||||
|
||||
ginkgo.It("should not allow expansion of pvcs without AllowVolumeExpansion property", func() {
|
||||
pvc, storageClassVar, err = setupFunc(false /* allowExpansion */, false /*BlockVolume*/)
|
||||
framework.ExpectNoError(err, "Error creating non-expandable PVC")
|
||||
|
||||
gomega.Expect(storageClassVar.AllowVolumeExpansion).To(gomega.BeNil())
|
||||
|
||||
pvcClaims := []*v1.PersistentVolumeClaim{pvc}
|
||||
pvs, err := framework.WaitForPVClaimBoundPhase(c, pvcClaims, framework.ClaimProvisionTimeout)
|
||||
framework.ExpectNoError(err, "Failed waiting for PVC to be bound %v", err)
|
||||
framework.ExpectEqual(len(pvs), 1)
|
||||
|
||||
ginkgo.By("Expanding non-expandable pvc")
|
||||
newSize := resource.MustParse("6Gi")
|
||||
pvc, err = expandPVCSize(pvc, newSize, c)
|
||||
framework.ExpectError(err, "While updating non-expandable PVC")
|
||||
})
|
||||
|
||||
ginkgo.It("Verify if offline PVC expansion works", func() {
|
||||
pvc, storageClassVar, err = setupFunc(true /* allowExpansion */, false /*BlockVolume*/)
|
||||
framework.ExpectNoError(err, "Error creating non-expandable PVC")
|
||||
|
||||
ginkgo.By("Waiting for pvc to be in bound phase")
|
||||
pvcClaims := []*v1.PersistentVolumeClaim{pvc}
|
||||
pvs, err := framework.WaitForPVClaimBoundPhase(c, pvcClaims, framework.ClaimProvisionTimeout)
|
||||
framework.ExpectNoError(err, "Failed waiting for PVC to be bound %v", err)
|
||||
framework.ExpectEqual(len(pvs), 1)
|
||||
|
||||
ginkgo.By("Creating a pod with dynamically provisioned volume")
|
||||
pod, err := framework.CreatePod(c, ns, nil, pvcClaims, false, "")
|
||||
framework.ExpectNoError(err, "While creating pods for resizing")
|
||||
defer func() {
|
||||
err = framework.DeletePodWithWait(f, c, pod)
|
||||
framework.ExpectNoError(err, "while cleaning up pod already deleted in resize test")
|
||||
}()
|
||||
|
||||
ginkgo.By("Deleting the previously created pod")
|
||||
err = framework.DeletePodWithWait(f, c, pod)
|
||||
framework.ExpectNoError(err, "while deleting pod for resizing")
|
||||
|
||||
// We expand the PVC while no pod is using it to ensure offline expansion
|
||||
ginkgo.By("Expanding current pvc")
|
||||
newSize := resource.MustParse("6Gi")
|
||||
pvc, err = expandPVCSize(pvc, newSize, c)
|
||||
framework.ExpectNoError(err, "While updating pvc for more size")
|
||||
gomega.Expect(pvc).NotTo(gomega.BeNil())
|
||||
|
||||
pvcSize := pvc.Spec.Resources.Requests[v1.ResourceStorage]
|
||||
if pvcSize.Cmp(newSize) != 0 {
|
||||
e2elog.Failf("error updating pvc size %q", pvc.Name)
|
||||
}
|
||||
|
||||
ginkgo.By("Waiting for cloudprovider resize to finish")
|
||||
err = waitForControllerVolumeResize(pvc, c, totalResizeWaitPeriod)
|
||||
framework.ExpectNoError(err, "While waiting for pvc resize to finish")
|
||||
|
||||
ginkgo.By("Checking for conditions on pvc")
|
||||
pvc, err = c.CoreV1().PersistentVolumeClaims(ns).Get(pvc.Name, metav1.GetOptions{})
|
||||
framework.ExpectNoError(err, "While fetching pvc after controller resize")
|
||||
|
||||
inProgressConditions := pvc.Status.Conditions
|
||||
framework.ExpectEqual(len(inProgressConditions), 1, "pvc must have file system resize pending condition")
|
||||
framework.ExpectEqual(inProgressConditions[0].Type, v1.PersistentVolumeClaimFileSystemResizePending, "pvc must have fs resizing condition")
|
||||
|
||||
ginkgo.By("Creating a new pod with same volume")
|
||||
pod2, err := framework.CreatePod(c, ns, nil, pvcClaims, false, "")
|
||||
framework.ExpectNoError(err, "while recreating pod for resizing")
|
||||
defer func() {
|
||||
err = framework.DeletePodWithWait(f, c, pod2)
|
||||
framework.ExpectNoError(err, "while cleaning up pod before exiting resizing test")
|
||||
}()
|
||||
|
||||
ginkgo.By("Waiting for file system resize to finish")
|
||||
pvc, err = waitForFSResize(pvc, c)
|
||||
framework.ExpectNoError(err, "while waiting for fs resize to finish")
|
||||
|
||||
pvcConditions := pvc.Status.Conditions
|
||||
framework.ExpectEqual(len(pvcConditions), 0, "pvc should not have conditions")
|
||||
})
|
||||
|
||||
ginkgo.It("should resize volume when PVC is edited while pod is using it", func() {
|
||||
pvc, storageClassVar, err = setupFunc(true /* allowExpansion */, false /*BlockVolume*/)
|
||||
framework.ExpectNoError(err, "Error creating non-expandable PVC")
|
||||
|
||||
ginkgo.By("Waiting for pvc to be in bound phase")
|
||||
pvcClaims := []*v1.PersistentVolumeClaim{pvc}
|
||||
pvs, err := framework.WaitForPVClaimBoundPhase(c, pvcClaims, framework.ClaimProvisionTimeout)
|
||||
framework.ExpectNoError(err, "Failed waiting for PVC to be bound %v", err)
|
||||
framework.ExpectEqual(len(pvs), 1)
|
||||
|
||||
ginkgo.By("Creating a pod with dynamically provisioned volume")
|
||||
pod, err := framework.CreatePod(c, ns, nil, pvcClaims, false, "")
|
||||
framework.ExpectNoError(err, "While creating pods for resizing")
|
||||
defer func() {
|
||||
err = framework.DeletePodWithWait(f, c, pod)
|
||||
framework.ExpectNoError(err, "while cleaning up pod already deleted in resize test")
|
||||
}()
|
||||
|
||||
// We expand the PVC while no pod is using it to ensure online expansion
|
||||
ginkgo.By("Expanding current pvc")
|
||||
newSize := resource.MustParse("6Gi")
|
||||
pvc, err = expandPVCSize(pvc, newSize, c)
|
||||
framework.ExpectNoError(err, "While updating pvc for more size")
|
||||
gomega.Expect(pvc).NotTo(gomega.BeNil())
|
||||
|
||||
pvcSize := pvc.Spec.Resources.Requests[v1.ResourceStorage]
|
||||
if pvcSize.Cmp(newSize) != 0 {
|
||||
e2elog.Failf("error updating pvc size %q", pvc.Name)
|
||||
}
|
||||
|
||||
ginkgo.By("Waiting for cloudprovider resize to finish")
|
||||
err = waitForControllerVolumeResize(pvc, c, totalResizeWaitPeriod)
|
||||
framework.ExpectNoError(err, "While waiting for pvc resize to finish")
|
||||
|
||||
ginkgo.By("Waiting for file system resize to finish")
|
||||
pvc, err = waitForFSResize(pvc, c)
|
||||
framework.ExpectNoError(err, "while waiting for fs resize to finish")
|
||||
|
||||
pvcConditions := pvc.Status.Conditions
|
||||
framework.ExpectEqual(len(pvcConditions), 0, "pvc should not have conditions")
|
||||
})
|
||||
|
||||
ginkgo.It("should allow expansion of block volumes", func() {
|
||||
pvc, storageClassVar, err = setupFunc(true /*allowExpansion*/, true /*blockVolume*/)
|
||||
|
||||
ginkgo.By("Waiting for pvc to be in bound phase")
|
||||
pvcClaims := []*v1.PersistentVolumeClaim{pvc}
|
||||
pvs, err := framework.WaitForPVClaimBoundPhase(c, pvcClaims, framework.ClaimProvisionTimeout)
|
||||
framework.ExpectNoError(err, "Failed waiting for PVC to be bound %v", err)
|
||||
framework.ExpectEqual(len(pvs), 1)
|
||||
|
||||
ginkgo.By("Expanding current pvc")
|
||||
newSize := resource.MustParse("6Gi")
|
||||
pvc, err = expandPVCSize(pvc, newSize, c)
|
||||
framework.ExpectNoError(err, "While updating pvc for more size")
|
||||
gomega.Expect(pvc).NotTo(gomega.BeNil())
|
||||
|
||||
pvcSize := pvc.Spec.Resources.Requests[v1.ResourceStorage]
|
||||
if pvcSize.Cmp(newSize) != 0 {
|
||||
e2elog.Failf("error updating pvc size %q", pvc.Name)
|
||||
}
|
||||
|
||||
ginkgo.By("Waiting for cloudprovider resize to finish")
|
||||
err = waitForControllerVolumeResize(pvc, c, totalResizeWaitPeriod)
|
||||
framework.ExpectNoError(err, "While waiting for pvc resize to finish")
|
||||
|
||||
ginkgo.By("Waiting for file system resize to finish")
|
||||
pvc, err = waitForFSResize(pvc, c)
|
||||
framework.ExpectNoError(err, "while waiting for fs resize to finish")
|
||||
|
||||
pvcConditions := pvc.Status.Conditions
|
||||
framework.ExpectEqual(len(pvcConditions), 0, "pvc should not have conditions")
|
||||
})
|
||||
})
|
||||
|
||||
func createStorageClass(t testsuites.StorageClassTest, ns string, suffix string, c clientset.Interface) (*storagev1.StorageClass, error) {
|
||||
stKlass := newStorageClass(t, ns, suffix)
|
||||
|
||||
var err error
|
||||
stKlass, err = c.StorageV1().StorageClasses().Create(stKlass)
|
||||
return stKlass, err
|
||||
}
|
||||
|
||||
func expandPVCSize(origPVC *v1.PersistentVolumeClaim, size resource.Quantity, c clientset.Interface) (*v1.PersistentVolumeClaim, error) {
|
||||
pvcName := origPVC.Name
|
||||
updatedPVC := origPVC.DeepCopy()
|
||||
|
||||
waitErr := wait.PollImmediate(resizePollInterval, 30*time.Second, func() (bool, error) {
|
||||
var err error
|
||||
updatedPVC, err = c.CoreV1().PersistentVolumeClaims(origPVC.Namespace).Get(pvcName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error fetching pvc %q for resizing with %v", pvcName, err)
|
||||
}
|
||||
|
||||
updatedPVC.Spec.Resources.Requests[v1.ResourceStorage] = size
|
||||
updatedPVC, err = c.CoreV1().PersistentVolumeClaims(origPVC.Namespace).Update(updatedPVC)
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
e2elog.Logf("Error updating pvc %s with %v", pvcName, err)
|
||||
return false, nil
|
||||
})
|
||||
return updatedPVC, waitErr
|
||||
}
|
||||
|
||||
func waitForResizingCondition(pvc *v1.PersistentVolumeClaim, c clientset.Interface, duration time.Duration) error {
|
||||
waitErr := wait.PollImmediate(resizePollInterval, duration, func() (bool, error) {
|
||||
var err error
|
||||
updatedPVC, err := c.CoreV1().PersistentVolumeClaims(pvc.Namespace).Get(pvc.Name, metav1.GetOptions{})
|
||||
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error fetching pvc %q for checking for resize status : %v", pvc.Name, err)
|
||||
}
|
||||
|
||||
pvcConditions := updatedPVC.Status.Conditions
|
||||
if len(pvcConditions) > 0 {
|
||||
if pvcConditions[0].Type == v1.PersistentVolumeClaimResizing {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
return waitErr
|
||||
}
|
||||
|
||||
func waitForControllerVolumeResize(pvc *v1.PersistentVolumeClaim, c clientset.Interface, duration time.Duration) error {
|
||||
pvName := pvc.Spec.VolumeName
|
||||
return wait.PollImmediate(resizePollInterval, duration, func() (bool, error) {
|
||||
pvcSize := pvc.Spec.Resources.Requests[v1.ResourceStorage]
|
||||
|
||||
pv, err := c.CoreV1().PersistentVolumes().Get(pvName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error fetching pv %q for resizing %v", pvName, err)
|
||||
}
|
||||
|
||||
pvSize := pv.Spec.Capacity[v1.ResourceStorage]
|
||||
|
||||
// If pv size is greater or equal to requested size that means controller resize is finished.
|
||||
if pvSize.Cmp(pvcSize) >= 0 {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
}
|
||||
|
||||
func waitForFSResize(pvc *v1.PersistentVolumeClaim, c clientset.Interface) (*v1.PersistentVolumeClaim, error) {
|
||||
var updatedPVC *v1.PersistentVolumeClaim
|
||||
waitErr := wait.PollImmediate(resizePollInterval, totalResizeWaitPeriod, func() (bool, error) {
|
||||
var err error
|
||||
updatedPVC, err = c.CoreV1().PersistentVolumeClaims(pvc.Namespace).Get(pvc.Name, metav1.GetOptions{})
|
||||
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error fetching pvc %q for checking for resize status : %v", pvc.Name, err)
|
||||
}
|
||||
|
||||
pvcSize := updatedPVC.Spec.Resources.Requests[v1.ResourceStorage]
|
||||
pvcStatusSize := updatedPVC.Status.Capacity[v1.ResourceStorage]
|
||||
|
||||
//If pvc's status field size is greater than or equal to pvc's size then done
|
||||
if pvcStatusSize.Cmp(pvcSize) >= 0 {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
return updatedPVC, waitErr
|
||||
}
|
Loading…
Reference in New Issue
Block a user