2019-12-12 20:00:51 +00:00
|
|
|
package cephfs
|
2015-05-01 19:35:40 +00:00
|
|
|
|
2018-10-09 04:26:51 +00:00
|
|
|
import (
|
2020-01-28 18:09:29 +00:00
|
|
|
"encoding/json"
|
2018-10-09 04:26:51 +00:00
|
|
|
"fmt"
|
|
|
|
"os"
|
2018-10-10 22:06:47 +00:00
|
|
|
"syscall"
|
2018-10-09 04:26:51 +00:00
|
|
|
"testing"
|
2019-12-20 12:51:53 +00:00
|
|
|
"time"
|
2019-12-05 16:53:41 +00:00
|
|
|
|
2019-12-18 22:28:06 +00:00
|
|
|
"github.com/ceph/go-ceph/rados"
|
|
|
|
|
2019-12-05 16:53:41 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/require"
|
2018-10-09 04:26:51 +00:00
|
|
|
)
|
2015-05-01 19:35:40 +00:00
|
|
|
|
2018-10-10 22:06:47 +00:00
|
|
|
var (
|
2019-12-12 20:17:12 +00:00
|
|
|
CephMountTest = "/tmp/ceph/mds/mnt/"
|
2018-10-10 22:06:47 +00:00
|
|
|
)
|
|
|
|
|
2015-05-01 19:35:40 +00:00
|
|
|
func TestCreateMount(t *testing.T) {
|
2019-12-20 12:51:53 +00:00
|
|
|
mount := fsConnect(t)
|
2019-12-12 20:00:51 +00:00
|
|
|
mount, err := CreateMount()
|
2015-07-08 08:34:54 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.NotNil(t, mount)
|
2015-05-01 19:35:40 +00:00
|
|
|
}
|
|
|
|
|
2019-12-20 12:51:53 +00:00
|
|
|
func fsConnect(t *testing.T) *MountInfo {
|
2019-12-12 20:00:51 +00:00
|
|
|
mount, err := CreateMount()
|
2019-12-20 12:51:53 +00:00
|
|
|
require.NoError(t, err)
|
2019-12-05 16:53:41 +00:00
|
|
|
require.NotNil(t, mount)
|
2015-05-01 19:35:40 +00:00
|
|
|
|
2015-07-08 08:34:54 +00:00
|
|
|
err = mount.ReadDefaultConfigFile()
|
2019-12-20 12:51:53 +00:00
|
|
|
require.NoError(t, err)
|
2015-05-01 19:35:40 +00:00
|
|
|
|
2019-12-20 12:51:53 +00:00
|
|
|
timeout := time.After(time.Second * 5)
|
|
|
|
ch := make(chan error)
|
|
|
|
go func(mount *MountInfo) {
|
|
|
|
ch <- mount.Mount()
|
|
|
|
}(mount)
|
|
|
|
select {
|
|
|
|
case err = <-ch:
|
|
|
|
case <-timeout:
|
|
|
|
err = fmt.Errorf("timed out waiting for connect")
|
|
|
|
}
|
|
|
|
require.NoError(t, err)
|
|
|
|
return mount
|
2015-05-01 19:35:40 +00:00
|
|
|
}
|
|
|
|
|
2019-12-20 12:51:53 +00:00
|
|
|
func TestMountRoot(t *testing.T) {
|
|
|
|
fsConnect(t)
|
|
|
|
}
|
2015-05-01 19:35:40 +00:00
|
|
|
|
2019-12-20 12:51:53 +00:00
|
|
|
func TestSyncFs(t *testing.T) {
|
|
|
|
mount := fsConnect(t)
|
2015-05-01 19:35:40 +00:00
|
|
|
|
2019-12-20 12:51:53 +00:00
|
|
|
err := mount.SyncFs()
|
2015-07-08 08:34:54 +00:00
|
|
|
assert.NoError(t, err)
|
2015-05-01 19:35:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestChangeDir(t *testing.T) {
|
2019-12-20 12:51:53 +00:00
|
|
|
mount := fsConnect(t)
|
2015-05-01 19:35:40 +00:00
|
|
|
|
2015-07-08 08:34:54 +00:00
|
|
|
dir1 := mount.CurrentDir()
|
|
|
|
assert.NotNil(t, dir1)
|
2015-05-01 19:35:40 +00:00
|
|
|
|
2019-12-20 12:51:53 +00:00
|
|
|
err := mount.MakeDir("/asdf", 0755)
|
2015-07-08 08:34:54 +00:00
|
|
|
assert.NoError(t, err)
|
2015-05-01 19:35:40 +00:00
|
|
|
|
2015-07-08 08:34:54 +00:00
|
|
|
err = mount.ChangeDir("/asdf")
|
|
|
|
assert.NoError(t, err)
|
2015-05-01 19:35:40 +00:00
|
|
|
|
2015-07-08 08:34:54 +00:00
|
|
|
dir2 := mount.CurrentDir()
|
|
|
|
assert.NotNil(t, dir2)
|
2015-05-01 19:35:40 +00:00
|
|
|
|
2015-07-08 08:34:54 +00:00
|
|
|
assert.NotEqual(t, dir1, dir2)
|
|
|
|
assert.Equal(t, dir1, "/")
|
|
|
|
assert.Equal(t, dir2, "/asdf")
|
2015-05-01 19:35:40 +00:00
|
|
|
}
|
2018-10-09 04:26:51 +00:00
|
|
|
|
|
|
|
func TestRemoveDir(t *testing.T) {
|
2018-10-10 22:06:47 +00:00
|
|
|
dirname := "one"
|
2019-12-20 12:51:53 +00:00
|
|
|
mount := fsConnect(t)
|
2018-10-09 04:26:51 +00:00
|
|
|
|
2019-12-20 12:51:53 +00:00
|
|
|
err := mount.MakeDir(dirname, 0755)
|
2018-10-09 04:26:51 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
err = mount.SyncFs()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2018-10-10 22:06:47 +00:00
|
|
|
// os.Stat the actual mounted location to verify Makedir/RemoveDir
|
|
|
|
_, err = os.Stat(CephMountTest + dirname)
|
2018-10-09 04:26:51 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
err = mount.RemoveDir(dirname)
|
|
|
|
assert.NoError(t, err)
|
2018-10-10 22:06:47 +00:00
|
|
|
|
|
|
|
_, err = os.Stat(CephMountTest + dirname)
|
|
|
|
assert.EqualError(t, err,
|
|
|
|
fmt.Sprintf("stat %s: no such file or directory", CephMountTest+dirname))
|
2018-10-09 04:26:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestUnmountMount(t *testing.T) {
|
2019-12-20 12:51:53 +00:00
|
|
|
t.Run("neverMounted", func(t *testing.T) {
|
|
|
|
mount, err := CreateMount()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, mount)
|
|
|
|
assert.False(t, mount.IsMounted())
|
|
|
|
})
|
|
|
|
t.Run("mountUnmount", func(t *testing.T) {
|
|
|
|
mount := fsConnect(t)
|
|
|
|
assert.True(t, mount.IsMounted())
|
|
|
|
|
|
|
|
err := mount.Unmount()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.False(t, mount.IsMounted())
|
|
|
|
})
|
2018-10-09 04:26:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestReleaseMount(t *testing.T) {
|
2019-12-12 20:00:51 +00:00
|
|
|
mount, err := CreateMount()
|
2018-10-09 04:26:51 +00:00
|
|
|
assert.NoError(t, err)
|
2019-12-05 16:53:41 +00:00
|
|
|
require.NotNil(t, mount)
|
2018-10-09 04:26:51 +00:00
|
|
|
|
|
|
|
err = mount.Release()
|
|
|
|
assert.NoError(t, err)
|
2018-10-10 22:06:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestChmodDir(t *testing.T) {
|
|
|
|
dirname := "two"
|
|
|
|
var stats_before uint32 = 0755
|
|
|
|
var stats_after uint32 = 0700
|
2019-12-20 12:51:53 +00:00
|
|
|
mount := fsConnect(t)
|
2018-10-10 22:06:47 +00:00
|
|
|
|
2019-12-20 12:51:53 +00:00
|
|
|
err := mount.MakeDir(dirname, stats_before)
|
2018-10-10 22:06:47 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
err = mount.SyncFs()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// os.Stat the actual mounted location to verify Makedir/RemoveDir
|
|
|
|
stats, err := os.Stat(CephMountTest + dirname)
|
2019-12-05 16:53:41 +00:00
|
|
|
require.NoError(t, err)
|
2018-10-10 22:06:47 +00:00
|
|
|
|
|
|
|
assert.Equal(t, uint32(stats.Mode().Perm()), stats_before)
|
|
|
|
|
|
|
|
err = mount.Chmod(dirname, stats_after)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
stats, err = os.Stat(CephMountTest + dirname)
|
|
|
|
assert.Equal(t, uint32(stats.Mode().Perm()), stats_after)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Not cross-platform, go's os does not specifiy Sys return type
|
|
|
|
func TestChown(t *testing.T) {
|
|
|
|
dirname := "three"
|
|
|
|
// dockerfile creates bob user account
|
|
|
|
var bob uint32 = 1010
|
2019-12-12 20:17:12 +00:00
|
|
|
var root uint32
|
2018-10-10 22:06:47 +00:00
|
|
|
|
2019-12-20 12:51:53 +00:00
|
|
|
mount := fsConnect(t)
|
2018-10-10 22:06:47 +00:00
|
|
|
|
2019-12-20 12:51:53 +00:00
|
|
|
err := mount.MakeDir(dirname, 0755)
|
2018-10-10 22:06:47 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
err = mount.SyncFs()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// os.Stat the actual mounted location to verify Makedir/RemoveDir
|
|
|
|
stats, err := os.Stat(CephMountTest + dirname)
|
2019-12-05 16:53:41 +00:00
|
|
|
require.NoError(t, err)
|
2018-10-10 22:06:47 +00:00
|
|
|
|
|
|
|
assert.Equal(t, uint32(stats.Sys().(*syscall.Stat_t).Uid), root)
|
|
|
|
assert.Equal(t, uint32(stats.Sys().(*syscall.Stat_t).Gid), root)
|
|
|
|
|
|
|
|
err = mount.Chown(dirname, bob, bob)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
stats, err = os.Stat(CephMountTest + dirname)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, uint32(stats.Sys().(*syscall.Stat_t).Uid), bob)
|
|
|
|
assert.Equal(t, uint32(stats.Sys().(*syscall.Stat_t).Gid), bob)
|
|
|
|
|
2018-10-09 04:26:51 +00:00
|
|
|
}
|
2019-12-12 20:03:17 +00:00
|
|
|
|
|
|
|
func TestCephFSError(t *testing.T) {
|
|
|
|
err := getError(0)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
err = getError(-5) // IO error
|
|
|
|
assert.Error(t, err)
|
|
|
|
assert.Equal(t, err.Error(), "cephfs: ret=5, Input/output error")
|
|
|
|
|
|
|
|
err = getError(345) // no such errno
|
|
|
|
assert.Error(t, err)
|
|
|
|
assert.Equal(t, err.Error(), "cephfs: ret=345")
|
|
|
|
}
|
2019-12-18 22:28:06 +00:00
|
|
|
|
|
|
|
func radosConnect(t *testing.T) *rados.Conn {
|
|
|
|
conn, err := rados.NewConn()
|
|
|
|
require.NoError(t, err)
|
|
|
|
err = conn.ReadDefaultConfigFile()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
timeout := time.After(time.Second * 5)
|
|
|
|
ch := make(chan error)
|
|
|
|
go func(conn *rados.Conn) {
|
|
|
|
ch <- conn.Connect()
|
|
|
|
}(conn)
|
|
|
|
select {
|
|
|
|
case err = <-ch:
|
|
|
|
case <-timeout:
|
|
|
|
err = fmt.Errorf("timed out waiting for connect")
|
|
|
|
}
|
|
|
|
require.NoError(t, err)
|
|
|
|
return conn
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCreateFromRados(t *testing.T) {
|
|
|
|
conn := radosConnect(t)
|
|
|
|
mount, err := CreateFromRados(conn)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.NotNil(t, mount)
|
|
|
|
}
|
2019-12-19 20:11:50 +00:00
|
|
|
|
|
|
|
func TestCreateMountWithId(t *testing.T) {
|
2020-01-28 18:12:33 +00:00
|
|
|
mount, err := CreateMountWithId("bobolink")
|
2019-12-19 20:11:50 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.NotNil(t, mount)
|
|
|
|
|
|
|
|
err = mount.ReadDefaultConfigFile()
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
err = mount.Mount()
|
|
|
|
assert.NoError(t, err)
|
2020-01-28 18:12:33 +00:00
|
|
|
|
|
|
|
// verify the custom entity_id is visible in the 'session ls' output
|
|
|
|
// of mds.
|
|
|
|
cmd := []byte(`{"prefix": "session ls"}`)
|
|
|
|
buf, info, err := mount.MdsCommand(
|
|
|
|
"Z", // TODO: fix hard-coded name mds (from ci container script)
|
|
|
|
[][]byte{cmd})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.NotEqual(t, "", string(buf))
|
|
|
|
assert.Equal(t, "", string(info))
|
|
|
|
assert.Contains(t, string(buf), `"bobolink"`)
|
2019-12-19 20:11:50 +00:00
|
|
|
}
|
2020-01-28 18:09:29 +00:00
|
|
|
|
|
|
|
func TestMdsCommand(t *testing.T) {
|
|
|
|
mount := fsConnect(t)
|
|
|
|
|
|
|
|
cmd := []byte(`{"prefix": "client ls"}`)
|
|
|
|
buf, info, err := mount.MdsCommand(
|
|
|
|
"Z", // TODO: fix hard-coded name mds (from ci container script)
|
|
|
|
[][]byte{cmd})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.NotEqual(t, "", string(buf))
|
|
|
|
assert.Equal(t, "", string(info))
|
|
|
|
assert.Contains(t, string(buf), "ceph_version")
|
|
|
|
// response should also be valid json
|
|
|
|
var j []interface{}
|
|
|
|
err = json.Unmarshal(buf, &j)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.GreaterOrEqual(t, len(j), 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestMdsCommandError(t *testing.T) {
|
|
|
|
mount := fsConnect(t)
|
|
|
|
|
|
|
|
cmd := []byte("iAMinValId~~~")
|
|
|
|
buf, info, err := mount.MdsCommand(
|
|
|
|
"Z", // TODO: fix hard-coded name mds (from ci container script)
|
|
|
|
[][]byte{cmd})
|
|
|
|
assert.Error(t, err)
|
|
|
|
assert.Equal(t, "", string(buf))
|
|
|
|
assert.NotEqual(t, "", string(info))
|
|
|
|
assert.Contains(t, string(info), "unparseable JSON")
|
|
|
|
}
|