Skip to content

Commit cb327fd

Browse files
authored
Merge pull request #293 from dr0pdb/nodegetstats
feat: Implement node get stats
2 parents b48294d + 86a1f1b commit cb327fd

File tree

4 files changed

+112
-7
lines changed

4 files changed

+112
-7
lines changed

pkg/blob/blob.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ func (d *Driver) Run(endpoint, kubeconfig string, testBool bool) {
157157

158158
d.AddNodeServiceCapabilities([]csi.NodeServiceCapability_RPC_Type{
159159
csi.NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME,
160+
csi.NodeServiceCapability_RPC_GET_VOLUME_STATS,
160161
csi.NodeServiceCapability_RPC_UNKNOWN,
161162
})
162163

pkg/blob/nodeserver.go

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030

3131
"k8s.io/apimachinery/pkg/util/wait"
3232
"k8s.io/klog/v2"
33+
"k8s.io/kubernetes/pkg/volume"
3334
"k8s.io/kubernetes/pkg/volume/util"
3435
"k8s.io/utils/mount"
3536

@@ -252,8 +253,69 @@ func (d *Driver) NodeGetInfo(ctx context.Context, req *csi.NodeGetInfoRequest) (
252253
}
253254

254255
// NodeGetVolumeStats get volume stats
255-
func (d *Driver) NodeGetVolumeStats(ctx context.Context, in *csi.NodeGetVolumeStatsRequest) (*csi.NodeGetVolumeStatsResponse, error) {
256-
return nil, status.Error(codes.Unimplemented, "")
256+
func (d *Driver) NodeGetVolumeStats(ctx context.Context, req *csi.NodeGetVolumeStatsRequest) (*csi.NodeGetVolumeStatsResponse, error) {
257+
if len(req.VolumeId) == 0 {
258+
return nil, status.Error(codes.InvalidArgument, "NodeGetVolumeStats volume ID was empty")
259+
}
260+
if len(req.VolumePath) == 0 {
261+
return nil, status.Error(codes.InvalidArgument, "NodeGetVolumeStats volume path was empty")
262+
}
263+
264+
_, err := os.Stat(req.VolumePath)
265+
if err != nil {
266+
if os.IsNotExist(err) {
267+
return nil, status.Errorf(codes.NotFound, "path %s does not exist", req.VolumePath)
268+
}
269+
return nil, status.Errorf(codes.Internal, "failed to stat file %s: %v", req.VolumePath, err)
270+
}
271+
272+
volumeMetrics, err := volume.NewMetricsStatFS(req.VolumePath).GetMetrics()
273+
if err != nil {
274+
return nil, status.Errorf(codes.Internal, "failed to get metrics: %v", err)
275+
}
276+
277+
available, ok := volumeMetrics.Available.AsInt64()
278+
if !ok {
279+
return nil, status.Errorf(codes.Internal, "failed to transform volume available size(%v)", volumeMetrics.Available)
280+
}
281+
capacity, ok := volumeMetrics.Capacity.AsInt64()
282+
if !ok {
283+
return nil, status.Errorf(codes.Internal, "failed to transform volume capacity size(%v)", volumeMetrics.Capacity)
284+
}
285+
used, ok := volumeMetrics.Used.AsInt64()
286+
if !ok {
287+
return nil, status.Errorf(codes.Internal, "failed to transform volume used size(%v)", volumeMetrics.Used)
288+
}
289+
290+
inodesFree, ok := volumeMetrics.InodesFree.AsInt64()
291+
if !ok {
292+
return nil, status.Errorf(codes.Internal, "failed to transform disk inodes free(%v)", volumeMetrics.InodesFree)
293+
}
294+
inodes, ok := volumeMetrics.Inodes.AsInt64()
295+
if !ok {
296+
return nil, status.Errorf(codes.Internal, "failed to transform disk inodes(%v)", volumeMetrics.Inodes)
297+
}
298+
inodesUsed, ok := volumeMetrics.InodesUsed.AsInt64()
299+
if !ok {
300+
return nil, status.Errorf(codes.Internal, "failed to transform disk inodes used(%v)", volumeMetrics.InodesUsed)
301+
}
302+
303+
return &csi.NodeGetVolumeStatsResponse{
304+
Usage: []*csi.VolumeUsage{
305+
{
306+
Unit: csi.VolumeUsage_BYTES,
307+
Available: available,
308+
Total: capacity,
309+
Used: used,
310+
},
311+
{
312+
Unit: csi.VolumeUsage_INODES,
313+
Available: inodesFree,
314+
Total: inodes,
315+
Used: inodesUsed,
316+
},
317+
},
318+
}, nil
257319
}
258320

259321
// NodeExpandVolume node expand volume

pkg/blob/nodeserver_test.go

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -415,13 +415,51 @@ func TestNewSafeMounter(t *testing.T) {
415415
}
416416

417417
func TestNodeGetVolumeStats(t *testing.T) {
418+
nonexistedPath := "/not/a/real/directory"
419+
fakePath := "/tmp/fake-volume-path"
420+
421+
tests := []struct {
422+
desc string
423+
req csi.NodeGetVolumeStatsRequest
424+
expectedErr error
425+
}{
426+
{
427+
desc: "[Error] Volume ID missing",
428+
req: csi.NodeGetVolumeStatsRequest{VolumePath: targetTest},
429+
expectedErr: status.Error(codes.InvalidArgument, "NodeGetVolumeStats volume ID was empty"),
430+
},
431+
{
432+
desc: "[Error] VolumePath missing",
433+
req: csi.NodeGetVolumeStatsRequest{VolumeId: "vol_1"},
434+
expectedErr: status.Error(codes.InvalidArgument, "NodeGetVolumeStats volume path was empty"),
435+
},
436+
{
437+
desc: "[Error] Incorrect volume path",
438+
req: csi.NodeGetVolumeStatsRequest{VolumePath: nonexistedPath, VolumeId: "vol_1"},
439+
expectedErr: status.Errorf(codes.NotFound, "path /not/a/real/directory does not exist"),
440+
},
441+
{
442+
desc: "[Success] Standard success",
443+
req: csi.NodeGetVolumeStatsRequest{VolumePath: fakePath, VolumeId: "vol_1"},
444+
expectedErr: nil,
445+
},
446+
}
447+
448+
// Setup
449+
_ = makeDir(fakePath)
418450
d := NewFakeDriver()
419-
req := csi.NodeGetVolumeStatsRequest{}
420-
resp, err := d.NodeGetVolumeStats(context.Background(), &req)
421-
assert.Nil(t, resp)
422-
if !reflect.DeepEqual(err, status.Error(codes.Unimplemented, "")) {
423-
t.Errorf("Unexpected error: %v", err)
451+
452+
for _, test := range tests {
453+
_, err := d.NodeGetVolumeStats(context.Background(), &test.req)
454+
//t.Errorf("[debug] error: %v\n metrics: %v", err, metrics)
455+
if !reflect.DeepEqual(err, test.expectedErr) {
456+
t.Errorf("desc: %v, expected error: %v, actual error: %v", test.desc, test.expectedErr, err)
457+
}
424458
}
459+
460+
// Clean up
461+
err := os.RemoveAll(fakePath)
462+
assert.NoError(t, err)
425463
}
426464

427465
func TestNodeExpandVolume(t *testing.T) {

test/integration/run-test.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ if [[ "$cloud" != "AzureChinaCloud" ]]; then
6262
csc node publish --endpoint "$endpoint" --cap 1,block --staging-target-path "$staging_target_path" --target-path "$target_path" "$volumeid"
6363
sleep 2
6464

65+
echo "node stats test:"
66+
csc node stats --endpoint "$endpoint" "$volumeid:$target_path:$staging_target_path"
67+
sleep 2
68+
6569
echo "unpublish volume test:"
6670
csc node unpublish --endpoint "$endpoint" --target-path "$target_path" "$volumeid"
6771
sleep 2

0 commit comments

Comments
 (0)