rbd: parse migration secret and set it for controller server operations

This commit adds a couple of helper functions to parse the migration
request secret and set it for further csi driver operations.

More details:

The intree secret has a data field called "key" which is the base64
admin secret key. The ceph CSI driver currently expect the secret to
contain data field "UserKey" for the equivalant. The CSI driver also
expect the "UserID" field which is not available in the in-tree secret
by deafult. This missing userID will be filled (if the username differ
than 'admin') in the migration secret as 'adminId' field in the
migration request, this commit adds the logic to parse this migration
secret as below:

"key" field value will be picked up from the migraion secret to "UserKey"
field.
"adminId" field value will be picked up from the migration secret to "UserID"
field

if `adminId` field is nil or not set, `UserID` field will be filled with
default value ie `admin`.The above logic get activated only when the secret
is a migration secret, otherwise skipped to the normal workflow as we have
today.

Signed-off-by: Humble Chirammal <hchiramm@redhat.com>
This commit is contained in:
Humble Chirammal 2021-10-24 14:18:28 +05:30 committed by mergify[bot]
parent b132696e54
commit b49bf4b987
2 changed files with 51 additions and 8 deletions

View File

@ -808,25 +808,34 @@ func (cs *ControllerServer) checkErrAndUndoReserve(
func (cs *ControllerServer) DeleteVolume( func (cs *ControllerServer) DeleteVolume(
ctx context.Context, ctx context.Context,
req *csi.DeleteVolumeRequest) (*csi.DeleteVolumeResponse, error) { req *csi.DeleteVolumeRequest) (*csi.DeleteVolumeResponse, error) {
if err := cs.Driver.ValidateControllerServiceRequest( var err error
if err = cs.Driver.ValidateControllerServiceRequest(
csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME); err != nil { csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME); err != nil {
log.ErrorLog(ctx, "invalid delete volume req: %v", protosanitizer.StripSecrets(req)) log.ErrorLog(ctx, "invalid delete volume req: %v", protosanitizer.StripSecrets(req))
return nil, err return nil, err
} }
cr, err := util.NewUserCredentials(req.GetSecrets())
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
defer cr.DeleteCredentials()
// For now the image get unconditionally deleted, but here retention policy can be checked // For now the image get unconditionally deleted, but here retention policy can be checked
volumeID := req.GetVolumeId() volumeID := req.GetVolumeId()
if volumeID == "" { if volumeID == "" {
return nil, status.Error(codes.InvalidArgument, "empty volume ID in request") return nil, status.Error(codes.InvalidArgument, "empty volume ID in request")
} }
secrets := req.GetSecrets()
if util.IsMigrationSecret(secrets) {
secrets, err = util.ParseAndSetSecretMapFromMigSecret(secrets)
if err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}
}
cr, err := util.NewUserCredentials(secrets)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
defer cr.DeleteCredentials()
if acquired := cs.VolumeLocks.TryAcquire(volumeID); !acquired { if acquired := cs.VolumeLocks.TryAcquire(volumeID); !acquired {
log.ErrorLog(ctx, util.VolumeOperationAlreadyExistsFmt, volumeID) log.ErrorLog(ctx, util.VolumeOperationAlreadyExistsFmt, volumeID)
@ -852,7 +861,7 @@ func (cs *ControllerServer) DeleteVolume(
return &csi.DeleteVolumeResponse{}, nil return &csi.DeleteVolumeResponse{}, nil
} }
rbdVol, err := genVolFromVolID(ctx, volumeID, cr, req.GetSecrets()) rbdVol, err := genVolFromVolID(ctx, volumeID, cr, secrets)
defer rbdVol.Destroy() defer rbdVol.Destroy()
if err != nil { if err != nil {
return cs.checkErrAndUndoReserve(ctx, err, volumeID, rbdVol, cr) return cs.checkErrAndUndoReserve(ctx, err, volumeID, rbdVol, cr)

View File

@ -31,6 +31,9 @@ const (
credMonitors = "monitors" credMonitors = "monitors"
tmpKeyFileLocation = "/tmp/csi/keys" tmpKeyFileLocation = "/tmp/csi/keys"
tmpKeyFileNamePrefix = "keyfile-" tmpKeyFileNamePrefix = "keyfile-"
migUserName = "admin"
migUserID = "adminId"
migUserKey = "key"
) )
// Credentials struct represents credentials to access the ceph cluster. // Credentials struct represents credentials to access the ceph cluster.
@ -119,3 +122,34 @@ func GetMonValFromSecret(secrets map[string]string) (string, error) {
return "", fmt.Errorf("missing %q", credMonitors) return "", fmt.Errorf("missing %q", credMonitors)
} }
// ParseAndSetSecretMapFromMigSecret parse the secretmap from the migration request and return
// newsecretmap with the userID and userKey fields set.
func ParseAndSetSecretMapFromMigSecret(secretmap map[string]string) (map[string]string, error) {
newSecretMap := make(map[string]string)
// parse and set userKey
if !IsMigrationSecret(secretmap) {
return nil, errors.New("passed secret map does not contain user key or it is nil")
}
newSecretMap[credUserKey] = secretmap[migUserKey]
// parse and set the userID
newSecretMap[credUserID] = migUserName
if secretmap[migUserID] != "" {
newSecretMap[credUserID] = secretmap[migUserID]
}
return newSecretMap, nil
}
// IsMigrationSecret validates if the passed in secretmap is a secret
// of a migration volume request. The migration secret carry a field
// called `key` which is the equivalent of `userKey` which is what we
// check here for identifying the secret.
func IsMigrationSecret(passedSecretMap map[string]string) bool {
// the below 'nil' check is an extra measure as the request validators like
// ValidateNodeStageVolumeRequest() already does the nil check, however considering
// this function can be called independently with a map of secret values
// it is good to have this check in place, also it gives clear error about this
// was hit on migration request compared to general one.
return len(passedSecretMap) != 0 && passedSecretMap[migUserKey] != ""
}