From 1e15c36ec9adc15bea3739bae17586b927aa3313 Mon Sep 17 00:00:00 2001 From: Mudit Agarwal Date: Mon, 1 Feb 2021 21:28:03 +0530 Subject: [PATCH] cephfs: add state field to SubVolumeInfo structure. Signed-off-by: Mudit Agarwal --- cephfs/admin/subvolume.go | 55 ++++++++++++++++++++++++---------- cephfs/admin/subvolume_test.go | 55 +++++++++++++++++++++++++++++++++- 2 files changed, 94 insertions(+), 16 deletions(-) diff --git a/cephfs/admin/subvolume.go b/cephfs/admin/subvolume.go index ac18983..69fb4f9 100644 --- a/cephfs/admin/subvolume.go +++ b/cephfs/admin/subvolume.go @@ -197,23 +197,48 @@ const ( SnapshotRetentionFeature = Feature("snapshot-retention") ) +// SubVolumeState is used to define constant value for the state of +// a subvolume. +type SubVolumeState string + +const ( + // StateUnset indicates a subvolume without any state. + StateUnset = SubVolumeState("") + // StateInit indicates that the subvolume is in initializing state. + StateInit = SubVolumeState("init") + // StatePending indicates that the subvolume is in pending state. + StatePending = SubVolumeState("pending") + // StateInProgress indicates that the subvolume is in in-progress state. + StateInProgress = SubVolumeState("in-progress") + // StateFailed indicates that the subvolume is in failed state. + StateFailed = SubVolumeState("failed") + // StateComplete indicates that the subvolume is in complete state. + StateComplete = SubVolumeState("complete") + // StateCanceled indicates that the subvolume is in canceled state. + StateCanceled = SubVolumeState("canceled") + // StateSnapRetained indicates that the subvolume is in + // snapshot-retained state. + StateSnapRetained = SubVolumeState("snapshot-retained") +) + // SubVolumeInfo reports various informational values about a subvolume. type SubVolumeInfo struct { - Type string `json:"type"` - Path string `json:"path"` - Uid int `json:"uid"` - Gid int `json:"gid"` - Mode int `json:"mode"` - BytesPercent string `json:"bytes_pcent"` - BytesUsed ByteCount `json:"bytes_used"` - BytesQuota QuotaSize `json:"-"` - DataPool string `json:"data_pool"` - PoolNamespace string `json:"pool_namespace"` - Atime TimeStamp `json:"atime"` - Mtime TimeStamp `json:"mtime"` - Ctime TimeStamp `json:"ctime"` - CreatedAt TimeStamp `json:"created_at"` - Features []Feature `json:"features"` + Type string `json:"type"` + Path string `json:"path"` + State SubVolumeState `json:"state"` + Uid int `json:"uid"` + Gid int `json:"gid"` + Mode int `json:"mode"` + BytesPercent string `json:"bytes_pcent"` + BytesUsed ByteCount `json:"bytes_used"` + BytesQuota QuotaSize `json:"-"` + DataPool string `json:"data_pool"` + PoolNamespace string `json:"pool_namespace"` + Atime TimeStamp `json:"atime"` + Mtime TimeStamp `json:"mtime"` + Ctime TimeStamp `json:"ctime"` + CreatedAt TimeStamp `json:"created_at"` + Features []Feature `json:"features"` } type subVolumeInfoWrapper struct { diff --git a/cephfs/admin/subvolume_test.go b/cephfs/admin/subvolume_test.go index 94fe19a..78cdc94 100644 --- a/cephfs/admin/subvolume_test.go +++ b/cephfs/admin/subvolume_test.go @@ -192,8 +192,11 @@ func TestRemoveSubVolume(t *testing.T) { assert.NoError(t, err) delay() - _, err = fsa.SubVolumeInfo(volume, NoGroup, subname) + subInfo, err := fsa.SubVolumeInfo(volume, NoGroup, subname) assert.NoError(t, err) + // If the subvolume is deleted with snapshots retained, then + // it must have snapshot-retained state. + assert.Equal(t, subInfo.State, StateSnapRetained) err = fsa.RemoveSubVolumeSnapshot(volume, NoGroup, subname, snapname) assert.NoError(t, err) @@ -361,6 +364,34 @@ var sampleSubVolumeInfo3 = []byte(` } `) +var sampleSubVolumeInfo4 = []byte(` +{ + "atime": "2020-10-02 13:48:17", + "bytes_pcent": "undefined", + "bytes_quota": "infinite", + "bytes_used": 0, + "created_at": "2020-10-02 13:48:17", + "ctime": "2020-10-02 13:48:17", + "data_pool": "cephfs_data", + "features": [ + "snapshot-clone", + "snapshot-autoprotect", + "snapshot-retention" + ], + "gid": 0, + "mode": 16877, + "mon_addrs": [ + "127.0.0.1:6789" + ], + "mtime": "2020-10-02 13:48:17", + "path": "/volumes/igotta/boogie/0302e067-e7fb-4d9b-8388-aae46164d8b0", + "pool_namespace": "", + "state": "complete", + "type": "subvolume", + "uid": 0 +} +`) + var badSampleSubVolumeInfo1 = []byte(` { "bytes_quota": "fishy", @@ -430,6 +461,18 @@ func TestParseSubVolumeInfo(t *testing.T) { assert.Contains(t, info.Features, SnapshotAutoprotectFeature) } }) + t.Run("ok4", func(t *testing.T) { + info, err := parseSubVolumeInfo(R(sampleSubVolumeInfo4, "", nil)) + assert.NoError(t, err) + if assert.NotNil(t, info) { + assert.Equal(t, + "/volumes/igotta/boogie/0302e067-e7fb-4d9b-8388-aae46164d8b0", + info.Path) + assert.Equal(t, 0, info.Uid) + assert.Contains(t, info.Features, SnapshotRetentionFeature) + assert.Equal(t, info.State, StateComplete) + } + }) t.Run("invalidBytesQuotaValue", func(t *testing.T) { info, err := parseSubVolumeInfo(R(badSampleSubVolumeInfo1, "", nil)) assert.Error(t, err) @@ -473,6 +516,16 @@ func TestSubVolumeInfo(t *testing.T) { assert.Equal(t, 20*gibiByte, vinfo.BytesQuota) assert.Equal(t, 040750, vinfo.Mode) assert.Equal(t, time.Now().Year(), vinfo.Ctime.Year()) + // state field was added with snapshot retention feature. + canRetain := false + for _, f := range vinfo.Features { + if f == SnapshotRetentionFeature { + canRetain = true + } + } + if canRetain { + assert.Equal(t, vinfo.State, StateComplete) + } } func TestSubVolumeSnapshots(t *testing.T) {