Repository: ceph/go-ceph
Pull request #184 (2020-02-16 19:17:48)

cephfs: add MountWithRoot to implement the root arg to ceph_mount
NOTE: This is based on the patches in PR #182. Please review/merge that first.

The existing Mount() method did not provide a way to access the root
path argument to ceph_mount. This new function allows the caller to
specify an alternate root dir for the mount.


## Checklist
- [x] Added tests for features and functional changes
- [x] Public functions and types are documented
- [x] Standard formatting is applied to Go code


phlogistonjohn: I missed that the ceph_get_fs_cid is new in nautilus. I need to conditional-ize that one. I'll fix that as well as the review comments and update soon.
phlogistonjohn: Updated.

Patch:
diff --git a/cephfs/cephfs.go b/cephfs/cephfs.go
index 40a71c1..9bfd2ea 100644
--- a/cephfs/cephfs.go
+++ b/cephfs/cephfs.go
@@ -91,6 +91,17 @@ func (mount *MountInfo) Mount() error {
 	return getError(ret)
 }
 
+// MountWithRoot mounts the file system using the path provided for the root of
+// the mount. This establishes a connection capable of I/O.
+//
+// Implements:
+//  int ceph_mount(struct ceph_mount_info *cmount, const char *root);
+func (mount *MountInfo) MountWithRoot(root string) error {
+	croot := C.CString(root)
+	defer C.free(unsafe.Pointer(croot))
+	return getError(C.ceph_mount(mount.mount, croot))
+}
+
 // Unmount the file system.
 //
 // Implements:
diff --git a/cephfs/conn_nautilus.go b/cephfs/conn_nautilus.go
new file mode 100644
index 0000000..13d1a65
--- /dev/null
+++ b/cephfs/conn_nautilus.go
@@ -0,0 +1,30 @@
+// +build !luminous,!mimic
+
+package cephfs
+
+/*
+#cgo LDFLAGS: -lcephfs
+#cgo CPPFLAGS: -D_FILE_OFFSET_BITS=64
+#include <cephfs/libcephfs.h>
+*/
+import "C"
+
+// Some general connectivity and mounting functions are new in
+// Ceph Nautilus.
+
+// GetFsCid returns the cluster ID for a mounted ceph file system.
+// If the object does not refer to a mounted file system, an error
+// will be returned.
+//
+// Note:
+//  Only supported in Ceph Nautilus and newer.
+//
+// Implements:
+//  int64_t ceph_get_fs_cid(struct ceph_mount_info *cmount);
+func (mount *MountInfo) GetFsCid() (int64, error) {
+	ret := C.ceph_get_fs_cid(mount.mount)
+	if ret < 0 {
+		return 0, getError(C.int(ret))
+	}
+	return int64(ret), nil
+}


Test patch:
diff --git a/cephfs/cephfs_test.go b/cephfs/cephfs_test.go
index 445d5c2..6d3bf72 100644
--- a/cephfs/cephfs_test.go
+++ b/cephfs/cephfs_test.go
@@ -276,3 +276,55 @@ func TestMdsCommandError(t *testing.T) {
 	assert.NotEqual(t, "", string(info))
 	assert.Contains(t, string(info), "unparseable JSON")
 }
+
+func TestMountWithRoot(t *testing.T) {
+	bMount := fsConnect(t)
+	defer func() {
+		assert.NoError(t, bMount.Unmount())
+		assert.NoError(t, bMount.Release())
+	}()
+
+	dir1 := "/test-mount-with-root"
+	err := bMount.MakeDir(dir1, 0755)
+	assert.NoError(t, err)
+	defer bMount.RemoveDir(dir1)
+
+	sub1 := "/i.was.here"
+	dir2 := dir1 + sub1
+	err = bMount.MakeDir(dir2, 0755)
+	assert.NoError(t, err)
+	defer bMount.RemoveDir(dir2)
+
+	t.Run("withRoot", func(t *testing.T) {
+		mount, err := CreateMount()
+		require.NoError(t, err)
+		require.NotNil(t, mount)
+		defer func() {
+			assert.NoError(t, mount.Unmount())
+			assert.NoError(t, mount.Release())
+		}()
+
+		err = mount.ReadDefaultConfigFile()
+		require.NoError(t, err)
+
+		err = mount.MountWithRoot(dir1)
+		assert.NoError(t, err)
+
+		err = mount.ChangeDir(sub1)
+		assert.NoError(t, err)
+	})
+	t.Run("badRoot", func(t *testing.T) {
+		mount, err := CreateMount()
+		require.NoError(t, err)
+		require.NotNil(t, mount)
+		defer func() {
+			assert.NoError(t, mount.Release())
+		}()
+
+		err = mount.ReadDefaultConfigFile()
+		require.NoError(t, err)
+
+		err = mount.MountWithRoot("/i-yam-what-i-yam")
+		assert.Error(t, err)
+	})
+}
diff --git a/cephfs/conn_nautilus_test.go b/cephfs/conn_nautilus_test.go
new file mode 100644
index 0000000..7277d45
--- /dev/null
+++ b/cephfs/conn_nautilus_test.go
@@ -0,0 +1,32 @@
+// +build !luminous,!mimic
+
+package cephfs
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+)
+
+func TestGetFsCid(t *testing.T) {
+	t.Run("unmounted", func(t *testing.T) {
+		mount, err := CreateMount()
+		require.NoError(t, err)
+		require.NotNil(t, mount)
+
+		err = mount.ReadDefaultConfigFile()
+		require.NoError(t, err)
+
+		cid, err := mount.GetFsCid()
+		assert.Error(t, err)
+		assert.Equal(t, cid, int64(0))
+	})
+	t.Run("mounted", func(t *testing.T) {
+		mount := fsConnect(t)
+
+		cid, err := mount.GetFsCid()
+		assert.NoError(t, err)
+		assert.GreaterOrEqual(t, cid, int64(0))
+	})
+}