2020-08-04 21:00:16 +00:00
|
|
|
package admin
|
|
|
|
|
|
|
|
import (
|
2020-09-01 15:12:45 +00:00
|
|
|
"errors"
|
2020-08-04 21:00:16 +00:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestListVolumes(t *testing.T) {
|
|
|
|
fsa := getFSAdmin(t)
|
|
|
|
|
|
|
|
vl, err := fsa.ListVolumes()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Len(t, vl, 1)
|
|
|
|
assert.Equal(t, "cephfs", vl[0])
|
|
|
|
}
|
2020-09-01 15:12:45 +00:00
|
|
|
|
|
|
|
func TestEnumerateVolumes(t *testing.T) {
|
|
|
|
fsa := getFSAdmin(t)
|
|
|
|
|
|
|
|
ve, err := fsa.EnumerateVolumes()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
if assert.Len(t, ve, 1) {
|
|
|
|
assert.Equal(t, "cephfs", ve[0].Name)
|
|
|
|
assert.Equal(t, int64(1), ve[0].ID)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// note: some of these dumps are simplified for testing purposes if we add
|
|
|
|
// general dump support these samples may need to be expanded upon.
|
|
|
|
var sampleDump1 = []byte(`
|
|
|
|
{
|
|
|
|
"epoch": 5,
|
|
|
|
"default_fscid": 1,
|
|
|
|
"filesystems": [
|
|
|
|
{
|
|
|
|
"mdsmap": {
|
|
|
|
"epoch": 5,
|
|
|
|
"flags": 18,
|
|
|
|
"ever_allowed_features": 0,
|
|
|
|
"explicitly_allowed_features": 0,
|
|
|
|
"created": "2020-08-31T18:37:34.657633+0000",
|
|
|
|
"modified": "2020-08-31T18:37:36.700989+0000",
|
|
|
|
"tableserver": 0,
|
|
|
|
"root": 0,
|
|
|
|
"session_timeout": 60,
|
|
|
|
"session_autoclose": 300,
|
|
|
|
"min_compat_client": "0 (unknown)",
|
|
|
|
"max_file_size": 1099511627776,
|
|
|
|
"last_failure": 0,
|
|
|
|
"last_failure_osd_epoch": 0,
|
|
|
|
"compat": {
|
|
|
|
"compat": {},
|
|
|
|
"ro_compat": {},
|
|
|
|
"incompat": {
|
|
|
|
"feature_1": "base v0.20",
|
|
|
|
"feature_2": "client writeable ranges",
|
|
|
|
"feature_3": "default file layouts on dirs",
|
|
|
|
"feature_4": "dir inode in separate object",
|
|
|
|
"feature_5": "mds uses versioned encoding",
|
|
|
|
"feature_6": "dirfrag is stored in omap",
|
|
|
|
"feature_8": "no anchor table",
|
|
|
|
"feature_9": "file layout v2",
|
|
|
|
"feature_10": "snaprealm v2"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"max_mds": 1,
|
|
|
|
"in": [
|
|
|
|
0
|
|
|
|
],
|
|
|
|
"up": {
|
|
|
|
"mds_0": 4115
|
|
|
|
},
|
|
|
|
"failed": [],
|
|
|
|
"damaged": [],
|
|
|
|
"stopped": [],
|
|
|
|
"info": {
|
|
|
|
"gid_4115": {
|
|
|
|
"gid": 4115,
|
|
|
|
"name": "Z",
|
|
|
|
"rank": 0,
|
|
|
|
"incarnation": 4,
|
|
|
|
"state": "up:active",
|
|
|
|
"state_seq": 2,
|
|
|
|
"addr": "127.0.0.1:6809/2568111595",
|
|
|
|
"addrs": {
|
|
|
|
"addrvec": [
|
|
|
|
{
|
|
|
|
"type": "v1",
|
|
|
|
"addr": "127.0.0.1:6809",
|
|
|
|
"nonce": 2568111595
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"join_fscid": -1,
|
|
|
|
"export_targets": [],
|
|
|
|
"features": 4540138292836696000,
|
|
|
|
"flags": 0
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"data_pools": [
|
|
|
|
1
|
|
|
|
],
|
|
|
|
"metadata_pool": 2,
|
|
|
|
"enabled": true,
|
|
|
|
"fs_name": "cephfs",
|
|
|
|
"balancer": "",
|
|
|
|
"standby_count_wanted": 0
|
|
|
|
},
|
|
|
|
"id": 1
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
`)
|
|
|
|
|
|
|
|
var sampleDump2 = []byte(`
|
|
|
|
{
|
|
|
|
"epoch": 5,
|
|
|
|
"default_fscid": 1,
|
|
|
|
"filesystems": [
|
|
|
|
{
|
|
|
|
"mdsmap": {
|
|
|
|
"fs_name": "wiffleball",
|
|
|
|
"standby_count_wanted": 0
|
|
|
|
},
|
|
|
|
"id": 1
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"mdsmap": {
|
|
|
|
"fs_name": "beanbag",
|
|
|
|
"standby_count_wanted": 0
|
|
|
|
},
|
|
|
|
"id": 2
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
`)
|
|
|
|
|
|
|
|
func TestParseDumpToIdents(t *testing.T) {
|
2020-09-21 18:53:29 +00:00
|
|
|
R := newResponse
|
2020-09-01 15:12:45 +00:00
|
|
|
fakePrefix := dumpOkPrefix + " 5"
|
|
|
|
t.Run("error", func(t *testing.T) {
|
2020-09-21 18:53:29 +00:00
|
|
|
idents, err := parseDumpToIdents(R(nil, "", errors.New("boop")))
|
2020-09-01 15:12:45 +00:00
|
|
|
assert.Error(t, err)
|
|
|
|
assert.Equal(t, "boop", err.Error())
|
|
|
|
assert.Nil(t, idents)
|
|
|
|
})
|
|
|
|
t.Run("badStatus", func(t *testing.T) {
|
2020-09-21 18:53:29 +00:00
|
|
|
_, err := parseDumpToIdents(R(sampleDump1, "unexpected!", nil))
|
2020-09-01 15:12:45 +00:00
|
|
|
assert.Error(t, err)
|
|
|
|
})
|
|
|
|
t.Run("oneVolOk", func(t *testing.T) {
|
2020-09-21 18:53:29 +00:00
|
|
|
idents, err := parseDumpToIdents(R(sampleDump1, fakePrefix, nil))
|
2020-09-01 15:12:45 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
if assert.Len(t, idents, 1) {
|
|
|
|
assert.Equal(t, "cephfs", idents[0].Name)
|
|
|
|
assert.Equal(t, int64(1), idents[0].ID)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
t.Run("twoVolOk", func(t *testing.T) {
|
2020-09-21 18:53:29 +00:00
|
|
|
idents, err := parseDumpToIdents(R(sampleDump2, fakePrefix, nil))
|
2020-09-01 15:12:45 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
if assert.Len(t, idents, 2) {
|
|
|
|
assert.Equal(t, "wiffleball", idents[0].Name)
|
|
|
|
assert.Equal(t, int64(1), idents[0].ID)
|
|
|
|
assert.Equal(t, "beanbag", idents[1].Name)
|
|
|
|
assert.Equal(t, int64(2), idents[1].ID)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
t.Run("unexpectedStatus", func(t *testing.T) {
|
2020-09-21 18:53:29 +00:00
|
|
|
idents, err := parseDumpToIdents(R(sampleDump1, "slip-up", nil))
|
2020-09-01 15:12:45 +00:00
|
|
|
assert.Error(t, err)
|
|
|
|
assert.Nil(t, idents)
|
|
|
|
})
|
|
|
|
}
|
2020-09-30 19:59:01 +00:00
|
|
|
|
|
|
|
func TestVolumeStatus(t *testing.T) {
|
2021-03-17 18:42:49 +00:00
|
|
|
if serverVersion == cephNautilus {
|
|
|
|
t.Skipf("can only execute on octopus/pacific servers")
|
2020-09-30 19:59:01 +00:00
|
|
|
}
|
|
|
|
fsa := getFSAdmin(t)
|
|
|
|
|
|
|
|
vs, err := fsa.VolumeStatus("cephfs")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Contains(t, vs.MDSVersion, "version")
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestVolumeStatusInvalid(t *testing.T) {
|
2021-03-17 18:42:49 +00:00
|
|
|
if serverVersion != cephNautilus {
|
2020-09-30 19:59:01 +00:00
|
|
|
t.Skipf("can only excecute on nautilus servers")
|
|
|
|
}
|
|
|
|
fsa := getFSAdmin(t)
|
|
|
|
|
|
|
|
vs, err := fsa.VolumeStatus("cephfs")
|
|
|
|
assert.Error(t, err)
|
|
|
|
assert.Nil(t, vs)
|
|
|
|
var notImpl NotImplementedError
|
|
|
|
assert.True(t, errors.As(err, ¬Impl))
|
|
|
|
}
|
|
|
|
|
|
|
|
var sampleVolumeStatus1 = []byte(`
|
|
|
|
{
|
|
|
|
"clients": [{"clients": 1, "fs": "cephfs"}],
|
|
|
|
"mds_version": "ceph version 15.2.4 (7447c15c6ff58d7fce91843b705a268a1917325c) octopus (stable)",
|
|
|
|
"mdsmap": [{"dns": 76, "inos": 19, "name": "Z", "rank": 0, "rate": 0.0, "state": "active"}],
|
|
|
|
"pools": [{"avail": 1017799872, "id": 2, "name": "cephfs_metadata", "type": "metadata", "used": 2204126}, {"avail": 1017799872, "id": 1, "name": "cephfs_data", "type": "data", "used": 0}]
|
|
|
|
}
|
|
|
|
`)
|
|
|
|
|
2022-03-18 21:14:19 +00:00
|
|
|
var sampleVolumeStatusQ = []byte(`
|
|
|
|
{"clients": [{"clients": 3, "fs": "cephfs"}], "mds_version": [{"daemon": ["Z"], "version": "ceph version 17.1.0 (c675060073a05d40ef404d5921c81178a52af6e0) quincy (dev)"}], "mdsmap": [{"caps": 11, "dirs": 26, "dns": 49, "inos": 30, "name": "Z", "rank": 0, "rate": 0, "state": "active"}], "pools": [{"avail": 1018405056, "id": 2, "name": "cephfs_metadata", "type": "metadata", "used": 467690}, {"avail": 1018405056, "id": 1, "name": "cephfs_data", "type": "data", "used": 8}]}
|
|
|
|
`)
|
|
|
|
|
2020-09-30 19:59:01 +00:00
|
|
|
var sampleVolumeStatusTextJunk = []byte(`cephfs - 2 clients
|
|
|
|
======
|
|
|
|
+------+--------+-----+---------------+-------+-------+
|
|
|
|
| Rank | State | MDS | Activity | dns | inos |
|
|
|
|
+------+--------+-----+---------------+-------+-------+
|
|
|
|
| 0 | active | Z | Reqs: 98 /s | 254 | 192 |
|
|
|
|
+------+--------+-----+---------------+-------+-------+
|
|
|
|
+-----------------+----------+-------+-------+
|
|
|
|
| Pool | type | used | avail |
|
|
|
|
+-----------------+----------+-------+-------+
|
|
|
|
| cephfs_metadata | metadata | 62.1M | 910M |
|
|
|
|
| cephfs_data | data | 0 | 910M |
|
|
|
|
+-----------------+----------+-------+-------+
|
|
|
|
+-------------+
|
|
|
|
| Standby MDS |
|
|
|
|
+-------------+
|
|
|
|
+-------------+
|
|
|
|
MDS version: ceph version 14.2.11 (f7fdb2f52131f54b891a2ec99d8205561242cdaf) nautilus (stable)
|
|
|
|
`)
|
|
|
|
|
|
|
|
func TestParseVolumeStatus(t *testing.T) {
|
|
|
|
R := newResponse
|
|
|
|
t.Run("error", func(t *testing.T) {
|
|
|
|
_, err := parseVolumeStatus(R(nil, "", errors.New("bonk")))
|
|
|
|
assert.Error(t, err)
|
|
|
|
assert.Equal(t, "bonk", err.Error())
|
|
|
|
})
|
|
|
|
t.Run("statusSet", func(t *testing.T) {
|
|
|
|
_, err := parseVolumeStatus(R(nil, "unexpected!", nil))
|
|
|
|
assert.Error(t, err)
|
|
|
|
})
|
|
|
|
t.Run("badJSON", func(t *testing.T) {
|
|
|
|
_, err := parseVolumeStatus(R([]byte("_XxXxX"), "", nil))
|
|
|
|
assert.Error(t, err)
|
|
|
|
})
|
|
|
|
t.Run("ok", func(t *testing.T) {
|
2022-03-18 21:14:19 +00:00
|
|
|
v, err := parseVolumeStatus(R(sampleVolumeStatus1, "", nil))
|
2020-09-30 19:59:01 +00:00
|
|
|
assert.NoError(t, err)
|
2022-03-18 21:14:19 +00:00
|
|
|
s := v.volumeStatus()
|
2020-09-30 19:59:01 +00:00
|
|
|
if assert.NotNil(t, s) {
|
|
|
|
assert.Contains(t, s.MDSVersion, "ceph version 15.2.4")
|
|
|
|
assert.Contains(t, s.MDSVersion, "octopus")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
t.Run("notJSONfromServer", func(t *testing.T) {
|
|
|
|
_, err := parseVolumeStatus(R(sampleVolumeStatusTextJunk, "", nil))
|
|
|
|
if assert.Error(t, err) {
|
|
|
|
var notImpl NotImplementedError
|
|
|
|
assert.True(t, errors.As(err, ¬Impl))
|
|
|
|
}
|
|
|
|
})
|
2022-03-18 21:14:19 +00:00
|
|
|
t.Run("quincy", func(t *testing.T) {
|
|
|
|
v, err := parseVolumeStatus(R(sampleVolumeStatusQ, "", nil))
|
|
|
|
assert.NoError(t, err)
|
|
|
|
s := v.volumeStatus()
|
|
|
|
if assert.NotNil(t, s) {
|
|
|
|
assert.Contains(t, s.MDSVersion, "ceph version 17.1.0")
|
|
|
|
assert.Contains(t, s.MDSVersion, "quincy")
|
|
|
|
}
|
|
|
|
})
|
2020-09-30 19:59:01 +00:00
|
|
|
|
|
|
|
}
|
2020-10-04 15:19:28 +00:00
|
|
|
|
|
|
|
var sampleFsLs1 = []byte(`
|
|
|
|
[
|
|
|
|
{
|
|
|
|
"name": "cephfs",
|
|
|
|
"metadata_pool": "cephfs_metadata",
|
|
|
|
"metadata_pool_id": 2,
|
|
|
|
"data_pool_ids": [
|
|
|
|
1
|
|
|
|
],
|
|
|
|
"data_pools": [
|
|
|
|
"cephfs_data"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
`)
|
|
|
|
|
|
|
|
var sampleFsLs2 = []byte(`
|
|
|
|
[
|
|
|
|
{
|
|
|
|
"name": "cephfs",
|
|
|
|
"metadata_pool": "cephfs_metadata",
|
|
|
|
"metadata_pool_id": 2,
|
|
|
|
"data_pool_ids": [
|
|
|
|
1
|
|
|
|
],
|
|
|
|
"data_pools": [
|
|
|
|
"cephfs_data"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"name": "archivefs",
|
|
|
|
"metadata_pool": "archivefs_metadata",
|
|
|
|
"metadata_pool_id": 6,
|
|
|
|
"data_pool_ids": [
|
|
|
|
4,
|
|
|
|
5
|
|
|
|
],
|
|
|
|
"data_pools": [
|
|
|
|
"archivefs_data1",
|
|
|
|
"archivefs_data2"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
`)
|
|
|
|
|
|
|
|
func TestParseFsList(t *testing.T) {
|
|
|
|
t.Run("error", func(t *testing.T) {
|
2021-03-03 19:45:21 +00:00
|
|
|
_, err := parseFsList(
|
|
|
|
newResponse(nil, "", errors.New("eek")))
|
2020-10-04 15:19:28 +00:00
|
|
|
assert.Error(t, err)
|
|
|
|
assert.Equal(t, "eek", err.Error())
|
|
|
|
})
|
|
|
|
t.Run("statusSet", func(t *testing.T) {
|
2021-03-03 19:45:21 +00:00
|
|
|
_, err := parseFsList(
|
|
|
|
newResponse(nil, "oof", nil))
|
2020-10-04 15:19:28 +00:00
|
|
|
assert.Error(t, err)
|
|
|
|
})
|
|
|
|
t.Run("badJSON", func(t *testing.T) {
|
2021-03-03 19:45:21 +00:00
|
|
|
_, err := parseFsList(
|
|
|
|
newResponse([]byte("______"), "", nil))
|
2020-10-04 15:19:28 +00:00
|
|
|
assert.Error(t, err)
|
|
|
|
})
|
|
|
|
t.Run("ok1", func(t *testing.T) {
|
2021-03-03 19:45:21 +00:00
|
|
|
l, err := parseFsList(
|
|
|
|
newResponse(sampleFsLs1, "", nil))
|
2020-10-04 15:19:28 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
if assert.NotNil(t, l) && assert.Len(t, l, 1) {
|
|
|
|
fs := l[0]
|
|
|
|
assert.Equal(t, "cephfs", fs.Name)
|
|
|
|
assert.Equal(t, "cephfs_metadata", fs.MetadataPool)
|
|
|
|
assert.Equal(t, 2, fs.MetadataPoolID)
|
|
|
|
assert.Len(t, fs.DataPools, 1)
|
|
|
|
assert.Contains(t, fs.DataPools, "cephfs_data")
|
|
|
|
assert.Len(t, fs.DataPoolIDs, 1)
|
|
|
|
assert.Contains(t, fs.DataPoolIDs, 1)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
t.Run("ok2", func(t *testing.T) {
|
2021-03-03 19:45:21 +00:00
|
|
|
l, err := parseFsList(
|
|
|
|
newResponse(sampleFsLs2, "", nil))
|
2020-10-04 15:19:28 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
if assert.NotNil(t, l) && assert.Len(t, l, 2) {
|
|
|
|
fs := l[0]
|
|
|
|
assert.Equal(t, "cephfs", fs.Name)
|
|
|
|
assert.Equal(t, "cephfs_metadata", fs.MetadataPool)
|
|
|
|
assert.Equal(t, 2, fs.MetadataPoolID)
|
|
|
|
assert.Len(t, fs.DataPools, 1)
|
|
|
|
assert.Contains(t, fs.DataPools, "cephfs_data")
|
|
|
|
assert.Len(t, fs.DataPoolIDs, 1)
|
|
|
|
assert.Contains(t, fs.DataPoolIDs, 1)
|
|
|
|
fs = l[1]
|
|
|
|
assert.Equal(t, "archivefs", fs.Name)
|
|
|
|
assert.Equal(t, "archivefs_metadata", fs.MetadataPool)
|
|
|
|
assert.Equal(t, 6, fs.MetadataPoolID)
|
|
|
|
assert.Len(t, fs.DataPools, 2)
|
|
|
|
assert.Contains(t, fs.DataPools, "archivefs_data1")
|
|
|
|
assert.Contains(t, fs.DataPools, "archivefs_data2")
|
|
|
|
assert.Len(t, fs.DataPoolIDs, 2)
|
|
|
|
assert.Contains(t, fs.DataPoolIDs, 4)
|
|
|
|
assert.Contains(t, fs.DataPoolIDs, 5)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestListFileSystems(t *testing.T) {
|
|
|
|
fsa := getFSAdmin(t)
|
|
|
|
|
|
|
|
l, err := fsa.ListFileSystems()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
if assert.Len(t, l, 1) {
|
|
|
|
assert.Equal(t, "cephfs", l[0].Name)
|
|
|
|
assert.Equal(t, "cephfs_metadata", l[0].MetadataPool)
|
|
|
|
assert.Len(t, l[0].DataPools, 1)
|
|
|
|
assert.Contains(t, l[0].DataPools, "cephfs_data")
|
|
|
|
}
|
|
|
|
}
|