rbd: make image features as optional parameter

Makes the rbd images features in the storageclass
as optional so that default image features of librbd
can be used. and also kept the option to user
to specify the image features in the storageclass.

Signed-off-by: Madhu Rajanna <madhupr007@gmail.com>
This commit is contained in:
Madhu Rajanna 2022-02-17 11:54:47 +05:30 committed by mergify[bot]
parent fb3835691f
commit d5c98f81a2
9 changed files with 127 additions and 26 deletions

View File

@ -279,7 +279,7 @@ storageClass:
# eg: pool: replicapool # eg: pool: replicapool
pool: replicapool pool: replicapool
# (required) RBD image features, CSI creates image with image-format 2 CSI # (optional) RBD image features, CSI creates image with image-format 2 CSI
# RBD currently supports `layering`, `journaling`, `exclusive-lock`, # RBD currently supports `layering`, `journaling`, `exclusive-lock`,
# `object-map`, `fast-diff`, `deep-flatten` features. If `journaling` is # `object-map`, `fast-diff`, `deep-flatten` features. If `journaling` is
# enabled, must enable `exclusive-lock` too. # enabled, must enable `exclusive-lock` too.

View File

@ -56,7 +56,7 @@ make image-cephcsi
| `dataPool` | no | Ceph pool used for the data of the RBD images. | | `dataPool` | no | Ceph pool used for the data of the RBD images. |
| `volumeNamePrefix` | no | Prefix to use for naming RBD images (defaults to `csi-vol-`). | | `volumeNamePrefix` | no | Prefix to use for naming RBD images (defaults to `csi-vol-`). |
| `snapshotNamePrefix` | no | Prefix to use for naming RBD snapshot images (defaults to `csi-snap-`). | | `snapshotNamePrefix` | no | Prefix to use for naming RBD snapshot images (defaults to `csi-snap-`). |
| `imageFeatures` | yes | RBD image features. CSI RBD currently supports `layering`, `journaling`, `exclusive-lock`, `object-map`, `fast-diff`, `deep-flatten` features. If `journaling` is enabled, must enable `exclusive-lock` too. See [man pages](http://docs.ceph.com/docs/master/man/8/rbd/#cmdoption-rbd-image-feature) Note that the required support for [object-map and fast-diff were added in 5.3, deep-flatten was added in 5.1 and journaling does not have KRBD support yet](https://docs.ceph.com/en/latest/rbd/rbd-config-ref/#image-features). deep-flatten is added for cloned images. | | `imageFeatures` | no | RBD image features. CSI RBD currently supports `layering`, `journaling`, `exclusive-lock`, `object-map`, `fast-diff`, `deep-flatten` features. If `journaling` is enabled, must enable `exclusive-lock` too. See [man pages](http://docs.ceph.com/docs/master/man/8/rbd/#cmdoption-rbd-image-feature) Note that the required support for [object-map and fast-diff were added in 5.3, deep-flatten was added in 5.1 and journaling does not have KRBD support yet](https://docs.ceph.com/en/latest/rbd/rbd-config-ref/#image-features). deep-flatten is added for cloned images. |
| `tryOtherMounters` | no | Specifies whether to try other mounters in case if the current mounter fails to mount the rbd image for any reason | | `tryOtherMounters` | no | Specifies whether to try other mounters in case if the current mounter fails to mount the rbd image for any reason |
| `mapOptions` | no | Map options to use when mapping rbd image. See [krbd](https://docs.ceph.com/docs/master/man/8/rbd/#kernel-rbd-krbd-options) and [nbd](https://docs.ceph.com/docs/master/man/8/rbd-nbd/#options) options. | | `mapOptions` | no | Map options to use when mapping rbd image. See [krbd](https://docs.ceph.com/docs/master/man/8/rbd/#kernel-rbd-krbd-options) and [nbd](https://docs.ceph.com/docs/master/man/8/rbd-nbd/#options) options. |
| `unmapOptions` | no | Unmap options to use when unmapping rbd image. See [krbd](https://docs.ceph.com/docs/master/man/8/rbd/#kernel-rbd-krbd-options) and [nbd](https://docs.ceph.com/docs/master/man/8/rbd-nbd/#options) options. | | `unmapOptions` | no | Unmap options to use when unmapping rbd image. See [krbd](https://docs.ceph.com/docs/master/man/8/rbd/#kernel-rbd-krbd-options) and [nbd](https://docs.ceph.com/docs/master/man/8/rbd-nbd/#options) options. |

View File

@ -852,6 +852,65 @@ var _ = Describe("RBD", func() {
validateRBDImageCount(f, 0, defaultRBDPool) validateRBDImageCount(f, 0, defaultRBDPool)
}) })
By("create PVC with layering,deep-flatten image-features and bind it to an app",
func() {
err := deleteResource(rbdExamplePath + "storageclass.yaml")
if err != nil {
e2elog.Failf("failed to delete storageclass: %v", err)
}
err = createRBDStorageClass(
f.ClientSet,
f,
defaultSCName,
nil,
map[string]string{
"imageFeatures": "",
},
deletePolicy)
if err != nil {
e2elog.Failf("failed to create storageclass: %v", err)
}
// set up PVC
pvc, err := loadPVC(pvcPath)
if err != nil {
e2elog.Failf("failed to load PVC: %v", err)
}
pvc.Namespace = f.UniqueName
err = createPVCAndvalidatePV(f.ClientSet, pvc, deployTimeout)
if err != nil {
e2elog.Failf("failed to create PVC: %v", err)
}
// validate created backend rbd images
validateRBDImageCount(f, 1, defaultRBDPool)
// checking the minimal kernel version for fast-diff as its
// higher kernel version than other default image features.
if util.CheckKernelSupport(kernelRelease, fastDiffSupport) {
app, aErr := loadApp(appPath)
if aErr != nil {
e2elog.Failf("failed to load application: %v", aErr)
}
app.Namespace = f.UniqueName
err = createApp(f.ClientSet, app, deployTimeout)
if err != nil {
e2elog.Failf("failed to create application: %v", err)
}
// delete pod as we should not create snapshot for in-use pvc
err = deletePod(app.Name, app.Namespace, f.ClientSet, deployTimeout)
if err != nil {
e2elog.Failf("failed to delete application: %v", err)
}
}
// clean up after ourselves
err = deletePVCAndValidatePV(f.ClientSet, pvc, deployTimeout)
if err != nil {
e2elog.Failf("failed to delete PVC: %v", err)
}
// validate created backend rbd images
validateRBDImageCount(f, 0, defaultRBDPool)
})
By("create PVC with journaling,fast-diff image-features and bind it to an app using rbd-nbd mounter", By("create PVC with journaling,fast-diff image-features and bind it to an app using rbd-nbd mounter",
func() { func() {
if util.CheckKernelSupport(kernelRelease, fastDiffSupport) { if util.CheckKernelSupport(kernelRelease, fastDiffSupport) {

View File

@ -149,6 +149,10 @@ func createRBDStorageClass(
sc.Parameters["clusterID"] = fsID sc.Parameters["clusterID"] = fsID
for k, v := range parameters { for k, v := range parameters {
sc.Parameters[k] = v sc.Parameters[k] = v
// if any values are empty remove it from the map
if v == "" {
delete(sc.Parameters, k)
}
} }
sc.Namespace = cephCSINamespace sc.Namespace = cephCSINamespace

View File

@ -29,7 +29,7 @@ parameters:
# eg: pool: rbdpool # eg: pool: rbdpool
pool: <rbd-pool-name> pool: <rbd-pool-name>
# (required) RBD image features, CSI creates image with image-format 2 CSI # (optional) RBD image features, CSI creates image with image-format 2 CSI
# RBD currently supports `layering`, `journaling`, `exclusive-lock`, # RBD currently supports `layering`, `journaling`, `exclusive-lock`,
# `object-map`, `fast-diff`, `deep-flatten` features. If `journaling` is # `object-map`, `fast-diff`, `deep-flatten` features. If `journaling` is
# enabled, must enable `exclusive-lock` too. # enabled, must enable `exclusive-lock` too.

View File

@ -115,8 +115,8 @@ func (cs *ControllerServer) parseVolCreateRequest(
"multi node access modes are only supported on rbd `block` type volumes") "multi node access modes are only supported on rbd `block` type volumes")
} }
if imageFeatures, ok := req.GetParameters()["imageFeatures"]; checkImageFeatures(imageFeatures, ok, true) { if imageFeatures, ok := req.GetParameters()["imageFeatures"]; !checkValidImageFeatures(imageFeatures, ok) {
return nil, status.Error(codes.InvalidArgument, "missing required parameter imageFeatures") return nil, status.Error(codes.InvalidArgument, "empty imageFeatures parameter")
} }
// if it's NOT SINGLE_NODE_WRITER, and it's BLOCK we'll set the parameter to ignore the in-use checks // if it's NOT SINGLE_NODE_WRITER, and it's BLOCK we'll set the parameter to ignore the in-use checks

View File

@ -215,12 +215,33 @@ func populateRbdVol(
rv.RbdImageName = imageAttributes.ImageName rv.RbdImageName = imageAttributes.ImageName
} }
err = rv.Connect(cr)
if err != nil {
log.ErrorLog(ctx, "failed to connect to volume %s: %v", rv, err)
return nil, status.Error(codes.Internal, err.Error())
}
// in case of any error call Destroy for cleanup.
defer func() {
if err != nil {
rv.Destroy()
}
}()
// get the image details from the ceph cluster.
err = rv.getImageInfo()
if err != nil {
log.ErrorLog(ctx, "failed to get image details %s: %v", rv, err)
return nil, status.Error(codes.Internal, err.Error())
}
if req.GetVolumeContext()["mounter"] == rbdDefaultMounter && if req.GetVolumeContext()["mounter"] == rbdDefaultMounter &&
!isKrbdFeatureSupported(ctx, req.GetVolumeContext()["imageFeatures"]) { !isKrbdFeatureSupported(ctx, strings.Join(rv.ImageFeatureSet.Names(), ",")) {
if !parseBoolOption(ctx, req.GetVolumeContext(), tryOtherMounters, false) { if !parseBoolOption(ctx, req.GetVolumeContext(), tryOtherMounters, false) {
log.ErrorLog(ctx, "unsupported krbd Feature, set `tryOtherMounters:true` or fix krbd driver") log.ErrorLog(ctx, "unsupported krbd Feature, set `tryOtherMounters:true` or fix krbd driver")
err = errors.New("unsupported krbd Feature")
return nil, status.Errorf(codes.Internal, "unsupported krbd Feature") return nil, status.Error(codes.Internal, err.Error())
} }
// fallback to rbd-nbd, // fallback to rbd-nbd,
rv.Mounter = rbdNbdMounter rv.Mounter = rbdNbdMounter
@ -299,24 +320,10 @@ func (ns *NodeServer) NodeStageVolume(
} }
isStaticVol := parseBoolOption(ctx, req.GetVolumeContext(), staticVol, false) isStaticVol := parseBoolOption(ctx, req.GetVolumeContext(), staticVol, false)
// throw error when imageFeatures parameter is missing or empty
// for backward compatibility, ignore error for non-static volumes from older cephcsi version
if imageFeatures, ok := req.GetVolumeContext()["imageFeatures"]; checkImageFeatures(imageFeatures, ok, isStaticVol) {
return nil, status.Error(codes.InvalidArgument, "missing required parameter imageFeatures")
}
rv, err := populateRbdVol(ctx, req, cr, req.GetSecrets()) rv, err := populateRbdVol(ctx, req, cr, req.GetSecrets())
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = rv.Connect(cr)
if err != nil {
log.ErrorLog(ctx, "failed to connect to volume %s: %v", rv, err)
return nil, status.Error(codes.Internal, err.Error())
}
defer rv.Destroy() defer rv.Destroy()
if isHealer { if isHealer {

View File

@ -471,11 +471,10 @@ func (ri *rbdImage) isInUse() (bool, error) {
return len(watchers) > defaultWatchers, nil return len(watchers) > defaultWatchers, nil
} }
// checkImageFeatures check presence of imageFeatures parameter. It returns true when // checkValidImageFeatures check presence of imageFeatures parameter. It returns false when
// there imageFeatures is missing or empty, skips missing parameter for non-static volumes // there imageFeatures is present and empty.
// for backward compatibility. func checkValidImageFeatures(imageFeatures string, ok bool) bool {
func checkImageFeatures(imageFeatures string, ok, static bool) bool { return !(ok && imageFeatures == "")
return static && (!ok || imageFeatures == "")
} }
// isNotMountPoint checks whether MountPoint does not exists and // isNotMountPoint checks whether MountPoint does not exists and

View File

@ -354,3 +354,35 @@ func TestIsKrbdFeatureSupported(t *testing.T) {
}) })
} }
} }
func Test_checkValidImageFeatures(t *testing.T) {
t.Parallel()
tests := []struct {
name string
imageFeatures string
ok bool
want bool
}{
{
name: "test for valid image features",
imageFeatures: "layering,exclusive-lock,object-map,fast-diff,deep-flatten",
ok: true,
want: true,
},
{
name: "test for empty image features",
imageFeatures: "",
ok: true,
want: false,
},
}
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
if got := checkValidImageFeatures(tc.imageFeatures, tc.ok); got != tc.want {
t.Errorf("checkValidImageFeatures() = %v, want %v", got, tc.want)
}
})
}
}