Skip to content

Commit

Permalink
Merge pull request #10 from aokumasan/feature/volume_stats
Browse files Browse the repository at this point in the history
Implement NodeGetVolumeStats method in node driver
  • Loading branch information
aokumasan authored Aug 6, 2023
2 parents 7a8506a + db17f57 commit 3ca7e98
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 2 deletions.
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/kubernetes-sigs/gcp-compute-persistent-disk-csi-driver v0.6.0
github.com/nifcloud/nifcloud-sdk-go v1.21.0
github.com/stretchr/testify v1.8.1
golang.org/x/sys v0.4.0
google.golang.org/grpc v1.27.0
k8s.io/apimachinery v0.19.2
k8s.io/klog v1.0.0
Expand All @@ -23,6 +24,7 @@ require (
github.com/aws/aws-sdk-go-v2 v1.17.4 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-logr/logr v0.2.0 // indirect
github.com/gogo/protobuf v1.3.1 // indirect
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/googleapis/gax-go/v2 v2.0.5 // indirect
Expand All @@ -31,12 +33,12 @@ require (
go.opencensus.io v0.22.2 // indirect
golang.org/x/net v0.1.0 // indirect
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6 // indirect
golang.org/x/sys v0.4.0 // indirect
golang.org/x/text v0.6.0 // indirect
google.golang.org/api v0.15.1 // indirect
google.golang.org/appengine v1.6.5 // indirect
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/klog/v2 v2.2.0 // indirect
)
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ github.com/godbus/dbus v0.0.0-20181101234600-2ff6f7ffd60f/go.mod h1:/YcGZj5zSblf
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
Expand Down Expand Up @@ -306,6 +307,7 @@ github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+u
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
Expand Down Expand Up @@ -874,6 +876,7 @@ gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/mcuadros/go-syslog.v2 v2.2.1/go.mod h1:l5LPIyOOyIdQquNg+oU6Z3524YwrcqEm0aKH+5zpt2U=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
Expand Down
111 changes: 110 additions & 1 deletion pkg/driver/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@ import (
"os"
"path/filepath"
"regexp"
"strconv"
"strings"

"github.com/aokumasan/nifcloud-additional-storage-csi-driver/pkg/cloud"
csi "github.com/container-storage-interface/spec/lib/go/csi"
awsdriver "github.com/kubernetes-sigs/aws-ebs-csi-driver/pkg/driver"
gcpcommon "github.com/kubernetes-sigs/gcp-compute-persistent-disk-csi-driver/pkg/common"
"golang.org/x/sys/unix"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/klog"
"k8s.io/kubernetes/pkg/util/resizefs"
"k8s.io/utils/exec"
Expand Down Expand Up @@ -323,7 +326,64 @@ func (n *nodeService) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpu
}

func (n *nodeService) NodeGetVolumeStats(ctx context.Context, req *csi.NodeGetVolumeStatsRequest) (*csi.NodeGetVolumeStatsResponse, error) {
return nil, status.Error(codes.Unimplemented, "NodeGetVolumeStats is not implemented yet")
klog.V(4).Infof("NodeGetVolumeStats: called with args %+v", *req)
if len(req.VolumeId) == 0 {
return nil, status.Error(codes.InvalidArgument, "NodeGetVolumeStats volume ID was empty")
}
if len(req.VolumePath) == 0 {
return nil, status.Error(codes.InvalidArgument, "NodeGetVolumeStats volume path was empty")
}

exists, err := n.mounter.ExistsPath(req.VolumePath)
if err != nil {
return nil, status.Errorf(codes.Internal, "unknown error when stat on %s: %v", req.VolumePath, err)
}
if !exists {
return nil, status.Errorf(codes.NotFound, "path %s does not exist", req.VolumePath)
}

isBlock, err := isBlockDevice(req.VolumePath)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to determine whether %s is block device: %v", req.VolumePath, err)
}

if isBlock {
bcap, err := n.getBlockSizeBytes(req.VolumePath)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get block capacity on path %s: %v", req.VolumePath, err)
}

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

available, capacity, used, inodes, inodesFree, inodesUsed, err := getFsInfo(req.VolumePath)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get FsInfo due to error: %v", err)
}

return &csi.NodeGetVolumeStatsResponse{
Usage: []*csi.VolumeUsage{
{
Unit: csi.VolumeUsage_BYTES,
Available: resource.NewQuantity(available, resource.BinarySI).AsDec().UnscaledBig().Int64(),
Total: resource.NewQuantity(capacity, resource.BinarySI).AsDec().UnscaledBig().Int64(),
Used: resource.NewQuantity(used, resource.BinarySI).AsDec().UnscaledBig().Int64(),
},
{
Unit: csi.VolumeUsage_INODES,
Available: resource.NewQuantity(inodesFree, resource.BinarySI).AsDec().UnscaledBig().Int64(),
Total: resource.NewQuantity(inodes, resource.BinarySI).AsDec().UnscaledBig().Int64(),
Used: resource.NewQuantity(inodesUsed, resource.BinarySI).AsDec().UnscaledBig().Int64(),
},
},
}, nil
}

func (n *nodeService) NodeGetCapabilities(ctx context.Context, req *csi.NodeGetCapabilitiesRequest) (*csi.NodeGetCapabilitiesResponse, error) {
Expand Down Expand Up @@ -454,6 +514,22 @@ func (n *nodeService) nodePublishVolumeForFileSystem(req *csi.NodePublishVolumeR
return nil
}

func (n *nodeService) getBlockSizeBytes(devicePath string) (int64, error) {
cmd := n.mounter.(*NodeMounter).Exec.Command("blockdev", "--getsize64", devicePath)
output, err := cmd.Output()
if err != nil {
return -1, fmt.Errorf("error when getting size of block volume at path %s: output: %s, err: %v", devicePath, string(output), err)
}

strOut := strings.TrimSpace(string(output))
gotSizeBytes, err := strconv.ParseInt(strOut, 10, 64)
if err != nil {
return -1, fmt.Errorf("failed to parse size %s as int", strOut)
}

return gotSizeBytes, nil
}

func (n *nodeService) findDevicePath(scsiID string) (string, error) {
if !strings.HasPrefix(scsiID, "SCSI") {
return "", fmt.Errorf("invalid SCSI ID %q was specified. SCSI ID must be start with SCSI (0:?)", scsiID)
Expand Down Expand Up @@ -576,3 +652,36 @@ func (n *nodeService) rescanStorageDevice(dev string) error {

return nil
}

func getFsInfo(path string) (int64, int64, int64, int64, int64, int64, error) {
statfs := &unix.Statfs_t{}
err := unix.Statfs(path, statfs)
if err != nil {
return 0, 0, 0, 0, 0, 0, err
}

// Available is blocks available * fragment size
available := int64(statfs.Bavail) * int64(statfs.Bsize)

// Capacity is total block count * fragment size
capacity := int64(statfs.Blocks) * int64(statfs.Bsize)

// Usage is block being used * fragment size (aka block size).
usage := (int64(statfs.Blocks) - int64(statfs.Bfree)) * int64(statfs.Bsize)

inodes := int64(statfs.Files)
inodesFree := int64(statfs.Ffree)
inodesUsed := inodes - inodesFree

return available, capacity, usage, inodes, inodesFree, inodesUsed, nil
}

func isBlockDevice(fullPath string) (bool, error) {
var st unix.Stat_t
err := unix.Stat(fullPath, &st)
if err != nil {
return false, err
}

return (st.Mode & unix.S_IFMT) == unix.S_IFBLK, nil
}

0 comments on commit 3ca7e98

Please sign in to comment.