mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 18:43:34 +00:00
added volumeNamePrefix and snapshotNamePrefix as parameters for storageClass
this allows administrators to override the naming prefix for both volumes and snapshots created by the rbd plugin. Signed-off-by: Reinier Schoof <reinier@skoef.nl>
This commit is contained in:
committed by
mergify[bot]
parent
8163552b81
commit
a4532fafd0
@ -71,6 +71,9 @@ func (cs *ControllerServer) validateVolumeReq(ctx context.Context, req *csi.Crea
|
||||
if value, ok := options["dataPool"]; ok && value == "" {
|
||||
return status.Error(codes.InvalidArgument, "empty datapool name to provision volume from")
|
||||
}
|
||||
if value, ok := options["volumeNamePrefix"]; ok && value == "" {
|
||||
return status.Error(codes.InvalidArgument, "empty volume name prefix to provision volume from")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -567,6 +570,11 @@ func (cs *ControllerServer) validateSnapshotReq(ctx context.Context, req *csi.Cr
|
||||
return status.Error(codes.InvalidArgument, "source Volume ID cannot be empty")
|
||||
}
|
||||
|
||||
options := req.GetParameters()
|
||||
if value, ok := options["snapshotNamePrefix"]; ok && value == "" {
|
||||
return status.Error(codes.InvalidArgument, "empty snapshot name prefix to provision snapshot from")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -68,12 +68,12 @@ func (ns *NodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVol
|
||||
disableInUseChecks := false
|
||||
// MULTI_NODE_MULTI_WRITER is supported by default for Block access type volumes
|
||||
if req.VolumeCapability.AccessMode.Mode == csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER {
|
||||
if isBlock {
|
||||
disableInUseChecks = true
|
||||
} else {
|
||||
if !isBlock {
|
||||
klog.Warningf(util.Log(ctx, "MULTI_NODE_MULTI_WRITER currently only supported with volumes of access type `block`, invalid AccessMode for volume: %v"), req.GetVolumeId())
|
||||
return nil, status.Error(codes.InvalidArgument, "rbd: RWX access mode request is only valid for volumes with access type `block`")
|
||||
}
|
||||
|
||||
disableInUseChecks = true
|
||||
}
|
||||
|
||||
volID := req.GetVolumeId()
|
||||
@ -102,11 +102,6 @@ func (ns *NodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVol
|
||||
}
|
||||
}
|
||||
|
||||
isLegacyVolume, volName, err := getVolumeNameByID(volID, stagingParentPath, staticVol)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var isNotMnt bool
|
||||
// check if stagingPath is already mounted
|
||||
isNotMnt, err = mount.IsNotMountPoint(ns.mounter, stagingTargetPath)
|
||||
@ -115,16 +110,39 @@ func (ns *NodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVol
|
||||
}
|
||||
|
||||
if !isNotMnt {
|
||||
klog.Infof(util.Log(ctx, "rbd: volume %s is already mounted to %s, skipping"), req.GetVolumeId(), stagingTargetPath)
|
||||
klog.Infof(util.Log(ctx, "rbd: volume %s is already mounted to %s, skipping"), volID, stagingTargetPath)
|
||||
return &csi.NodeStageVolumeResponse{}, nil
|
||||
}
|
||||
|
||||
isLegacyVolume := isLegacyVolumeID(volID)
|
||||
volOptions, err := genVolFromVolumeOptions(ctx, req.GetVolumeContext(), req.GetSecrets(), disableInUseChecks, isLegacyVolume)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
volOptions.RbdImageName = volName
|
||||
volOptions.VolID = req.GetVolumeId()
|
||||
|
||||
// get rbd image name from the volume journal
|
||||
// for static volumes, the image name is actually the volume ID itself
|
||||
// for legacy volumes (v1.0.0), the image name can be found in the staging path
|
||||
switch {
|
||||
case staticVol:
|
||||
volOptions.RbdImageName = volID
|
||||
case isLegacyVolume:
|
||||
volOptions.RbdImageName, err = getLegacyVolumeName(stagingTargetPath)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
default:
|
||||
var vi util.CSIIdentifier
|
||||
err = vi.DecomposeCSIID(volID)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error decoding volume ID (%s) (%s)", err, volID)
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
_, volOptions.RbdImageName, _, _, err = volJournal.GetObjectUUIDData(ctx, volOptions.Monitors, cr, volOptions.Pool, vi.ObjectUUID, false)
|
||||
}
|
||||
|
||||
volOptions.VolID = volID
|
||||
|
||||
isMounted := false
|
||||
isEncrypted := false
|
||||
@ -139,41 +157,13 @@ func (ns *NodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVol
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
ns.undoStagingTransaction(ctx, stagingParentPath, devicePath, volID, isStagePathCreated, isMounted, isEncrypted)
|
||||
ns.undoStagingTransaction(ctx, req, devicePath, isStagePathCreated, isMounted, isEncrypted)
|
||||
}
|
||||
}()
|
||||
|
||||
// Mapping RBD image
|
||||
devicePath, err = attachRBDImage(ctx, volOptions, cr)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
klog.V(4).Infof(util.Log(ctx, "rbd image: %s/%s was successfully mapped at %s\n"),
|
||||
req.GetVolumeId(), volOptions.Pool, devicePath)
|
||||
|
||||
if volOptions.Encrypted {
|
||||
devicePath, err = ns.processEncryptedDevice(ctx, volOptions, devicePath, cr)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
isEncrypted = true
|
||||
}
|
||||
|
||||
err = ns.createStageMountPoint(ctx, stagingTargetPath, isBlock)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
isStagePathCreated = true
|
||||
|
||||
// nodeStage Path
|
||||
err = ns.mountVolumeToStagePath(ctx, req, staticVol, stagingTargetPath, devicePath)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
isMounted = true
|
||||
|
||||
// #nosec - allow anyone to write inside the target path
|
||||
err = os.Chmod(stagingTargetPath, 0777)
|
||||
// perform the actual staging and if this fails, have undoStagingTransaction
|
||||
// cleans up for us
|
||||
isStagePathCreated, isMounted, isEncrypted, err = ns.stageTransaction(ctx, req, volOptions, staticVol)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
@ -183,10 +173,65 @@ func (ns *NodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVol
|
||||
return &csi.NodeStageVolumeResponse{}, nil
|
||||
}
|
||||
|
||||
func (ns *NodeServer) undoStagingTransaction(ctx context.Context, stagingParentPath, devicePath, volID string, isStagePathCreated, isMounted, isEncrypted bool) {
|
||||
func (ns *NodeServer) stageTransaction(ctx context.Context, req *csi.NodeStageVolumeRequest, volOptions *rbdVolume, staticVol bool) (bool, bool, bool, error) {
|
||||
isStagePathCreated := false
|
||||
isMounted := false
|
||||
isEncrypted := false
|
||||
|
||||
var err error
|
||||
|
||||
stagingTargetPath := stagingParentPath + "/" + volID
|
||||
var cr *util.Credentials
|
||||
cr, err = util.NewUserCredentials(req.GetSecrets())
|
||||
if err != nil {
|
||||
return isStagePathCreated, isMounted, isEncrypted, err
|
||||
}
|
||||
defer cr.DeleteCredentials()
|
||||
|
||||
// Mapping RBD image
|
||||
var devicePath string
|
||||
devicePath, err = attachRBDImage(ctx, volOptions, cr)
|
||||
if err != nil {
|
||||
return isStagePathCreated, isMounted, isEncrypted, err
|
||||
}
|
||||
|
||||
klog.V(4).Infof(util.Log(ctx, "rbd image: %s/%s was successfully mapped at %s\n"),
|
||||
req.GetVolumeId(), volOptions.Pool, devicePath)
|
||||
|
||||
if volOptions.Encrypted {
|
||||
devicePath, err = ns.processEncryptedDevice(ctx, volOptions, devicePath, cr)
|
||||
if err != nil {
|
||||
return isStagePathCreated, isMounted, isEncrypted, err
|
||||
}
|
||||
isEncrypted = true
|
||||
}
|
||||
|
||||
stagingTargetPath := getStagingTargetPath(req)
|
||||
|
||||
isBlock := req.GetVolumeCapability().GetBlock() != nil
|
||||
err = ns.createStageMountPoint(ctx, stagingTargetPath, isBlock)
|
||||
if err != nil {
|
||||
return isStagePathCreated, isMounted, isEncrypted, err
|
||||
}
|
||||
|
||||
isStagePathCreated = true
|
||||
|
||||
// nodeStage Path
|
||||
err = ns.mountVolumeToStagePath(ctx, req, staticVol, stagingTargetPath, devicePath)
|
||||
if err != nil {
|
||||
return isStagePathCreated, isMounted, isEncrypted, err
|
||||
}
|
||||
isMounted = true
|
||||
|
||||
// #nosec - allow anyone to write inside the target path
|
||||
err = os.Chmod(stagingTargetPath, 0777)
|
||||
|
||||
return isStagePathCreated, isMounted, isEncrypted, err
|
||||
}
|
||||
|
||||
func (ns *NodeServer) undoStagingTransaction(ctx context.Context, req *csi.NodeStageVolumeRequest, devicePath string, isStagePathCreated, isMounted, isEncrypted bool) {
|
||||
var err error
|
||||
|
||||
stagingTargetPath := getStagingTargetPath(req)
|
||||
if isMounted {
|
||||
err = ns.mounter.Unmount(stagingTargetPath)
|
||||
if err != nil {
|
||||
@ -204,6 +249,8 @@ func (ns *NodeServer) undoStagingTransaction(ctx context.Context, stagingParentP
|
||||
}
|
||||
}
|
||||
|
||||
volID := req.GetVolumeId()
|
||||
|
||||
// Unmapping rbd device
|
||||
if devicePath != "" {
|
||||
err = detachRBDDevice(ctx, devicePath, volID, isEncrypted)
|
||||
@ -214,7 +261,7 @@ func (ns *NodeServer) undoStagingTransaction(ctx context.Context, stagingParentP
|
||||
}
|
||||
|
||||
// Cleanup the stashed image metadata
|
||||
if err = cleanupRBDImageMetadataStash(stagingParentPath); err != nil {
|
||||
if err = cleanupRBDImageMetadataStash(req.GetStagingTargetPath()); err != nil {
|
||||
klog.Errorf(util.Log(ctx, "failed to cleanup image metadata stash (%v)"), err)
|
||||
return
|
||||
}
|
||||
@ -457,6 +504,19 @@ func (ns *NodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpu
|
||||
return &csi.NodeUnpublishVolumeResponse{}, nil
|
||||
}
|
||||
|
||||
// getStagingTargetPath concats either NodeStageVolumeRequest's or
|
||||
// NodeUnstageVolumeRequest's target path with the volumeID
|
||||
func getStagingTargetPath(req interface{}) string {
|
||||
switch vr := req.(type) {
|
||||
case *csi.NodeStageVolumeRequest:
|
||||
return vr.GetStagingTargetPath() + "/" + vr.GetVolumeId()
|
||||
case *csi.NodeUnstageVolumeRequest:
|
||||
return vr.GetStagingTargetPath() + "/" + vr.GetVolumeId()
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// NodeUnstageVolume unstages the volume from the staging path
|
||||
func (ns *NodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstageVolumeRequest) (*csi.NodeUnstageVolumeResponse, error) {
|
||||
var err error
|
||||
@ -473,7 +533,7 @@ func (ns *NodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstag
|
||||
defer ns.VolumeLocks.Release(volID)
|
||||
|
||||
stagingParentPath := req.GetStagingTargetPath()
|
||||
stagingTargetPath := stagingParentPath + "/" + req.GetVolumeId()
|
||||
stagingTargetPath := getStagingTargetPath(req)
|
||||
|
||||
notMnt, err := mount.IsNotMountPoint(ns.mounter, stagingTargetPath)
|
||||
if err != nil {
|
||||
@ -556,10 +616,6 @@ func (ns *NodeServer) NodeExpandVolume(ctx context.Context, req *csi.NodeExpandV
|
||||
}
|
||||
defer ns.VolumeLocks.Release(volumeID)
|
||||
|
||||
volName, err := getVolumeName(volumeID)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||
}
|
||||
// volumePath is targetPath for block PVC and stagingPath for filesystem.
|
||||
// check the path is mountpoint or not, if it is
|
||||
// mountpoint treat this as block PVC or else it is filesystem PVC
|
||||
@ -574,14 +630,12 @@ func (ns *NodeServer) NodeExpandVolume(ctx context.Context, req *csi.NodeExpandV
|
||||
if !notMnt {
|
||||
return &csi.NodeExpandVolumeResponse{}, nil
|
||||
}
|
||||
imgInfo, devicePath, err := getDevicePathAndImageInfo(ctx, volumePath)
|
||||
|
||||
devicePath, err := getDevicePath(ctx, volumePath)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
if volName != imgInfo.ImageName {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "volume name missmatch between request (%s) and stored metadata (%s)", volName, imgInfo.ImageName)
|
||||
}
|
||||
diskMounter := &mount.SafeFormatAndMount{Interface: ns.mounter, Exec: utilexec.New()}
|
||||
// TODO check size and return success or error
|
||||
volumePath += "/" + volumeID
|
||||
@ -593,16 +647,16 @@ func (ns *NodeServer) NodeExpandVolume(ctx context.Context, req *csi.NodeExpandV
|
||||
return &csi.NodeExpandVolumeResponse{}, nil
|
||||
}
|
||||
|
||||
func getDevicePathAndImageInfo(ctx context.Context, volumePath string) (rbdImageMetadataStash, string, error) {
|
||||
func getDevicePath(ctx context.Context, volumePath string) (string, error) {
|
||||
imgInfo, err := lookupRBDImageMetadataStash(volumePath)
|
||||
if err != nil {
|
||||
klog.Errorf(util.Log(ctx, "failed to find image metadata: %v"), err)
|
||||
}
|
||||
device, found := findDeviceMappingImage(ctx, imgInfo.Pool, imgInfo.ImageName, imgInfo.NbdAccess)
|
||||
if found {
|
||||
return imgInfo, device, nil
|
||||
return device, nil
|
||||
}
|
||||
return rbdImageMetadataStash{}, "", fmt.Errorf("failed to get device for stagingtarget path %v", volumePath)
|
||||
return "", fmt.Errorf("failed to get device for stagingtarget path %v", volumePath)
|
||||
}
|
||||
|
||||
// NodeGetCapabilities returns the supported capabilities of the node server
|
||||
@ -731,28 +785,3 @@ func openEncryptedDevice(ctx context.Context, volOptions *rbdVolume, devicePath
|
||||
|
||||
return mapperFilePath, nil
|
||||
}
|
||||
|
||||
func getVolumeNameByID(volID, stagingTargetPath string, staticVol bool) (bool, string, error) {
|
||||
volName, err := getVolumeName(volID)
|
||||
if err != nil {
|
||||
if staticVol {
|
||||
return false, volID, nil
|
||||
}
|
||||
|
||||
// error ErrInvalidVolID may mean this is an 1.0.0 version volume, check for name
|
||||
// pattern match in addition to error to ensure this is a likely v1.0.0 volume
|
||||
|
||||
if _, ok := err.(ErrInvalidVolID); !ok || !isLegacyVolumeID(volID) {
|
||||
return false, "", status.Error(codes.InvalidArgument, err.Error())
|
||||
}
|
||||
|
||||
volName, err = getLegacyVolumeName(stagingTargetPath)
|
||||
if err != nil {
|
||||
return false, "", status.Error(codes.InvalidArgument, err.Error())
|
||||
}
|
||||
|
||||
return true, volName, nil
|
||||
}
|
||||
|
||||
return false, volName, nil
|
||||
}
|
||||
|
76
pkg/rbd/nodeserver_test.go
Normal file
76
pkg/rbd/nodeserver_test.go
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
Copyright 2020 The Ceph-CSI 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 rbd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/container-storage-interface/spec/lib/go/csi"
|
||||
)
|
||||
|
||||
func TestGetLegacyVolumeName(t *testing.T) {
|
||||
tests := []struct {
|
||||
mountPath string
|
||||
volName string
|
||||
}{
|
||||
{"csi/vol/56a0cc34-a5c9-44ab-ad33-ed53dd2bd5ea/globalmount", "56a0cc34-a5c9-44ab-ad33-ed53dd2bd5ea"},
|
||||
{"csi/vol/9fdb7491-3469-4414-8fe2-ea96be6f7f72/mount", "9fdb7491-3469-4414-8fe2-ea96be6f7f72"},
|
||||
{"csi/vol/82cd91c4-4582-47b3-bb08-a84f8c5716d6", "82cd91c4-4582-47b3-bb08-a84f8c5716d6"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
if got, err := getLegacyVolumeName(test.mountPath); err != nil {
|
||||
t.Errorf("getLegacyVolumeName(%s) returned error when it shouldn't: %s", test.mountPath, err.Error())
|
||||
} else if got != test.volName {
|
||||
t.Errorf("getLegacyVolumeName(%s) = %s, want %s", test.mountPath, got, test.volName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetStagingPath(t *testing.T) {
|
||||
var stagingPath string
|
||||
// test with nodestagevolumerequest
|
||||
nsvr := &csi.NodeStageVolumeRequest{
|
||||
VolumeId: "758978be-6331-4925-b25e-e490fe99c9eb",
|
||||
StagingTargetPath: "/path/to/stage",
|
||||
}
|
||||
|
||||
expect := "/path/to/stage/758978be-6331-4925-b25e-e490fe99c9eb"
|
||||
stagingPath = getStagingTargetPath(nsvr)
|
||||
if stagingPath != expect {
|
||||
t.Errorf("getStagingTargetPath() = %s, got %s", stagingPath, expect)
|
||||
}
|
||||
|
||||
// test with nodestagevolumerequest
|
||||
nuvr := &csi.NodeUnstageVolumeRequest{
|
||||
VolumeId: "622cfdeb-69bf-4de6-9bd7-5fa0b71a603e",
|
||||
StagingTargetPath: "/path/to/unstage",
|
||||
}
|
||||
|
||||
expect = "/path/to/unstage/622cfdeb-69bf-4de6-9bd7-5fa0b71a603e"
|
||||
stagingPath = getStagingTargetPath(nuvr)
|
||||
if stagingPath != expect {
|
||||
t.Errorf("getStagingTargetPath() = %s, got %s", stagingPath, expect)
|
||||
}
|
||||
|
||||
// test with non-handled interface
|
||||
expect = ""
|
||||
stagingPath = getStagingTargetPath("")
|
||||
if stagingPath != expect {
|
||||
t.Errorf("getStagingTargetPath() = %s, got %s", stagingPath, expect)
|
||||
}
|
||||
}
|
@ -115,14 +115,21 @@ func checkSnapExists(ctx context.Context, rbdSnap *rbdSnapshot, cr *util.Credent
|
||||
}
|
||||
|
||||
snapUUID, err := snapJournal.CheckReservation(ctx, rbdSnap.Monitors, cr, rbdSnap.Pool,
|
||||
rbdSnap.RequestName, rbdSnap.RbdImageName, "")
|
||||
rbdSnap.RequestName, rbdSnap.NamePrefix, rbdSnap.RbdImageName, "")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if snapUUID == "" {
|
||||
return false, nil
|
||||
}
|
||||
rbdSnap.RbdSnapName = snapJournal.NamingPrefix() + snapUUID
|
||||
|
||||
// now that we now that the reservation exists, let's get the image name from
|
||||
// the omap
|
||||
_, rbdSnap.RbdSnapName, _, _, err = volJournal.GetObjectUUIDData(ctx, rbdSnap.Monitors, cr,
|
||||
rbdSnap.Pool, snapUUID, false)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Fetch on-disk image attributes
|
||||
err = updateSnapWithImageInfo(ctx, rbdSnap, cr)
|
||||
@ -167,14 +174,21 @@ func checkVolExists(ctx context.Context, rbdVol *rbdVolume, cr *util.Credentials
|
||||
kmsID = rbdVol.KMS.GetID()
|
||||
}
|
||||
imageUUID, err := volJournal.CheckReservation(ctx, rbdVol.Monitors, cr, rbdVol.Pool,
|
||||
rbdVol.RequestName, "", kmsID)
|
||||
rbdVol.RequestName, rbdVol.NamePrefix, "", kmsID)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if imageUUID == "" {
|
||||
return false, nil
|
||||
}
|
||||
rbdVol.RbdImageName = volJournal.NamingPrefix() + imageUUID
|
||||
|
||||
// now that we now that the reservation exists, let's get the image name from
|
||||
// the omap
|
||||
_, rbdVol.RbdImageName, _, _, err = volJournal.GetObjectUUIDData(ctx, rbdVol.Monitors, cr,
|
||||
rbdVol.Pool, imageUUID, false)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// NOTE: Return volsize should be on-disk volsize, not request vol size, so
|
||||
// save it for size checks before fetching image data
|
||||
@ -214,8 +228,13 @@ func checkVolExists(ctx context.Context, rbdVol *rbdVolume, cr *util.Credentials
|
||||
// reserveSnap is a helper routine to request a rbdSnapshot name reservation and generate the
|
||||
// volume ID for the generated name
|
||||
func reserveSnap(ctx context.Context, rbdSnap *rbdSnapshot, cr *util.Credentials) error {
|
||||
snapUUID, err := snapJournal.ReserveName(ctx, rbdSnap.Monitors, cr, rbdSnap.Pool,
|
||||
rbdSnap.RequestName, rbdSnap.RbdImageName, "")
|
||||
var (
|
||||
snapUUID string
|
||||
err error
|
||||
)
|
||||
|
||||
snapUUID, rbdSnap.RbdSnapName, err = snapJournal.ReserveName(ctx, rbdSnap.Monitors, cr, rbdSnap.Pool,
|
||||
rbdSnap.RequestName, rbdSnap.NamePrefix, rbdSnap.RbdImageName, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -226,10 +245,8 @@ func reserveSnap(ctx context.Context, rbdSnap *rbdSnapshot, cr *util.Credentials
|
||||
return err
|
||||
}
|
||||
|
||||
rbdSnap.RbdSnapName = snapJournal.NamingPrefix() + snapUUID
|
||||
|
||||
klog.V(4).Infof(util.Log(ctx, "generated Volume ID (%s) and image name (%s) for request name (%s)"),
|
||||
rbdSnap.SnapID, rbdSnap.RbdImageName, rbdSnap.RequestName)
|
||||
rbdSnap.SnapID, rbdSnap.RbdSnapName, rbdSnap.RequestName)
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -237,12 +254,18 @@ func reserveSnap(ctx context.Context, rbdSnap *rbdSnapshot, cr *util.Credentials
|
||||
// reserveVol is a helper routine to request a rbdVolume name reservation and generate the
|
||||
// volume ID for the generated name
|
||||
func reserveVol(ctx context.Context, rbdVol *rbdVolume, cr *util.Credentials) error {
|
||||
var (
|
||||
imageUUID string
|
||||
err error
|
||||
)
|
||||
|
||||
kmsID := ""
|
||||
if rbdVol.Encrypted {
|
||||
kmsID = rbdVol.KMS.GetID()
|
||||
}
|
||||
imageUUID, err := volJournal.ReserveName(ctx, rbdVol.Monitors, cr, rbdVol.Pool,
|
||||
rbdVol.RequestName, "", kmsID)
|
||||
|
||||
imageUUID, rbdVol.RbdImageName, err = volJournal.ReserveName(ctx, rbdVol.Monitors, cr, rbdVol.Pool,
|
||||
rbdVol.RequestName, rbdVol.NamePrefix, "", kmsID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -253,8 +276,6 @@ func reserveVol(ctx context.Context, rbdVol *rbdVolume, cr *util.Credentials) er
|
||||
return err
|
||||
}
|
||||
|
||||
rbdVol.RbdImageName = volJournal.NamingPrefix() + imageUUID
|
||||
|
||||
klog.V(4).Infof(util.Log(ctx, "generated Volume ID (%s) and image name (%s) for request name (%s)"),
|
||||
rbdVol.VolID, rbdVol.RbdImageName, rbdVol.RequestName)
|
||||
|
||||
|
@ -70,6 +70,7 @@ type rbdVolume struct {
|
||||
// VolName and MonValueFromSecret are retained from older plugin versions (<= 1.0.0)
|
||||
// for backward compatibility reasons
|
||||
RbdImageName string
|
||||
NamePrefix string
|
||||
VolID string `json:"volID"`
|
||||
Monitors string `json:"monitors"`
|
||||
Pool string `json:"pool"`
|
||||
@ -98,6 +99,7 @@ type rbdSnapshot struct {
|
||||
// RequestName is the CSI generated snapshot name for the rbdSnapshot
|
||||
SourceVolumeID string
|
||||
RbdImageName string
|
||||
NamePrefix string
|
||||
RbdSnapName string
|
||||
SnapID string
|
||||
Monitors string
|
||||
@ -295,7 +297,6 @@ func genSnapFromSnapID(ctx context.Context, rbdSnap *rbdSnapshot, snapshotID str
|
||||
|
||||
rbdSnap.ClusterID = vi.ClusterID
|
||||
options["clusterID"] = rbdSnap.ClusterID
|
||||
rbdSnap.RbdSnapName = snapJournal.NamingPrefix() + vi.ObjectUUID
|
||||
|
||||
rbdSnap.Monitors, _, err = getMonsAndClusterID(ctx, options)
|
||||
if err != nil {
|
||||
@ -307,7 +308,7 @@ func genSnapFromSnapID(ctx context.Context, rbdSnap *rbdSnapshot, snapshotID str
|
||||
return err
|
||||
}
|
||||
|
||||
rbdSnap.RequestName, rbdSnap.RbdImageName, _, err = snapJournal.GetObjectUUIDData(ctx, rbdSnap.Monitors,
|
||||
rbdSnap.RequestName, rbdSnap.RbdSnapName, rbdSnap.RbdImageName, _, err = snapJournal.GetObjectUUIDData(ctx, rbdSnap.Monitors,
|
||||
cr, rbdSnap.Pool, vi.ObjectUUID, true)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -339,7 +340,6 @@ func genVolFromVolID(ctx context.Context, rbdVol *rbdVolume, volumeID string, cr
|
||||
|
||||
rbdVol.ClusterID = vi.ClusterID
|
||||
options["clusterID"] = rbdVol.ClusterID
|
||||
rbdVol.RbdImageName = volJournal.NamingPrefix() + vi.ObjectUUID
|
||||
|
||||
rbdVol.Monitors, _, err = getMonsAndClusterID(ctx, options)
|
||||
if err != nil {
|
||||
@ -352,8 +352,8 @@ func genVolFromVolID(ctx context.Context, rbdVol *rbdVolume, volumeID string, cr
|
||||
}
|
||||
|
||||
kmsID := ""
|
||||
rbdVol.RequestName, _, kmsID, err = volJournal.GetObjectUUIDData(
|
||||
ctx, rbdVol.Monitors, cr, rbdVol.Pool, vi.ObjectUUID, false)
|
||||
rbdVol.RequestName, rbdVol.RbdImageName, _, kmsID, err = volJournal.GetObjectUUIDData(ctx, rbdVol.Monitors, cr,
|
||||
rbdVol.Pool, vi.ObjectUUID, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -454,9 +454,10 @@ func updateMons(rbdVol *rbdVolume, options, credentials map[string]string) error
|
||||
|
||||
func genVolFromVolumeOptions(ctx context.Context, volOptions, credentials map[string]string, disableInUseChecks, isLegacyVolume bool) (*rbdVolume, error) {
|
||||
var (
|
||||
ok bool
|
||||
err error
|
||||
encrypted string
|
||||
ok bool
|
||||
err error
|
||||
namePrefix string
|
||||
encrypted string
|
||||
)
|
||||
|
||||
rbdVol := &rbdVolume{}
|
||||
@ -466,6 +467,9 @@ func genVolFromVolumeOptions(ctx context.Context, volOptions, credentials map[st
|
||||
}
|
||||
|
||||
rbdVol.DataPool = volOptions["dataPool"]
|
||||
if namePrefix, ok = volOptions["volumeNamePrefix"]; ok {
|
||||
rbdVol.NamePrefix = namePrefix
|
||||
}
|
||||
|
||||
if isLegacyVolume {
|
||||
err = updateMons(rbdVol, volOptions, credentials)
|
||||
@ -537,6 +541,10 @@ func genSnapFromOptions(ctx context.Context, rbdVol *rbdVolume, snapOptions map[
|
||||
rbdSnap.ClusterID = rbdVol.ClusterID
|
||||
}
|
||||
|
||||
if namePrefix, ok := snapOptions["snapshotNamePrefix"]; ok {
|
||||
rbdSnap.NamePrefix = namePrefix
|
||||
}
|
||||
|
||||
return rbdSnap
|
||||
}
|
||||
|
||||
@ -870,23 +878,16 @@ func resizeRBDImage(rbdVol *rbdVolume, newSize int64, cr *util.Credentials) erro
|
||||
return nil
|
||||
}
|
||||
|
||||
func getVolumeName(volID string) (string, error) {
|
||||
func ensureEncryptionMetadataSet(ctx context.Context, cr *util.Credentials, rbdVol *rbdVolume) error {
|
||||
var vi util.CSIIdentifier
|
||||
|
||||
err := vi.DecomposeCSIID(volID)
|
||||
err := vi.DecomposeCSIID(rbdVol.VolID)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error decoding volume ID (%s) (%s)", err, volID)
|
||||
return "", ErrInvalidVolID{err}
|
||||
err = fmt.Errorf("error decoding volume ID (%s) (%s)", rbdVol.VolID, err)
|
||||
return ErrInvalidVolID{err}
|
||||
}
|
||||
|
||||
return volJournal.NamingPrefix() + vi.ObjectUUID, nil
|
||||
}
|
||||
|
||||
func ensureEncryptionMetadataSet(ctx context.Context, cr *util.Credentials, rbdVol *rbdVolume) error {
|
||||
rbdImageName, err := getVolumeName(rbdVol.VolID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rbdImageName := volJournal.GetNameForUUID(rbdVol.NamePrefix, vi.ObjectUUID, false)
|
||||
imageSpec := rbdVol.Pool + "/" + rbdImageName
|
||||
|
||||
err = util.SaveRbdImageEncryptionStatus(ctx, cr, rbdVol.Monitors, imageSpec, rbdImageRequiresEncryption)
|
||||
|
56
pkg/rbd/rbd_util_test.go
Normal file
56
pkg/rbd/rbd_util_test.go
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
Copyright 2020 The Ceph-CSI 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 rbd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIsLegacyVolumeID(t *testing.T) {
|
||||
tests := []struct {
|
||||
volID string
|
||||
isLegacy bool
|
||||
}{
|
||||
{"prefix-bda37d42-9979-420f-9389-74362f3f98f6", false},
|
||||
{"csi-rbd-vo-f997e783-ff00-48b0-8cc7-30cb36c3df3d", false},
|
||||
{"csi-rbd-vol-this-is-clearly-not-a-valid-UUID----", false},
|
||||
{"csi-rbd-vol-b82f27de-3b3a-43f2-b5e7-9f8d0aad04e9", true},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
if got := isLegacyVolumeID(test.volID); got != test.isLegacy {
|
||||
t.Errorf("isLegacyVolumeID(%s) = %t, want %t", test.volID, got, test.isLegacy)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasSnapshotFeature(t *testing.T) {
|
||||
tests := []struct {
|
||||
features string
|
||||
hasFeature bool
|
||||
}{
|
||||
{"foo", false},
|
||||
{"foo,bar", false},
|
||||
{"foo,layering,bar", true},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
if got := hasSnapshotFeature(test.features); got != test.hasFeature {
|
||||
t.Errorf("hasSnapshotFeature(%s) = %t, want %t", test.features, got, test.hasFeature)
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user