mirror of
https://github.com/ceph/ceph-csi.git
synced 2024-11-22 22:30:23 +00:00
created struct for keeping the state of a staging transaction
this way extending transaction rollbacks is easier Signed-off-by: Reinier Schoof <reinier@skoef.nl>
This commit is contained in:
parent
9d7b50dccb
commit
3af5e0619f
@ -45,6 +45,18 @@ type NodeServer struct {
|
|||||||
VolumeLocks *util.VolumeLocks
|
VolumeLocks *util.VolumeLocks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// stageTransaction struct represents the state a transaction was when it either completed
|
||||||
|
// or failed
|
||||||
|
// this transaction state can be used to rollback the transaction
|
||||||
|
type stageTransaction struct {
|
||||||
|
// isStagePathCreated represents whether the mount path to stage the volume on was created or not
|
||||||
|
isStagePathCreated bool
|
||||||
|
// isMounted represents if the volume was mounted or not
|
||||||
|
isMounted bool
|
||||||
|
// isEncrypted represents if the volume was encrypted or not
|
||||||
|
isEncrypted bool
|
||||||
|
}
|
||||||
|
|
||||||
// NodeStageVolume mounts the volume to a staging path on the node.
|
// NodeStageVolume mounts the volume to a staging path on the node.
|
||||||
// Implementation notes:
|
// Implementation notes:
|
||||||
// - stagingTargetPath is the directory passed in the request where the volume needs to be staged
|
// - stagingTargetPath is the directory passed in the request where the volume needs to be staged
|
||||||
@ -143,10 +155,7 @@ func (ns *NodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVol
|
|||||||
}
|
}
|
||||||
|
|
||||||
volOptions.VolID = volID
|
volOptions.VolID = volID
|
||||||
|
transaction := stageTransaction{}
|
||||||
isMounted := false
|
|
||||||
isEncrypted := false
|
|
||||||
isStagePathCreated := false
|
|
||||||
devicePath := ""
|
devicePath := ""
|
||||||
|
|
||||||
// Stash image details prior to mapping the image (useful during Unstage as it has no
|
// Stash image details prior to mapping the image (useful during Unstage as it has no
|
||||||
@ -157,13 +166,13 @@ func (ns *NodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVol
|
|||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ns.undoStagingTransaction(ctx, req, devicePath, isStagePathCreated, isMounted, isEncrypted)
|
ns.undoStagingTransaction(ctx, req, devicePath, transaction)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// perform the actual staging and if this fails, have undoStagingTransaction
|
// perform the actual staging and if this fails, have undoStagingTransaction
|
||||||
// cleans up for us
|
// cleans up for us
|
||||||
isStagePathCreated, isMounted, isEncrypted, err = ns.stageTransaction(ctx, req, volOptions, staticVol)
|
transaction, err = ns.stageTransaction(ctx, req, volOptions, staticVol)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.Error(codes.Internal, err.Error())
|
return nil, status.Error(codes.Internal, err.Error())
|
||||||
}
|
}
|
||||||
@ -173,17 +182,15 @@ func (ns *NodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVol
|
|||||||
return &csi.NodeStageVolumeResponse{}, nil
|
return &csi.NodeStageVolumeResponse{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *NodeServer) stageTransaction(ctx context.Context, req *csi.NodeStageVolumeRequest, volOptions *rbdVolume, staticVol bool) (bool, bool, bool, error) {
|
func (ns *NodeServer) stageTransaction(ctx context.Context, req *csi.NodeStageVolumeRequest, volOptions *rbdVolume, staticVol bool) (stageTransaction, error) {
|
||||||
isStagePathCreated := false
|
transaction := stageTransaction{}
|
||||||
isMounted := false
|
|
||||||
isEncrypted := false
|
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
var cr *util.Credentials
|
var cr *util.Credentials
|
||||||
cr, err = util.NewUserCredentials(req.GetSecrets())
|
cr, err = util.NewUserCredentials(req.GetSecrets())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return isStagePathCreated, isMounted, isEncrypted, err
|
return transaction, err
|
||||||
}
|
}
|
||||||
defer cr.DeleteCredentials()
|
defer cr.DeleteCredentials()
|
||||||
|
|
||||||
@ -191,7 +198,7 @@ func (ns *NodeServer) stageTransaction(ctx context.Context, req *csi.NodeStageVo
|
|||||||
var devicePath string
|
var devicePath string
|
||||||
devicePath, err = attachRBDImage(ctx, volOptions, cr)
|
devicePath, err = attachRBDImage(ctx, volOptions, cr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return isStagePathCreated, isMounted, isEncrypted, err
|
return transaction, err
|
||||||
}
|
}
|
||||||
|
|
||||||
klog.V(4).Infof(util.Log(ctx, "rbd image: %s/%s was successfully mapped at %s\n"),
|
klog.V(4).Infof(util.Log(ctx, "rbd image: %s/%s was successfully mapped at %s\n"),
|
||||||
@ -200,9 +207,9 @@ func (ns *NodeServer) stageTransaction(ctx context.Context, req *csi.NodeStageVo
|
|||||||
if volOptions.Encrypted {
|
if volOptions.Encrypted {
|
||||||
devicePath, err = ns.processEncryptedDevice(ctx, volOptions, devicePath, cr)
|
devicePath, err = ns.processEncryptedDevice(ctx, volOptions, devicePath, cr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return isStagePathCreated, isMounted, isEncrypted, err
|
return transaction, err
|
||||||
}
|
}
|
||||||
isEncrypted = true
|
transaction.isEncrypted = true
|
||||||
}
|
}
|
||||||
|
|
||||||
stagingTargetPath := getStagingTargetPath(req)
|
stagingTargetPath := getStagingTargetPath(req)
|
||||||
@ -210,29 +217,29 @@ func (ns *NodeServer) stageTransaction(ctx context.Context, req *csi.NodeStageVo
|
|||||||
isBlock := req.GetVolumeCapability().GetBlock() != nil
|
isBlock := req.GetVolumeCapability().GetBlock() != nil
|
||||||
err = ns.createStageMountPoint(ctx, stagingTargetPath, isBlock)
|
err = ns.createStageMountPoint(ctx, stagingTargetPath, isBlock)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return isStagePathCreated, isMounted, isEncrypted, err
|
return transaction, err
|
||||||
}
|
}
|
||||||
|
|
||||||
isStagePathCreated = true
|
transaction.isStagePathCreated = true
|
||||||
|
|
||||||
// nodeStage Path
|
// nodeStage Path
|
||||||
err = ns.mountVolumeToStagePath(ctx, req, staticVol, stagingTargetPath, devicePath)
|
err = ns.mountVolumeToStagePath(ctx, req, staticVol, stagingTargetPath, devicePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return isStagePathCreated, isMounted, isEncrypted, err
|
return transaction, err
|
||||||
}
|
}
|
||||||
isMounted = true
|
transaction.isMounted = true
|
||||||
|
|
||||||
// #nosec - allow anyone to write inside the target path
|
// #nosec - allow anyone to write inside the target path
|
||||||
err = os.Chmod(stagingTargetPath, 0777)
|
err = os.Chmod(stagingTargetPath, 0777)
|
||||||
|
|
||||||
return isStagePathCreated, isMounted, isEncrypted, err
|
return transaction, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *NodeServer) undoStagingTransaction(ctx context.Context, req *csi.NodeStageVolumeRequest, devicePath string, isStagePathCreated, isMounted, isEncrypted bool) {
|
func (ns *NodeServer) undoStagingTransaction(ctx context.Context, req *csi.NodeStageVolumeRequest, devicePath string, transaction stageTransaction) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
stagingTargetPath := getStagingTargetPath(req)
|
stagingTargetPath := getStagingTargetPath(req)
|
||||||
if isMounted {
|
if transaction.isMounted {
|
||||||
err = ns.mounter.Unmount(stagingTargetPath)
|
err = ns.mounter.Unmount(stagingTargetPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf(util.Log(ctx, "failed to unmount stagingtargetPath: %s with error: %v"), stagingTargetPath, err)
|
klog.Errorf(util.Log(ctx, "failed to unmount stagingtargetPath: %s with error: %v"), stagingTargetPath, err)
|
||||||
@ -241,7 +248,7 @@ func (ns *NodeServer) undoStagingTransaction(ctx context.Context, req *csi.NodeS
|
|||||||
}
|
}
|
||||||
|
|
||||||
// remove the file/directory created on staging path
|
// remove the file/directory created on staging path
|
||||||
if isStagePathCreated {
|
if transaction.isStagePathCreated {
|
||||||
err = os.Remove(stagingTargetPath)
|
err = os.Remove(stagingTargetPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf(util.Log(ctx, "failed to remove stagingtargetPath: %s with error: %v"), stagingTargetPath, err)
|
klog.Errorf(util.Log(ctx, "failed to remove stagingtargetPath: %s with error: %v"), stagingTargetPath, err)
|
||||||
@ -253,7 +260,7 @@ func (ns *NodeServer) undoStagingTransaction(ctx context.Context, req *csi.NodeS
|
|||||||
|
|
||||||
// Unmapping rbd device
|
// Unmapping rbd device
|
||||||
if devicePath != "" {
|
if devicePath != "" {
|
||||||
err = detachRBDDevice(ctx, devicePath, volID, isEncrypted)
|
err = detachRBDDevice(ctx, devicePath, volID, transaction.isEncrypted)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf(util.Log(ctx, "failed to unmap rbd device: %s for volume %s with error: %v"), devicePath, volID, err)
|
klog.Errorf(util.Log(ctx, "failed to unmap rbd device: %s for volume %s with error: %v"), devicePath, volID, err)
|
||||||
// continue on failure to delete the stash file, as kubernetes will fail to delete the staging path otherwise
|
// continue on failure to delete the stash file, as kubernetes will fail to delete the staging path otherwise
|
||||||
|
Loading…
Reference in New Issue
Block a user