2014-05-24 17:36:12 +00:00
|
|
|
package rados
|
|
|
|
|
|
|
|
// #cgo LDFLAGS: -lrados
|
|
|
|
// #include <stdlib.h>
|
|
|
|
// #include <rados/librados.h>
|
|
|
|
import "C"
|
|
|
|
|
2019-12-12 20:30:01 +00:00
|
|
|
import (
|
|
|
|
"unsafe"
|
2020-04-10 17:35:49 +00:00
|
|
|
|
2020-06-19 17:38:28 +00:00
|
|
|
"github.com/ceph/go-ceph/internal/cutil"
|
2020-04-10 17:35:49 +00:00
|
|
|
"github.com/ceph/go-ceph/internal/retry"
|
2019-12-12 20:30:01 +00:00
|
|
|
)
|
|
|
|
|
2020-06-11 18:34:09 +00:00
|
|
|
var argvPlaceholder = "placeholder"
|
|
|
|
|
2014-08-31 01:03:23 +00:00
|
|
|
// ClusterStat represents Ceph cluster statistics.
|
2014-05-26 19:43:44 +00:00
|
|
|
type ClusterStat struct {
|
2015-02-11 21:21:05 +00:00
|
|
|
Kb uint64
|
|
|
|
Kb_used uint64
|
|
|
|
Kb_avail uint64
|
|
|
|
Num_objects uint64
|
2014-05-26 19:43:44 +00:00
|
|
|
}
|
|
|
|
|
2014-08-31 01:03:23 +00:00
|
|
|
// Conn is a connection handle to a Ceph cluster.
|
2014-05-24 17:36:12 +00:00
|
|
|
type Conn struct {
|
2018-07-28 21:23:18 +00:00
|
|
|
cluster C.rados_t
|
|
|
|
connected bool
|
2014-05-24 17:36:12 +00:00
|
|
|
}
|
|
|
|
|
2019-12-18 22:25:37 +00:00
|
|
|
// ClusterRef represents a fundamental RADOS cluster connection.
|
|
|
|
type ClusterRef C.rados_t
|
|
|
|
|
|
|
|
// Cluster returns the underlying RADOS cluster reference for this Conn.
|
|
|
|
func (c *Conn) Cluster() ClusterRef {
|
|
|
|
return ClusterRef(c.cluster)
|
|
|
|
}
|
|
|
|
|
2014-08-30 17:29:17 +00:00
|
|
|
// PingMonitor sends a ping to a monitor and returns the reply.
|
2014-05-24 17:36:12 +00:00
|
|
|
func (c *Conn) PingMonitor(id string) (string, error) {
|
2021-06-21 20:12:42 +00:00
|
|
|
cid := C.CString(id)
|
|
|
|
defer C.free(unsafe.Pointer(cid))
|
2014-05-24 17:36:12 +00:00
|
|
|
|
2015-02-11 21:21:05 +00:00
|
|
|
var strlen C.size_t
|
|
|
|
var strout *C.char
|
2014-05-24 17:36:12 +00:00
|
|
|
|
2021-06-21 20:12:42 +00:00
|
|
|
ret := C.rados_ping_monitor(c.cluster, cid, &strout, &strlen)
|
2015-02-11 21:21:05 +00:00
|
|
|
defer C.rados_buffer_free(strout)
|
2014-05-24 17:36:12 +00:00
|
|
|
|
2015-02-11 21:21:05 +00:00
|
|
|
if ret == 0 {
|
|
|
|
reply := C.GoStringN(strout, (C.int)(strlen))
|
|
|
|
return reply, nil
|
|
|
|
}
|
2020-03-30 21:03:52 +00:00
|
|
|
return "", getError(ret)
|
2014-05-24 17:36:12 +00:00
|
|
|
}
|
|
|
|
|
2014-05-24 18:41:58 +00:00
|
|
|
// Connect establishes a connection to a RADOS cluster. It returns an error,
|
|
|
|
// if any.
|
2014-05-24 17:36:12 +00:00
|
|
|
func (c *Conn) Connect() error {
|
2015-02-11 21:21:05 +00:00
|
|
|
ret := C.rados_connect(c.cluster)
|
2018-10-06 21:35:07 +00:00
|
|
|
if ret != 0 {
|
2020-03-30 21:03:52 +00:00
|
|
|
return getError(ret)
|
2015-02-11 21:21:05 +00:00
|
|
|
}
|
2018-10-06 21:35:07 +00:00
|
|
|
c.connected = true
|
|
|
|
return nil
|
2014-05-24 17:36:12 +00:00
|
|
|
}
|
|
|
|
|
2014-08-30 17:29:17 +00:00
|
|
|
// Shutdown disconnects from the cluster.
|
2014-05-24 17:36:12 +00:00
|
|
|
func (c *Conn) Shutdown() {
|
2018-07-28 21:57:10 +00:00
|
|
|
if err := c.ensure_connected(); err != nil {
|
|
|
|
return
|
|
|
|
}
|
2019-11-26 09:52:37 +00:00
|
|
|
freeConn(c)
|
2014-05-24 17:36:12 +00:00
|
|
|
}
|
|
|
|
|
2014-08-30 17:29:17 +00:00
|
|
|
// ReadConfigFile configures the connection using a Ceph configuration file.
|
2014-05-24 17:36:12 +00:00
|
|
|
func (c *Conn) ReadConfigFile(path string) error {
|
2021-06-21 20:19:55 +00:00
|
|
|
cPath := C.CString(path)
|
|
|
|
defer C.free(unsafe.Pointer(cPath))
|
|
|
|
ret := C.rados_conf_read_file(c.cluster, cPath)
|
2020-03-30 20:57:54 +00:00
|
|
|
return getError(ret)
|
2014-05-24 17:36:12 +00:00
|
|
|
}
|
|
|
|
|
2014-08-30 17:29:17 +00:00
|
|
|
// ReadDefaultConfigFile configures the connection using a Ceph configuration
|
|
|
|
// file located at default locations.
|
2014-05-24 17:36:12 +00:00
|
|
|
func (c *Conn) ReadDefaultConfigFile() error {
|
2015-02-11 21:21:05 +00:00
|
|
|
ret := C.rados_conf_read_file(c.cluster, nil)
|
2020-03-30 20:57:54 +00:00
|
|
|
return getError(ret)
|
2014-05-24 17:36:12 +00:00
|
|
|
}
|
|
|
|
|
2020-01-22 17:27:31 +00:00
|
|
|
// OpenIOContext creates and returns a new IOContext for the given pool.
|
|
|
|
//
|
|
|
|
// Implements:
|
|
|
|
// int rados_ioctx_create(rados_t cluster, const char *pool_name,
|
|
|
|
// rados_ioctx_t *ioctx);
|
2015-01-09 19:33:02 +00:00
|
|
|
func (c *Conn) OpenIOContext(pool string) (*IOContext, error) {
|
2021-06-21 20:20:00 +00:00
|
|
|
cPool := C.CString(pool)
|
|
|
|
defer C.free(unsafe.Pointer(cPool))
|
2015-02-11 21:21:05 +00:00
|
|
|
ioctx := &IOContext{}
|
2021-06-21 20:20:00 +00:00
|
|
|
ret := C.rados_ioctx_create(c.cluster, cPool, &ioctx.ioctx)
|
2015-02-11 21:21:05 +00:00
|
|
|
if ret == 0 {
|
|
|
|
return ioctx, nil
|
|
|
|
}
|
2020-03-30 21:03:52 +00:00
|
|
|
return nil, getError(ret)
|
2014-05-24 17:36:12 +00:00
|
|
|
}
|
2014-05-26 17:53:30 +00:00
|
|
|
|
2014-08-30 17:29:17 +00:00
|
|
|
// ListPools returns the names of all existing pools.
|
2014-05-26 17:53:30 +00:00
|
|
|
func (c *Conn) ListPools() (names []string, err error) {
|
2015-02-11 21:21:05 +00:00
|
|
|
buf := make([]byte, 4096)
|
|
|
|
for {
|
2020-03-30 21:03:52 +00:00
|
|
|
ret := C.rados_pool_list(c.cluster,
|
|
|
|
(*C.char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf)))
|
2015-02-11 21:21:05 +00:00
|
|
|
if ret < 0 {
|
2020-03-30 21:03:52 +00:00
|
|
|
return nil, getError(ret)
|
2015-02-11 21:21:05 +00:00
|
|
|
}
|
|
|
|
|
2020-03-30 21:03:52 +00:00
|
|
|
if int(ret) > len(buf) {
|
2015-02-11 21:21:05 +00:00
|
|
|
buf = make([]byte, ret)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2020-06-19 17:38:28 +00:00
|
|
|
names = cutil.SplitSparseBuffer(buf[:ret])
|
2015-02-11 21:21:05 +00:00
|
|
|
return names, nil
|
|
|
|
}
|
2014-05-26 17:53:30 +00:00
|
|
|
}
|
2014-05-26 18:11:47 +00:00
|
|
|
|
2014-08-29 16:40:44 +00:00
|
|
|
// SetConfigOption sets the value of the configuration option identified by
|
|
|
|
// the given name.
|
2014-05-26 18:11:47 +00:00
|
|
|
func (c *Conn) SetConfigOption(option, value string) error {
|
2021-06-21 20:21:24 +00:00
|
|
|
cOpt, cVal := C.CString(option), C.CString(value)
|
|
|
|
defer C.free(unsafe.Pointer(cOpt))
|
|
|
|
defer C.free(unsafe.Pointer(cVal))
|
|
|
|
ret := C.rados_conf_set(c.cluster, cOpt, cVal)
|
2020-03-30 20:57:54 +00:00
|
|
|
return getError(ret)
|
2014-05-26 18:11:47 +00:00
|
|
|
}
|
2014-05-26 18:38:46 +00:00
|
|
|
|
2014-08-29 16:40:44 +00:00
|
|
|
// GetConfigOption returns the value of the Ceph configuration option
|
|
|
|
// identified by the given name.
|
2014-08-29 16:21:10 +00:00
|
|
|
func (c *Conn) GetConfigOption(name string) (value string, err error) {
|
2020-04-10 17:35:49 +00:00
|
|
|
cOption := C.CString(name)
|
|
|
|
defer C.free(unsafe.Pointer(cOption))
|
|
|
|
|
|
|
|
var buf []byte
|
|
|
|
// range from 4k to 256KiB
|
|
|
|
retry.WithSizes(4096, 1<<18, func(size int) retry.Hint {
|
|
|
|
buf = make([]byte, size)
|
|
|
|
ret := C.rados_conf_get(
|
|
|
|
c.cluster,
|
|
|
|
cOption,
|
|
|
|
(*C.char)(unsafe.Pointer(&buf[0])),
|
|
|
|
C.size_t(len(buf)))
|
|
|
|
err = getError(ret)
|
|
|
|
return retry.DoubleSize.If(err == errNameTooLong)
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
2015-02-11 21:21:05 +00:00
|
|
|
}
|
2020-04-10 17:35:49 +00:00
|
|
|
value = C.GoString((*C.char)(unsafe.Pointer(&buf[0])))
|
|
|
|
return value, nil
|
2014-08-29 16:21:10 +00:00
|
|
|
}
|
|
|
|
|
2014-05-26 18:38:46 +00:00
|
|
|
// WaitForLatestOSDMap blocks the caller until the latest OSD map has been
|
2014-08-29 16:40:44 +00:00
|
|
|
// retrieved.
|
2014-05-26 18:38:46 +00:00
|
|
|
func (c *Conn) WaitForLatestOSDMap() error {
|
2015-02-11 21:21:05 +00:00
|
|
|
ret := C.rados_wait_for_latest_osdmap(c.cluster)
|
2020-03-30 20:57:54 +00:00
|
|
|
return getError(ret)
|
2014-05-26 18:38:46 +00:00
|
|
|
}
|
2014-05-26 19:43:44 +00:00
|
|
|
|
2018-07-28 21:57:10 +00:00
|
|
|
func (c *Conn) ensure_connected() error {
|
|
|
|
if c.connected {
|
|
|
|
return nil
|
|
|
|
}
|
2019-12-20 18:43:51 +00:00
|
|
|
return ErrNotConnected
|
2018-07-28 21:57:10 +00:00
|
|
|
}
|
|
|
|
|
2019-03-06 03:14:57 +00:00
|
|
|
// GetClusterStats returns statistics about the cluster associated with the
|
2014-08-29 16:40:44 +00:00
|
|
|
// connection.
|
2014-05-26 19:43:44 +00:00
|
|
|
func (c *Conn) GetClusterStats() (stat ClusterStat, err error) {
|
2018-07-28 21:57:10 +00:00
|
|
|
if err := c.ensure_connected(); err != nil {
|
|
|
|
return ClusterStat{}, err
|
|
|
|
}
|
2015-02-11 21:21:05 +00:00
|
|
|
c_stat := C.struct_rados_cluster_stat_t{}
|
|
|
|
ret := C.rados_cluster_stat(c.cluster, &c_stat)
|
|
|
|
if ret < 0 {
|
2020-03-30 21:03:52 +00:00
|
|
|
return ClusterStat{}, getError(ret)
|
2015-02-11 21:21:05 +00:00
|
|
|
}
|
2019-12-20 18:43:51 +00:00
|
|
|
return ClusterStat{
|
|
|
|
Kb: uint64(c_stat.kb),
|
|
|
|
Kb_used: uint64(c_stat.kb_used),
|
|
|
|
Kb_avail: uint64(c_stat.kb_avail),
|
|
|
|
Num_objects: uint64(c_stat.num_objects),
|
|
|
|
}, nil
|
2014-05-26 19:43:44 +00:00
|
|
|
}
|
2014-05-28 03:12:17 +00:00
|
|
|
|
2020-06-11 18:34:09 +00:00
|
|
|
// ParseConfigArgv configures the connection using a unix style command line
|
|
|
|
// argument vector.
|
|
|
|
//
|
|
|
|
// Implements:
|
|
|
|
// int rados_conf_parse_argv(rados_t cluster, int argc,
|
|
|
|
// const char **argv);
|
|
|
|
func (c *Conn) ParseConfigArgv(argv []string) error {
|
|
|
|
if c.cluster == nil {
|
|
|
|
return ErrNotConnected
|
|
|
|
}
|
|
|
|
if len(argv) == 0 {
|
|
|
|
return ErrEmptyArgument
|
|
|
|
}
|
|
|
|
cargv := make([]*C.char, len(argv))
|
|
|
|
for i := range argv {
|
|
|
|
cargv[i] = C.CString(argv[i])
|
|
|
|
defer C.free(unsafe.Pointer(cargv[i]))
|
2015-02-11 21:21:05 +00:00
|
|
|
}
|
|
|
|
|
2020-06-11 18:34:09 +00:00
|
|
|
ret := C.rados_conf_parse_argv(c.cluster, C.int(len(cargv)), &cargv[0])
|
2020-03-30 20:57:54 +00:00
|
|
|
return getError(ret)
|
2014-05-28 03:12:17 +00:00
|
|
|
}
|
2014-08-29 16:21:10 +00:00
|
|
|
|
2020-06-11 18:34:09 +00:00
|
|
|
// ParseCmdLineArgs configures the connection from command line arguments.
|
|
|
|
//
|
|
|
|
// This function passes a placeholder value to Ceph as argv[0], see
|
|
|
|
// ParseConfigArgv for a version of this function that allows the caller to
|
|
|
|
// specify argv[0].
|
|
|
|
func (c *Conn) ParseCmdLineArgs(args []string) error {
|
|
|
|
argv := make([]string, len(args)+1)
|
|
|
|
// Ceph expects a proper argv array as the actual contents with the
|
|
|
|
// first element containing the executable name
|
|
|
|
argv[0] = argvPlaceholder
|
|
|
|
for i := range args {
|
|
|
|
argv[i+1] = args[i]
|
|
|
|
}
|
|
|
|
return c.ParseConfigArgv(argv)
|
|
|
|
}
|
|
|
|
|
2014-08-29 16:40:44 +00:00
|
|
|
// ParseDefaultConfigEnv configures the connection from the default Ceph
|
2020-06-11 18:41:42 +00:00
|
|
|
// environment variable CEPH_ARGS.
|
2014-08-29 16:21:10 +00:00
|
|
|
func (c *Conn) ParseDefaultConfigEnv() error {
|
2015-02-11 21:21:05 +00:00
|
|
|
ret := C.rados_conf_parse_env(c.cluster, nil)
|
2020-03-30 20:57:54 +00:00
|
|
|
return getError(ret)
|
2014-08-29 16:21:10 +00:00
|
|
|
}
|
2014-08-29 22:56:17 +00:00
|
|
|
|
|
|
|
// GetFSID returns the fsid of the cluster as a hexadecimal string. The fsid
|
|
|
|
// is a unique identifier of an entire Ceph cluster.
|
|
|
|
func (c *Conn) GetFSID() (fsid string, err error) {
|
2015-02-11 21:21:05 +00:00
|
|
|
buf := make([]byte, 37)
|
2020-03-30 21:03:52 +00:00
|
|
|
ret := C.rados_cluster_fsid(c.cluster,
|
|
|
|
(*C.char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf)))
|
2015-02-11 21:21:05 +00:00
|
|
|
// FIXME: the success case isn't documented correctly in librados.h
|
|
|
|
if ret == 36 {
|
|
|
|
fsid = C.GoString((*C.char)(unsafe.Pointer(&buf[0])))
|
|
|
|
return fsid, nil
|
|
|
|
}
|
2020-03-30 21:03:52 +00:00
|
|
|
return "", getError(ret)
|
2014-08-29 22:56:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetInstanceID returns a globally unique identifier for the cluster
|
|
|
|
// connection instance.
|
|
|
|
func (c *Conn) GetInstanceID() uint64 {
|
2015-02-11 21:21:05 +00:00
|
|
|
// FIXME: are there any error cases for this?
|
|
|
|
return uint64(C.rados_get_instance_id(c.cluster))
|
2014-08-29 22:56:17 +00:00
|
|
|
}
|
2014-08-30 17:28:24 +00:00
|
|
|
|
|
|
|
// MakePool creates a new pool with default settings.
|
|
|
|
func (c *Conn) MakePool(name string) error {
|
2021-06-21 20:14:25 +00:00
|
|
|
cName := C.CString(name)
|
|
|
|
defer C.free(unsafe.Pointer(cName))
|
|
|
|
ret := C.rados_pool_create(c.cluster, cName)
|
2020-03-30 20:57:54 +00:00
|
|
|
return getError(ret)
|
2014-08-30 17:28:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// DeletePool deletes a pool and all the data inside the pool.
|
|
|
|
func (c *Conn) DeletePool(name string) error {
|
2018-07-28 21:57:10 +00:00
|
|
|
if err := c.ensure_connected(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-06-21 20:14:25 +00:00
|
|
|
cName := C.CString(name)
|
|
|
|
defer C.free(unsafe.Pointer(cName))
|
|
|
|
ret := C.rados_pool_delete(c.cluster, cName)
|
2020-03-30 20:57:54 +00:00
|
|
|
return getError(ret)
|
2014-08-30 17:28:24 +00:00
|
|
|
}
|
2015-02-10 20:13:56 +00:00
|
|
|
|
2019-10-14 12:09:30 +00:00
|
|
|
// GetPoolByName returns the ID of the pool with a given name.
|
|
|
|
func (c *Conn) GetPoolByName(name string) (int64, error) {
|
|
|
|
if err := c.ensure_connected(); err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
2021-06-21 20:14:25 +00:00
|
|
|
cName := C.CString(name)
|
|
|
|
defer C.free(unsafe.Pointer(cName))
|
|
|
|
ret := int64(C.rados_pool_lookup(c.cluster, cName))
|
2019-10-14 12:09:30 +00:00
|
|
|
if ret < 0 {
|
2020-07-13 23:51:20 +00:00
|
|
|
return 0, radosError(ret)
|
2019-10-14 12:09:30 +00:00
|
|
|
}
|
2019-12-20 18:43:51 +00:00
|
|
|
return ret, nil
|
2019-10-14 12:09:30 +00:00
|
|
|
}
|
|
|
|
|
2019-10-14 15:38:52 +00:00
|
|
|
// GetPoolByID returns the name of a pool by a given ID.
|
|
|
|
func (c *Conn) GetPoolByID(id int64) (string, error) {
|
|
|
|
buf := make([]byte, 4096)
|
|
|
|
if err := c.ensure_connected(); err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
2021-06-21 20:12:42 +00:00
|
|
|
cid := C.int64_t(id)
|
|
|
|
ret := int(C.rados_pool_reverse_lookup(c.cluster, cid, (*C.char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf))))
|
2019-10-14 15:38:52 +00:00
|
|
|
if ret < 0 {
|
2020-07-13 23:51:20 +00:00
|
|
|
return "", radosError(ret)
|
2019-10-14 15:38:52 +00:00
|
|
|
}
|
2019-12-20 18:43:51 +00:00
|
|
|
return C.GoString((*C.char)(unsafe.Pointer(&buf[0]))), nil
|
2019-10-14 15:38:52 +00:00
|
|
|
}
|