2020-09-03 09:34:29 +00:00
|
|
|
package e2e
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2021-02-10 08:19:40 +00:00
|
|
|
"regexp"
|
2020-09-03 09:34:29 +00:00
|
|
|
"strings"
|
|
|
|
|
2021-02-10 08:19:40 +00:00
|
|
|
snapapi "github.com/kubernetes-csi/external-snapshotter/v2/pkg/apis/volumesnapshot/v1beta1"
|
2020-09-03 09:34:29 +00:00
|
|
|
v1 "k8s.io/api/core/v1"
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
"k8s.io/client-go/kubernetes"
|
|
|
|
"k8s.io/kubernetes/test/e2e/framework"
|
2021-02-10 08:19:40 +00:00
|
|
|
e2elog "k8s.io/kubernetes/test/e2e/framework/log"
|
2020-09-03 09:34:29 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
adminUser = "admin"
|
|
|
|
)
|
|
|
|
|
|
|
|
// validateSubvolumegroup validates whether subvolumegroup is present.
|
|
|
|
func validateSubvolumegroup(f *framework.Framework, subvolgrp string) error {
|
|
|
|
cmd := fmt.Sprintf("ceph fs subvolumegroup getpath myfs %s", subvolgrp)
|
|
|
|
stdOut, stdErr, err := execCommandInToolBoxPod(f, cmd, rookNamespace)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if stdErr != "" {
|
|
|
|
return fmt.Errorf("failed to getpath for subvolumegroup %s with error %v", subvolgrp, stdErr)
|
|
|
|
}
|
|
|
|
expectedGrpPath := "/volumes/" + subvolgrp
|
|
|
|
stdOut = strings.TrimSpace(stdOut)
|
|
|
|
if stdOut != expectedGrpPath {
|
|
|
|
return fmt.Errorf("error unexpected group path. Found: %s", stdOut)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-09-21 14:56:15 +00:00
|
|
|
func createCephfsStorageClass(c kubernetes.Interface, f *framework.Framework, enablePool bool, params map[string]string) error {
|
2020-09-03 09:34:29 +00:00
|
|
|
scPath := fmt.Sprintf("%s/%s", cephfsExamplePath, "storageclass.yaml")
|
|
|
|
sc, err := getStorageClass(scPath)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
sc.Parameters["fsName"] = "myfs"
|
2021-02-22 11:13:40 +00:00
|
|
|
sc.Parameters["csi.storage.k8s.io/provisioner-secret-namespace"] = cephCSINamespace
|
|
|
|
sc.Parameters["csi.storage.k8s.io/provisioner-secret-name"] = cephFSProvisionerSecretName
|
2020-09-03 09:34:29 +00:00
|
|
|
|
2021-02-22 11:13:40 +00:00
|
|
|
sc.Parameters["csi.storage.k8s.io/controller-expand-secret-namespace"] = cephCSINamespace
|
|
|
|
sc.Parameters["csi.storage.k8s.io/controller-expand-secret-name"] = cephFSProvisionerSecretName
|
2020-09-03 09:34:29 +00:00
|
|
|
|
2021-02-22 11:13:40 +00:00
|
|
|
sc.Parameters["csi.storage.k8s.io/node-stage-secret-namespace"] = cephCSINamespace
|
|
|
|
sc.Parameters["csi.storage.k8s.io/node-stage-secret-name"] = cephFSNodePluginSecretName
|
2020-09-03 09:34:29 +00:00
|
|
|
|
|
|
|
if enablePool {
|
|
|
|
sc.Parameters["pool"] = "myfs-data0"
|
|
|
|
}
|
2020-09-21 14:56:15 +00:00
|
|
|
|
|
|
|
// overload any parameters that were passed
|
|
|
|
if params == nil {
|
|
|
|
// create an empty params, so that params["clusterID"] below
|
|
|
|
// does not panic
|
|
|
|
params = map[string]string{}
|
2020-09-03 09:34:29 +00:00
|
|
|
}
|
2020-09-21 14:56:15 +00:00
|
|
|
for param, value := range params {
|
|
|
|
sc.Parameters[param] = value
|
2020-09-03 09:34:29 +00:00
|
|
|
}
|
2020-09-21 14:56:15 +00:00
|
|
|
|
|
|
|
// fetch and set fsID from the cluster if not set in params
|
|
|
|
if _, found := params["clusterID"]; !found {
|
|
|
|
fsID, stdErr, failErr := execCommandInToolBoxPod(f, "ceph fsid", rookNamespace)
|
|
|
|
if failErr != nil {
|
|
|
|
return failErr
|
|
|
|
}
|
|
|
|
if stdErr != "" {
|
|
|
|
return fmt.Errorf("error getting fsid %v", stdErr)
|
|
|
|
}
|
|
|
|
sc.Parameters["clusterID"] = strings.Trim(fsID, "\n")
|
2020-09-03 09:34:29 +00:00
|
|
|
}
|
|
|
|
sc.Namespace = cephCSINamespace
|
|
|
|
_, err = c.StorageV1().StorageClasses().Create(context.TODO(), &sc, metav1.CreateOptions{})
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-02-22 11:13:40 +00:00
|
|
|
func createCephfsSecret(f *framework.Framework, secretName, userName, userKey string) error {
|
2020-09-03 09:34:29 +00:00
|
|
|
scPath := fmt.Sprintf("%s/%s", cephfsExamplePath, "secret.yaml")
|
|
|
|
sc, err := getSecret(scPath)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-02-22 11:13:40 +00:00
|
|
|
if secretName != "" {
|
|
|
|
sc.Name = secretName
|
2020-09-03 09:34:29 +00:00
|
|
|
}
|
2021-02-22 11:13:40 +00:00
|
|
|
sc.StringData["adminID"] = userName
|
|
|
|
sc.StringData["adminKey"] = userKey
|
2020-09-03 09:34:29 +00:00
|
|
|
delete(sc.StringData, "userID")
|
|
|
|
delete(sc.StringData, "userKey")
|
|
|
|
sc.Namespace = cephCSINamespace
|
2021-02-22 11:13:40 +00:00
|
|
|
_, err = f.ClientSet.CoreV1().Secrets(cephCSINamespace).Create(context.TODO(), &sc, metav1.CreateOptions{})
|
2020-09-03 09:34:29 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-03-22 06:17:42 +00:00
|
|
|
// unmountCephFSVolume unmounts a cephFS volume mounted on a pod.
|
|
|
|
func unmountCephFSVolume(f *framework.Framework, appName, pvcName string) error {
|
|
|
|
pod, err := f.ClientSet.CoreV1().Pods(f.UniqueName).Get(context.TODO(), appName, metav1.GetOptions{})
|
|
|
|
if err != nil {
|
|
|
|
e2elog.Logf("Error occurred getting pod %s in namespace %s", appName, f.UniqueName)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
pvc, err := f.ClientSet.CoreV1().PersistentVolumeClaims(f.UniqueName).Get(context.TODO(), pvcName, metav1.GetOptions{})
|
|
|
|
if err != nil {
|
|
|
|
e2elog.Logf("Error occurred getting PVC %s in namespace %s", pvcName, f.UniqueName)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd := fmt.Sprintf("umount /var/lib/kubelet/pods/%s/volumes/kubernetes.io~csi/%s/mount", pod.UID, pvc.Spec.VolumeName)
|
|
|
|
_, stdErr, err := execCommandInDaemonsetPod(f, cmd, cephfsDeamonSetName, pod.Spec.NodeName, cephfsContainerName, cephCSINamespace)
|
|
|
|
if stdErr != "" {
|
|
|
|
e2elog.Logf("StdErr occurred: %s", stdErr)
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-09-03 09:34:29 +00:00
|
|
|
func deleteBackingCephFSVolume(f *framework.Framework, pvc *v1.PersistentVolumeClaim) error {
|
|
|
|
imageData, err := getImageInfoFromPVC(pvc.Namespace, pvc.Name, f)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-02-10 08:19:40 +00:00
|
|
|
cmd := fmt.Sprintf("ceph fs subvolume rm %s %s %s", fileSystemName, imageData.imageName, subvolumegroup)
|
|
|
|
_, stdErr, err := execCommandInToolBoxPod(f, cmd, rookNamespace)
|
2020-09-03 09:34:29 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if stdErr != "" {
|
|
|
|
return fmt.Errorf("error deleting backing volume %s %v", imageData.imageName, stdErr)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type cephfsSubVolume struct {
|
|
|
|
Name string `json:"name"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func listCephFSSubVolumes(f *framework.Framework, filesystem, groupname string) ([]cephfsSubVolume, error) {
|
|
|
|
var subVols []cephfsSubVolume
|
|
|
|
stdout, stdErr, err := execCommandInToolBoxPod(f, fmt.Sprintf("ceph fs subvolume ls %s --group_name=%s --format=json", filesystem, groupname), rookNamespace)
|
|
|
|
if err != nil {
|
|
|
|
return subVols, err
|
|
|
|
}
|
|
|
|
if stdErr != "" {
|
|
|
|
return subVols, fmt.Errorf("error listing subolumes %v", stdErr)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = json.Unmarshal([]byte(stdout), &subVols)
|
|
|
|
if err != nil {
|
|
|
|
return subVols, err
|
|
|
|
}
|
|
|
|
return subVols, nil
|
|
|
|
}
|
2021-02-09 10:32:40 +00:00
|
|
|
|
|
|
|
// getSubvolumepath validates whether subvolumegroup is present.
|
|
|
|
func getSubvolumePath(f *framework.Framework, filesystem, subvolgrp, subvolume string) (string, error) {
|
|
|
|
cmd := fmt.Sprintf("ceph fs subvolume getpath %s %s --group_name=%s", filesystem, subvolume, subvolgrp)
|
|
|
|
stdOut, stdErr, err := execCommandInToolBoxPod(f, cmd, rookNamespace)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
if stdErr != "" {
|
|
|
|
return "", fmt.Errorf("failed to getpath for subvolume %s with error %s", subvolume, stdErr)
|
|
|
|
}
|
|
|
|
return strings.TrimSpace(stdOut), nil
|
|
|
|
}
|
2021-02-10 08:19:40 +00:00
|
|
|
|
|
|
|
func getSnapName(snapNamespace, snapName string) (string, error) {
|
|
|
|
sclient, err := newSnapshotClient()
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
snap, err := sclient.SnapshotV1beta1().VolumeSnapshots(snapNamespace).Get(context.TODO(), snapName, metav1.GetOptions{})
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
sc, err := sclient.SnapshotV1beta1().VolumeSnapshotContents().Get(context.TODO(), *snap.Status.BoundVolumeSnapshotContentName, metav1.GetOptions{})
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
snapIDRegex := regexp.MustCompile(`(\w+\-?){5}$`)
|
|
|
|
snapID := snapIDRegex.FindString(*sc.Status.SnapshotHandle)
|
|
|
|
snapshotName := fmt.Sprintf("csi-snap-%s", snapID)
|
|
|
|
e2elog.Logf("snapshotName= %s", snapshotName)
|
|
|
|
return snapshotName, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func deleteBackingCephFSSubvolumeSnapshot(f *framework.Framework, pvc *v1.PersistentVolumeClaim, snap *snapapi.VolumeSnapshot) error {
|
|
|
|
snapshotName, err := getSnapName(snap.Namespace, snap.Name)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
imageData, err := getImageInfoFromPVC(pvc.Namespace, pvc.Name, f)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cmd := fmt.Sprintf("ceph fs subvolume snapshot rm %s %s %s %s", fileSystemName, imageData.imageName, snapshotName, subvolumegroup)
|
|
|
|
_, stdErr, err := execCommandInToolBoxPod(f, cmd, rookNamespace)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if stdErr != "" {
|
|
|
|
return fmt.Errorf("error deleting backing snapshot %s %v", snapshotName, stdErr)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|