Skip to content

Commit 0e81334

Browse files
iPraveenPariharmergify[bot]
authored andcommitted
e2e: validate image features on temp clone and snapshot backing images
Add an e2e test that verifies the intermediate RBD images created during snapshot and clone operations inherit StorageClass image features. Specifically validates: - csi-snap-* (snapshot backing image) inherits features from parent - csi-vol-*-temp (temp clone image) inherits features from parent Signed-off-by: Praveen M <m.praveen@ibm.com>
1 parent 28daf2e commit 0e81334

File tree

2 files changed

+164
-5
lines changed

2 files changed

+164
-5
lines changed

e2e/rbd.go

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1870,6 +1870,130 @@ var _ = Describe("RBD", func() {
18701870
validateOmapCount(f, 0, rbdType, defaultRBDPool, volumesType)
18711871
})
18721872

1873+
It("verify temp clone and snapshot backing images inherit StorageClass image features",
1874+
func() {
1875+
if !kernel.CheckKernelSupport(kernelRelease, fastDiffSupport) {
1876+
Skip("kernel does not support fast-diff, skipping image features inheritance test")
1877+
}
1878+
1879+
imageFeatures := "layering,exclusive-lock,object-map,fast-diff,deep-flatten"
1880+
expectedFeatures := []string{
1881+
"layering", "exclusive-lock", "object-map", "fast-diff", "deep-flatten",
1882+
}
1883+
1884+
err := deleteResource(rbdExamplePath + "storageclass.yaml")
1885+
if err != nil {
1886+
logAndFail("failed to delete storageclass: %v", err)
1887+
}
1888+
err = createRBDStorageClass(
1889+
f.ClientSet,
1890+
f,
1891+
defaultSCName,
1892+
nil,
1893+
map[string]string{
1894+
"imageFeatures": imageFeatures,
1895+
},
1896+
deletePolicy)
1897+
if err != nil {
1898+
logAndFail("failed to create storageclass: %v", err)
1899+
}
1900+
defer func() {
1901+
err = deleteResource(rbdExamplePath + "storageclass.yaml")
1902+
if err != nil {
1903+
logAndFail("failed to delete storageclass: %v", err)
1904+
}
1905+
err = createRBDStorageClass(f.ClientSet, f, defaultSCName, nil, nil, deletePolicy)
1906+
if err != nil {
1907+
logAndFail("failed to create storageclass: %v", err)
1908+
}
1909+
}()
1910+
1911+
// create source PVC
1912+
pvc, err := loadPVC(pvcPath)
1913+
if err != nil {
1914+
logAndFail("failed to load PVC: %v", err)
1915+
}
1916+
pvc.Namespace = f.UniqueName
1917+
err = createPVCAndvalidatePV(f.ClientSet, pvc, deployTimeout)
1918+
if err != nil {
1919+
logAndFail("failed to create PVC: %v", err)
1920+
}
1921+
1922+
// create a snapshot and verify the backing image (csi-snap-*)
1923+
// inherits StorageClass image features
1924+
err = createRBDSnapshotClass(f)
1925+
if err != nil {
1926+
logAndFail("failed to create snapshotclass: %v", err)
1927+
}
1928+
defer func() {
1929+
err = deleteRBDSnapshotClass()
1930+
if err != nil {
1931+
logAndFail("failed to delete snapshotclass: %v", err)
1932+
}
1933+
}()
1934+
1935+
snap := getSnapshot(snapshotPath)
1936+
snap.Namespace = f.UniqueName
1937+
snap.Spec.Source.PersistentVolumeClaimName = &pvc.Name
1938+
err = createSnapshot(&snap, deployTimeout)
1939+
if err != nil {
1940+
logAndFail("failed to create snapshot: %v", err)
1941+
}
1942+
1943+
snapImageName, err := getSnapName(snap.Namespace, snap.Name)
1944+
if err != nil {
1945+
logAndFail("failed to get snapshot image name: %v", err)
1946+
}
1947+
err = validateImageFeatures(f, snapImageName, defaultRBDPool, expectedFeatures)
1948+
if err != nil {
1949+
logAndFail("snapshot backing image %s features validation failed: %v",
1950+
snapImageName, err)
1951+
}
1952+
1953+
err = deleteSnapshot(&snap, deployTimeout)
1954+
if err != nil {
1955+
logAndFail("failed to delete snapshot: %v", err)
1956+
}
1957+
1958+
// create a PVC-PVC clone and verify the temp clone image
1959+
// (csi-vol-*-temp) inherits StorageClass image features
1960+
pvcSmartClone, err := loadPVC(pvcSmartClonePath)
1961+
if err != nil {
1962+
logAndFail("failed to load PVC: %v", err)
1963+
}
1964+
pvcSmartClone.Namespace = f.UniqueName
1965+
pvcSmartClone.Spec.DataSource.Name = pvc.Name
1966+
err = createPVCAndvalidatePV(f.ClientSet, pvcSmartClone, deployTimeout)
1967+
if err != nil {
1968+
logAndFail("failed to create cloned PVC: %v", err)
1969+
}
1970+
1971+
// the temp clone image name is the clone image name + "-temp"
1972+
imageData, err := getImageInfoFromPVC(pvcSmartClone.Namespace, pvcSmartClone.Name, f)
1973+
if err != nil {
1974+
logAndFail("failed to get image info from source PVC: %v", err)
1975+
}
1976+
tempCloneImageName := imageData.imageName + "-temp"
1977+
err = validateImageFeatures(f, tempCloneImageName, defaultRBDPool, expectedFeatures)
1978+
if err != nil {
1979+
logAndFail("temp clone image %s features validation failed: %v",
1980+
tempCloneImageName, err)
1981+
}
1982+
1983+
// clean up clone and source
1984+
err = deletePVCAndValidatePV(f.ClientSet, pvcSmartClone, deployTimeout)
1985+
if err != nil {
1986+
logAndFail("failed to delete cloned PVC: %v", err)
1987+
}
1988+
err = deletePVCAndValidatePV(f.ClientSet, pvc, deployTimeout)
1989+
if err != nil {
1990+
logAndFail("failed to delete source PVC: %v", err)
1991+
}
1992+
1993+
validateRBDImageCount(f, 0, defaultRBDPool)
1994+
validateOmapCount(f, 0, rbdType, defaultRBDPool, volumesType)
1995+
})
1996+
18731997
It("create PVC without layering,deep-flatten image-features and bind it to an app",
18741998
func() {
18751999
err := deleteResource(rbdExamplePath + "storageclass.yaml")

e2e/rbd_helper.go

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,11 +1230,12 @@ func waitToRemoveImagesFromTrash(f *framework.Framework, poolName string, t int)
12301230

12311231
// imageInfo strongly typed JSON spec for image info.
12321232
type imageInfo struct {
1233-
Name string `json:"name"`
1234-
StripeUnit int `json:"stripe_unit"`
1235-
StripeCount int `json:"stripe_count"`
1236-
ObjectSize int `json:"object_size"`
1237-
DataPool string `json:"data_pool"`
1233+
Name string `json:"name"`
1234+
StripeUnit int `json:"stripe_unit"`
1235+
StripeCount int `json:"stripe_count"`
1236+
ObjectSize int `json:"object_size"`
1237+
DataPool string `json:"data_pool"`
1238+
Features []string `json:"features"`
12381239
}
12391240

12401241
// getImageInfo queries rbd about the given image and returns its metadata, and returns
@@ -1313,6 +1314,40 @@ func validateStripe(f *framework.Framework,
13131314
return nil
13141315
}
13151316

1317+
// validateImageFeatures checks that the given RBD image has all the expected
1318+
// image features enabled.
1319+
func validateImageFeatures(
1320+
f *framework.Framework,
1321+
imageName, pool string,
1322+
expectedFeatures []string,
1323+
) error {
1324+
var imgInfo imageInfo
1325+
1326+
imgInfoStr, err := getImageInfo(f, imageName, pool)
1327+
if err != nil {
1328+
return err
1329+
}
1330+
1331+
err = json.Unmarshal([]byte(imgInfoStr), &imgInfo)
1332+
if err != nil {
1333+
return fmt.Errorf("unmarshal failed: %w. raw buffer response: %s", err, imgInfoStr)
1334+
}
1335+
1336+
actualSet := make(map[string]bool, len(imgInfo.Features))
1337+
for _, feat := range imgInfo.Features {
1338+
actualSet[feat] = true
1339+
}
1340+
1341+
for _, want := range expectedFeatures {
1342+
if !actualSet[want] {
1343+
return fmt.Errorf("image %s missing expected feature %q, got features: %v",
1344+
imageName, want, imgInfo.Features)
1345+
}
1346+
}
1347+
1348+
return nil
1349+
}
1350+
13161351
func validateQOS(f *framework.Framework,
13171352
pvc *v1.PersistentVolumeClaim,
13181353
wants map[string]string,

0 commit comments

Comments
 (0)