mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 19:31:44 +00:00
Add pre provisioned snapshot tests
Make pre provisioned snapshots using CSI driver by 1. Take a dynamic snapshot with retain policy 2. Delete the dynamic snapshot and content 3. Create a preprovisioned snapshot with snapshotHandle This commit adds a preprovisiond test pattern, all snapshots made using create snapshot resource become prepv snapshots. All exisitng test cases now run again with prepv snapshots.
This commit is contained in:
parent
ed85129831
commit
e78aee9965
4
test/e2e/storage/external/external.go
vendored
4
test/e2e/storage/external/external.go
vendored
@ -255,6 +255,10 @@ func (d *driverDefinition) SkipUnsupportedTest(pattern testpatterns.TestPattern)
|
|||||||
if d.SnapshotClass.FromName || d.SnapshotClass.FromFile != "" || d.SnapshotClass.FromExistingClassName != "" {
|
if d.SnapshotClass.FromName || d.SnapshotClass.FromFile != "" || d.SnapshotClass.FromExistingClassName != "" {
|
||||||
supported = true
|
supported = true
|
||||||
}
|
}
|
||||||
|
case testpatterns.PreprovisionedCreatedSnapshot:
|
||||||
|
if d.SnapshotClass.FromName || d.SnapshotClass.FromFile != "" || d.SnapshotClass.FromExistingClassName != "" {
|
||||||
|
supported = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if !supported {
|
if !supported {
|
||||||
e2eskipper.Skipf("Driver %q does not support snapshot type %q - skipping", d.DriverInfo.Name, pattern.SnapshotType)
|
e2eskipper.Skipf("Driver %q does not support snapshot type %q - skipping", d.DriverInfo.Name, pattern.SnapshotType)
|
||||||
|
@ -70,6 +70,10 @@ var (
|
|||||||
RetainSnapshot TestSnapshotDeletionPolicy = "Retain"
|
RetainSnapshot TestSnapshotDeletionPolicy = "Retain"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (t TestSnapshotDeletionPolicy) String() string {
|
||||||
|
return string(t)
|
||||||
|
}
|
||||||
|
|
||||||
// TestPattern represents a combination of parameters to be tested in a TestSuite
|
// TestPattern represents a combination of parameters to be tested in a TestSuite
|
||||||
type TestPattern struct {
|
type TestPattern struct {
|
||||||
Name string // Name of TestPattern
|
Name string // Name of TestPattern
|
||||||
|
@ -18,6 +18,7 @@ package testsuites
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/sha1"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
@ -571,6 +572,64 @@ func getSnapshot(claimName string, ns, snapshotClassName string) *unstructured.U
|
|||||||
|
|
||||||
return snapshot
|
return snapshot
|
||||||
}
|
}
|
||||||
|
func getPreProvisionedSnapshot(snapshotContentName, ns, snapshotHandle string) *unstructured.Unstructured {
|
||||||
|
snapshot := &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"kind": "VolumeSnapshot",
|
||||||
|
"apiVersion": snapshotAPIVersion,
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": getPreProvisionedSnapshotName(snapshotHandle),
|
||||||
|
"namespace": ns,
|
||||||
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"source": map[string]interface{}{
|
||||||
|
"volumeSnapshotContentName": snapshotContentName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return snapshot
|
||||||
|
}
|
||||||
|
func getPreProvisionedSnapshotContent(snapshotName, snapshotNamespace, snapshotHandle, deletionPolicy, csiDriverName, volumeSnapshotClassName string) *unstructured.Unstructured {
|
||||||
|
snapshotContent := &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"kind": "VolumeSnapshotContent",
|
||||||
|
"apiVersion": snapshotAPIVersion,
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": getPreProvisionedSnapshotContentName(snapshotHandle),
|
||||||
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"source": map[string]interface{}{
|
||||||
|
"snapshotHandle": snapshotHandle,
|
||||||
|
},
|
||||||
|
"volumeSnapshotRef": map[string]interface{}{
|
||||||
|
"name": snapshotName,
|
||||||
|
"namespace": snapshotNamespace,
|
||||||
|
},
|
||||||
|
"driver": csiDriverName,
|
||||||
|
"deletionPolicy": deletionPolicy,
|
||||||
|
"volumeSnapshotClassName": volumeSnapshotClassName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return snapshotContent
|
||||||
|
}
|
||||||
|
|
||||||
|
func genShortHash(s string) string {
|
||||||
|
h := sha1.New()
|
||||||
|
h.Write([]byte(s))
|
||||||
|
bs := h.Sum(nil)
|
||||||
|
return fmt.Sprintf("%x", bs)[:7]
|
||||||
|
}
|
||||||
|
func getPreProvisionedSnapshotContentName(snapshotHandle string) string {
|
||||||
|
return fmt.Sprintf("pre-provisioned-snapcontent-%s", genShortHash(snapshotHandle))
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPreProvisionedSnapshotName(snapshotHandle string) string {
|
||||||
|
return fmt.Sprintf("pre-provisioned-snapshot-%s", genShortHash(snapshotHandle))
|
||||||
|
}
|
||||||
|
|
||||||
// StartPodLogs begins capturing log output and events from current
|
// StartPodLogs begins capturing log output and events from current
|
||||||
// and future pods running in the namespace of the framework. That
|
// and future pods running in the namespace of the framework. That
|
||||||
|
@ -75,6 +75,8 @@ func InitSnapshottableTestSuite() TestSuite {
|
|||||||
TestPatterns: []testpatterns.TestPattern{
|
TestPatterns: []testpatterns.TestPattern{
|
||||||
testpatterns.DynamicSnapshotDelete,
|
testpatterns.DynamicSnapshotDelete,
|
||||||
testpatterns.DynamicSnapshotRetain,
|
testpatterns.DynamicSnapshotRetain,
|
||||||
|
testpatterns.PreprovisionedSnapshotDelete,
|
||||||
|
testpatterns.PreprovisionedSnapshotRetain,
|
||||||
},
|
},
|
||||||
SupportedSizeRange: e2evolume.SizeRange{
|
SupportedSizeRange: e2evolume.SizeRange{
|
||||||
Min: "1Mi",
|
Min: "1Mi",
|
||||||
@ -94,7 +96,6 @@ func (s *snapshottableTestSuite) SkipRedundantSuite(driver TestDriver, pattern t
|
|||||||
func (s *snapshottableTestSuite) DefineTests(driver TestDriver, pattern testpatterns.TestPattern) {
|
func (s *snapshottableTestSuite) DefineTests(driver TestDriver, pattern testpatterns.TestPattern) {
|
||||||
ginkgo.BeforeEach(func() {
|
ginkgo.BeforeEach(func() {
|
||||||
// Check preconditions.
|
// Check preconditions.
|
||||||
framework.ExpectEqual(pattern.SnapshotType, testpatterns.DynamicCreatedSnapshot)
|
|
||||||
dInfo := driver.GetDriverInfo()
|
dInfo := driver.GetDriverInfo()
|
||||||
ok := false
|
ok := false
|
||||||
sDriver, ok = driver.(SnapshottableTestDriver)
|
sDriver, ok = driver.(SnapshottableTestDriver)
|
||||||
@ -355,6 +356,10 @@ type SnapshotResource struct {
|
|||||||
// different test pattern snapshot provisioning and deletion policy
|
// different test pattern snapshot provisioning and deletion policy
|
||||||
func CreateSnapshotResource(sDriver SnapshottableTestDriver, config *PerTestConfig, pattern testpatterns.TestPattern, pvcName string, pvcNamespace string) *SnapshotResource {
|
func CreateSnapshotResource(sDriver SnapshottableTestDriver, config *PerTestConfig, pattern testpatterns.TestPattern, pvcName string, pvcNamespace string) *SnapshotResource {
|
||||||
var err error
|
var err error
|
||||||
|
if pattern.SnapshotType != testpatterns.DynamicCreatedSnapshot || pattern.SnapshotType != testpatterns.PreprovisionedCreatedSnapshot {
|
||||||
|
err = fmt.Errorf("SnapshotType must be set to either DynamicCreatedSnapshot or PreprovisionedCreatedSnapshot")
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
}
|
||||||
r := SnapshotResource{
|
r := SnapshotResource{
|
||||||
Config: config,
|
Config: config,
|
||||||
Pattern: pattern,
|
Pattern: pattern,
|
||||||
@ -366,7 +371,7 @@ func CreateSnapshotResource(sDriver SnapshottableTestDriver, config *PerTestConf
|
|||||||
if r.Vsclass == nil {
|
if r.Vsclass == nil {
|
||||||
framework.Failf("Failed to get snapshot class based on test config")
|
framework.Failf("Failed to get snapshot class based on test config")
|
||||||
}
|
}
|
||||||
r.Vsclass.Object["deletionPolicy"] = pattern.SnapshotDeletionPolicy
|
r.Vsclass.Object["deletionPolicy"] = pattern.SnapshotDeletionPolicy.String()
|
||||||
|
|
||||||
r.Vsclass, err = dc.Resource(SnapshotClassGVR).Create(context.TODO(), r.Vsclass, metav1.CreateOptions{})
|
r.Vsclass, err = dc.Resource(SnapshotClassGVR).Create(context.TODO(), r.Vsclass, metav1.CreateOptions{})
|
||||||
framework.ExpectNoError(err)
|
framework.ExpectNoError(err)
|
||||||
@ -402,14 +407,68 @@ func CreateSnapshotResource(sDriver SnapshottableTestDriver, config *PerTestConf
|
|||||||
// to pre-provision the snapshot as we normally would using their API.
|
// to pre-provision the snapshot as we normally would using their API.
|
||||||
// We instead dynamically take a snapshot and create another snapshot using
|
// We instead dynamically take a snapshot and create another snapshot using
|
||||||
// the first snapshot's snapshot handle.
|
// the first snapshot's snapshot handle.
|
||||||
ginkgo.Skip("Preprovisioned test not implemented")
|
ginkgo.By("taking a dynamic snapshot")
|
||||||
ginkgo.By("taking a snapshot with deletion policy retain")
|
r.Vs = getSnapshot(pvcName, pvcNamespace, r.Vsclass.GetName())
|
||||||
ginkgo.By("recording the volume handle and status.snapshotHandle")
|
r.Vs, err = dc.Resource(SnapshotGVR).Namespace(r.Vs.GetNamespace()).Create(context.TODO(), r.Vs, metav1.CreateOptions{})
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
|
||||||
|
err = WaitForSnapshotReady(dc, r.Vs.GetNamespace(), r.Vs.GetName(), framework.Poll, framework.SnapshotCreateTimeout)
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
|
||||||
|
r.Vs, err = dc.Resource(SnapshotGVR).Namespace(r.Vs.GetNamespace()).Get(context.TODO(), r.Vs.GetName(), metav1.GetOptions{})
|
||||||
|
|
||||||
|
snapshotStatus := r.Vs.Object["status"].(map[string]interface{})
|
||||||
|
snapshotContentName := snapshotStatus["boundVolumeSnapshotContentName"].(string)
|
||||||
|
framework.Logf("received snapshotStatus %v", snapshotStatus)
|
||||||
|
framework.Logf("snapshotContentName %s", snapshotContentName)
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
|
||||||
|
ginkgo.By("updating the snapshot content deletion policy to retain")
|
||||||
|
r.Vscontent, err = dc.Resource(SnapshotContentGVR).Get(context.TODO(), snapshotContentName, metav1.GetOptions{})
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
r.Vscontent.Object["spec"].(map[string]interface{})["deletionPolicy"] = "Retain"
|
||||||
|
|
||||||
|
r.Vscontent, err = dc.Resource(SnapshotContentGVR).Update(context.TODO(), r.Vscontent, metav1.UpdateOptions{})
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
|
||||||
|
ginkgo.By("recording the volume handle and snapshotHandle")
|
||||||
|
snapshotHandle := r.Vscontent.Object["status"].(map[string]interface{})["snapshotHandle"].(string)
|
||||||
|
framework.Logf("Recording snapshot handle: %s", snapshotHandle)
|
||||||
|
csiDriverName := r.Vsclass.Object["driver"].(string)
|
||||||
|
|
||||||
ginkgo.By("deleting the snapshot and snapshot content") // TODO: test what happens when I have two snapshot content that refer to the same content
|
ginkgo.By("deleting the snapshot and snapshot content") // TODO: test what happens when I have two snapshot content that refer to the same content
|
||||||
|
err = dc.Resource(SnapshotGVR).Namespace(r.Vs.GetNamespace()).Delete(context.TODO(), r.Vs.GetName(), metav1.DeleteOptions{})
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
|
||||||
|
ginkgo.By("checking the Snapshot has been deleted")
|
||||||
|
err = utils.WaitForNamespacedGVRDeletion(dc, SnapshotGVR, r.Vs.GetName(), r.Vs.GetNamespace(), framework.Poll, framework.SnapshotDeleteTimeout)
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
|
||||||
|
err = dc.Resource(SnapshotContentGVR).Delete(context.TODO(), r.Vscontent.GetName(), metav1.DeleteOptions{})
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
|
||||||
|
ginkgo.By("checking the Snapshot content has been deleted")
|
||||||
|
err = utils.WaitForGVRDeletion(dc, SnapshotContentGVR, r.Vscontent.GetName(), framework.Poll, framework.SnapshotDeleteTimeout)
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
|
||||||
ginkgo.By("creating a snapshot content with the snapshot handle")
|
ginkgo.By("creating a snapshot content with the snapshot handle")
|
||||||
|
r.Vscontent = getPreProvisionedSnapshotContent(getPreProvisionedSnapshotName(snapshotHandle), pvcNamespace, snapshotHandle, pattern.SnapshotDeletionPolicy.String(), csiDriverName, r.Vsclass.GetName())
|
||||||
|
r.Vscontent, err = dc.Resource(SnapshotContentGVR).Create(context.TODO(), r.Vscontent, metav1.CreateOptions{})
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
|
||||||
ginkgo.By("creating a snapshot with that snapshot content")
|
ginkgo.By("creating a snapshot with that snapshot content")
|
||||||
default:
|
r.Vs = getPreProvisionedSnapshot(getPreProvisionedSnapshotContentName(snapshotHandle), pvcNamespace, snapshotHandle)
|
||||||
err = fmt.Errorf("SnapshotType must be set to either DynamicCreatedSnapshot or PreprovisionedCreatedSnapshot")
|
r.Vs, err = dc.Resource(SnapshotGVR).Namespace(r.Vs.GetNamespace()).Create(context.TODO(), r.Vs, metav1.CreateOptions{})
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
|
||||||
|
err = WaitForSnapshotReady(dc, r.Vs.GetNamespace(), r.Vs.GetName(), framework.Poll, framework.SnapshotCreateTimeout)
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
|
||||||
|
ginkgo.By("getting the snapshot and snapshot content")
|
||||||
|
r.Vs, err = dc.Resource(SnapshotGVR).Namespace(r.Vs.GetNamespace()).Get(context.TODO(), r.Vs.GetName(), metav1.GetOptions{})
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
|
||||||
|
r.Vscontent, err = dc.Resource(SnapshotContentGVR).Get(context.TODO(), r.Vscontent.GetName(), metav1.GetOptions{})
|
||||||
framework.ExpectNoError(err)
|
framework.ExpectNoError(err)
|
||||||
}
|
}
|
||||||
return &r
|
return &r
|
||||||
|
Loading…
Reference in New Issue
Block a user