Skip to content

Commit

Permalink
rbd: add support for block-devices in NodeGetVolumeStats()
Browse files Browse the repository at this point in the history
The NodeGetVolumeStats procedure can now be used to fetch the capacity
of the RBD block-device. By default this is a thin-provisioned device,
which means that the capacity is not reserved in the Ceph cluster. This
makes it possible to over-provision the cluster.

In order to detect the amount of storage used by the RBD block-device
(when thin-provisioned), it is required to connect to the Ceph cluster.
Unfortunately, the NodeGetVolumeStats CSI procedure does not provide
enough parameters to connect to the Ceph cluster and fetch more details
about the RBD image.

Signed-off-by: Niels de Vos <ndevos@redhat.com>
  • Loading branch information
nixpanic committed Jan 25, 2021
1 parent 94e025c commit 7a7a6ff
Showing 1 changed file with 37 additions and 1 deletion.
38 changes: 37 additions & 1 deletion internal/csi-common/nodeserver-default.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ package csicommon
import (
"fmt"
"os"
"strconv"
"strings"

"github.com/ceph/ceph-csi/internal/util"

Expand Down Expand Up @@ -119,9 +121,43 @@ func (ns *DefaultNodeServer) NodeGetVolumeStats(ctx context.Context, req *csi.No

if stat.Mode().IsDir() {
return filesystemNodeGetVolumeStats(ctx, targetPath)
} else if (stat.Mode() & os.ModeDevice) == os.ModeDevice {
return blockNodeGetVolumeStats(ctx, targetPath)
}

return nil, fmt.Errorf("targetpath %q is not a directory", targetPath)
return nil, fmt.Errorf("targetpath %q is not a directory or device", targetPath)
}

// blockNodeGetVolumeStats gets the metrics for a `volumeMode: Block` type of
// volume. At the moment, only the size of the block-device can be returned, as
// there are no secrets in the NodeGetVolumeStats request that enables us to
// connect to the Ceph cluster.
//
// TODO: https://github.com/container-storage-interface/spec/issues/371#issuecomment-756834471
func blockNodeGetVolumeStats(ctx context.Context, targetPath string) (*csi.NodeGetVolumeStatsResponse, error) {
args := []string{"--noheadings", "--bytes", "--output=SIZE", targetPath}
lsblkSize, _, err := util.ExecCommand(ctx, "/bin/lsblk", args...)
if err != nil {
err = fmt.Errorf("lsblk %v returned an error: %w", args, err)
util.ErrorLog(ctx, err.Error())
return nil, status.Error(codes.Internal, err.Error())
}

size, err := strconv.ParseInt(strings.TrimSpace(lsblkSize), 10, 64)
if err != nil {
err = fmt.Errorf("failed to convert %q to bytes: %w", lsblkSize, err)
util.ErrorLog(ctx, err.Error())
return nil, status.Error(codes.Internal, err.Error())
}

return &csi.NodeGetVolumeStatsResponse{
Usage: []*csi.VolumeUsage{
{
Total: size,
Unit: csi.VolumeUsage_BYTES,
},
},
}, nil
}

func filesystemNodeGetVolumeStats(ctx context.Context, targetPath string) (*csi.NodeGetVolumeStatsResponse, error) {
Expand Down

0 comments on commit 7a7a6ff

Please sign in to comment.