From 20d336fca3d380137940edd4bb2e73c9dc459209 Mon Sep 17 00:00:00 2001 From: ShyamsundarR Date: Tue, 6 Aug 2019 12:59:40 -0400 Subject: [PATCH] Add support to use ceph manager rbd command to delete an image Image deletion takes time proportional to the size of the image. Hence, ceph manager is enhanced to support async deletion of an image, or rather passing the task of deleting an image to the ceph manager. This commit leverages the ceph manager enhancement in the CSI code. NOTE: This is tested against a ceph cluster that is running Ceph master version of the code. Once other releases catch up in terms of the feature, the optimization would be available to the CSI driver as well. Fixes: #523 Signed-off-by: ShyamsundarR --- pkg/rbd/rbd_util.go | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/pkg/rbd/rbd_util.go b/pkg/rbd/rbd_util.go index 7112ba45c..94d9569d5 100644 --- a/pkg/rbd/rbd_util.go +++ b/pkg/rbd/rbd_util.go @@ -45,6 +45,12 @@ const ( rbdImageWatcherFactor = 1.4 rbdImageWatcherSteps = 10 rbdDefaultMounter = "rbd" + + // Output strings returned during invocation of "ceph rbd task add remove " when + // command is not supported by ceph manager. Used to check errors and recover when the command + // is unsupported. + rbdTaskRemoveCmdInvalidString1 = "no valid command found" + rbdTaskRemoveCmdInvalidString2 = "Error EINVAL: invalid command" ) // rbdVolume represents a CSI volume and its RBD image specifics @@ -166,6 +172,31 @@ func rbdStatus(pOpts *rbdVolume, cr *util.Credentials) (bool, string, error) { return false, output, nil } +// rbdManagerTaskDelete adds a ceph manager task to delete an rbd image, thus deleting +// it asynchronously. If command is not found returns a bool set to false +func rbdManagerTaskDeleteImage(pOpts *rbdVolume, cr *util.Credentials) (bool, error) { + var output []byte + + args := []string{"rbd", "task", "add", "remove", + pOpts.Pool + "/" + pOpts.RbdImageName, + "--id", cr.ID, + "--keyfile=" + cr.KeyFile, + "-m", pOpts.Monitors, + } + + output, err := execCommand("ceph", args) + if err != nil { + if strings.Contains(string(output), rbdTaskRemoveCmdInvalidString1) && + strings.Contains(string(output), rbdTaskRemoveCmdInvalidString2) { + klog.Infof("cluster with cluster ID (%s) does not support Ceph manager based rbd image"+ + " deletion (minimum ceph version required is v14.2.3)", pOpts.ClusterID) + return false, err + } + } + + return true, err +} + // deleteImage deletes a ceph image with provision and volume options. func deleteImage(pOpts *rbdVolume, cr *util.Credentials) error { var output []byte @@ -181,9 +212,16 @@ func deleteImage(pOpts *rbdVolume, cr *util.Credentials) error { } klog.V(4).Infof("rbd: rm %s using mon %s, pool %s", image, pOpts.Monitors, pOpts.Pool) - args := []string{"rm", image, "--pool", pOpts.Pool, "--id", cr.ID, "-m", pOpts.Monitors, - "--keyfile=" + cr.KeyFile} - output, err = execCommand("rbd", args) + + // attempt to use Ceph manager based deletion support if available + rbdCephMgrSupported, err := rbdManagerTaskDeleteImage(pOpts, cr) + if !rbdCephMgrSupported { + // attempt older style deletion + args := []string{"rm", image, "--pool", pOpts.Pool, "--id", cr.ID, "-m", pOpts.Monitors, + "--keyfile=" + cr.KeyFile} + output, err = execCommand("rbd", args) + } + if err != nil { klog.Errorf("failed to delete rbd image: %v, command output: %s", err, string(output)) }