dep: add github.com/ceph/go-ceph for rbd API

Signed-off-by: Niels de Vos <ndevos@redhat.com>
This commit is contained in:
Niels de Vos 2020-01-07 14:30:27 +01:00 committed by mergify[bot]
parent 3226b17d08
commit ba99275f90
17 changed files with 3444 additions and 1 deletions

14
Gopkg.lock generated
View File

@ -25,6 +25,18 @@
revision = "ba2c2ddd89069b46a7011d4106f6868f17ee1705" revision = "ba2c2ddd89069b46a7011d4106f6868f17ee1705"
version = "v3.6.1" version = "v3.6.1"
[[projects]]
digest = "1:286a840b63ddce8e6f85368e22a834aefcaaf23f18a58ce01a42d7a978d21baf"
name = "github.com/ceph/go-ceph"
packages = [
"errutil",
"rados",
"rbd",
]
pruneopts = "NUT"
revision = "dc289754c8976f8cca2eb47dbea81895a4cac872"
version = "v0.2.0"
[[projects]] [[projects]]
digest = "1:7f21fa1f8ab9a529dba26a7e9cf20de217c307fa1d96cb599d3afd9e5c83e9d6" digest = "1:7f21fa1f8ab9a529dba26a7e9cf20de217c307fa1d96cb599d3afd9e5c83e9d6"
name = "github.com/container-storage-interface/spec" name = "github.com/container-storage-interface/spec"
@ -1331,6 +1343,8 @@
analyzer-name = "dep" analyzer-name = "dep"
analyzer-version = 1 analyzer-version = 1
input-imports = [ input-imports = [
"github.com/ceph/go-ceph/rados",
"github.com/ceph/go-ceph/rbd",
"github.com/container-storage-interface/spec/lib/go/csi", "github.com/container-storage-interface/spec/lib/go/csi",
"github.com/golang/protobuf/ptypes", "github.com/golang/protobuf/ptypes",
"github.com/golang/protobuf/ptypes/timestamp", "github.com/golang/protobuf/ptypes/timestamp",

View File

@ -75,6 +75,10 @@
branch = "master" branch = "master"
name = "k8s.io/utils" name = "k8s.io/utils"
[[constraint]]
name = "github.com/ceph/go-ceph"
version = "0.2"
[prune] [prune]
go-tests = true go-tests = true
non-go = true non-go = true
@ -84,4 +88,3 @@
[[prune.project]] [[prune.project]]
name = "github.com/kubernetes-csi/external-snapshotter" name = "github.com/kubernetes-csi/external-snapshotter"
non-go = false non-go = false

21
vendor/github.com/ceph/go-ceph/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Noah Watkins
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

45
vendor/github.com/ceph/go-ceph/errutil/strerror.go generated vendored Normal file
View File

@ -0,0 +1,45 @@
/*
Package errutil provides common functions for dealing with error conditions for
all ceph api wrappers.
*/
package errutil
/* force XSI-complaint strerror_r() */
// #define _POSIX_C_SOURCE 200112L
// #undef _GNU_SOURCE
// #include <stdlib.h>
// #include <errno.h>
// #include <string.h>
import "C"
import (
"unsafe"
)
// FormatErrno returns the absolute value of the errno as well as a string
// describing the errno. The string will be empty is the errno is not known.
func FormatErrno(errno int) (int, string) {
buf := make([]byte, 1024)
// strerror expects errno >= 0
if errno < 0 {
errno = -errno
}
ret := C.strerror_r(
C.int(errno),
(*C.char)(unsafe.Pointer(&buf[0])),
C.size_t(len(buf)))
if ret != 0 {
return errno, ""
}
return errno, C.GoString((*C.char)(unsafe.Pointer(&buf[0])))
}
// StrError returns a string describing the errno. The string will be empty if
// the errno is not known.
func StrError(errno int) string {
_, s := FormatErrno(errno)
return s
}

408
vendor/github.com/ceph/go-ceph/rados/conn.go generated vendored Normal file
View File

@ -0,0 +1,408 @@
package rados
// #cgo LDFLAGS: -lrados
// #include <stdlib.h>
// #include <rados/librados.h>
import "C"
import (
"bytes"
"errors"
"unsafe"
)
var (
// ErrNotConnected is returned when functions are called without a RADOS connection
ErrNotConnected = errors.New("RADOS not connected")
)
// ClusterStat represents Ceph cluster statistics.
type ClusterStat struct {
Kb uint64
Kb_used uint64
Kb_avail uint64
Num_objects uint64
}
// Conn is a connection handle to a Ceph cluster.
type Conn struct {
cluster C.rados_t
connected bool
}
// 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)
}
// PingMonitor sends a ping to a monitor and returns the reply.
func (c *Conn) PingMonitor(id string) (string, error) {
c_id := C.CString(id)
defer C.free(unsafe.Pointer(c_id))
var strlen C.size_t
var strout *C.char
ret := C.rados_ping_monitor(c.cluster, c_id, &strout, &strlen)
defer C.rados_buffer_free(strout)
if ret == 0 {
reply := C.GoStringN(strout, (C.int)(strlen))
return reply, nil
}
return "", RadosError(int(ret))
}
// Connect establishes a connection to a RADOS cluster. It returns an error,
// if any.
func (c *Conn) Connect() error {
ret := C.rados_connect(c.cluster)
if ret != 0 {
return RadosError(int(ret))
}
c.connected = true
return nil
}
// Shutdown disconnects from the cluster.
func (c *Conn) Shutdown() {
if err := c.ensure_connected(); err != nil {
return
}
freeConn(c)
}
// ReadConfigFile configures the connection using a Ceph configuration file.
func (c *Conn) ReadConfigFile(path string) error {
c_path := C.CString(path)
defer C.free(unsafe.Pointer(c_path))
ret := C.rados_conf_read_file(c.cluster, c_path)
return getRadosError(int(ret))
}
// ReadDefaultConfigFile configures the connection using a Ceph configuration
// file located at default locations.
func (c *Conn) ReadDefaultConfigFile() error {
ret := C.rados_conf_read_file(c.cluster, nil)
return getRadosError(int(ret))
}
// 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);
func (c *Conn) OpenIOContext(pool string) (*IOContext, error) {
c_pool := C.CString(pool)
defer C.free(unsafe.Pointer(c_pool))
ioctx := &IOContext{}
ret := C.rados_ioctx_create(c.cluster, c_pool, &ioctx.ioctx)
if ret == 0 {
return ioctx, nil
}
return nil, RadosError(int(ret))
}
// ListPools returns the names of all existing pools.
func (c *Conn) ListPools() (names []string, err error) {
buf := make([]byte, 4096)
for {
ret := int(C.rados_pool_list(c.cluster,
(*C.char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf))))
if ret < 0 {
return nil, RadosError(int(ret))
}
if ret > len(buf) {
buf = make([]byte, ret)
continue
}
tmp := bytes.SplitAfter(buf[:ret-1], []byte{0})
for _, s := range tmp {
if len(s) > 0 {
name := C.GoString((*C.char)(unsafe.Pointer(&s[0])))
names = append(names, name)
}
}
return names, nil
}
}
// SetConfigOption sets the value of the configuration option identified by
// the given name.
func (c *Conn) SetConfigOption(option, value string) error {
c_opt, c_val := C.CString(option), C.CString(value)
defer C.free(unsafe.Pointer(c_opt))
defer C.free(unsafe.Pointer(c_val))
ret := C.rados_conf_set(c.cluster, c_opt, c_val)
return getRadosError(int(ret))
}
// GetConfigOption returns the value of the Ceph configuration option
// identified by the given name.
func (c *Conn) GetConfigOption(name string) (value string, err error) {
buf := make([]byte, 4096)
c_name := C.CString(name)
defer C.free(unsafe.Pointer(c_name))
ret := int(C.rados_conf_get(c.cluster, c_name,
(*C.char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf))))
// FIXME: ret may be -ENAMETOOLONG if the buffer is not large enough. We
// can handle this case, but we need a reliable way to test for
// -ENAMETOOLONG constant. Will the syscall/Errno stuff in Go help?
if ret == 0 {
value = C.GoString((*C.char)(unsafe.Pointer(&buf[0])))
return value, nil
}
return "", RadosError(ret)
}
// WaitForLatestOSDMap blocks the caller until the latest OSD map has been
// retrieved.
func (c *Conn) WaitForLatestOSDMap() error {
ret := C.rados_wait_for_latest_osdmap(c.cluster)
return getRadosError(int(ret))
}
func (c *Conn) ensure_connected() error {
if c.connected {
return nil
}
return ErrNotConnected
}
// GetClusterStats returns statistics about the cluster associated with the
// connection.
func (c *Conn) GetClusterStats() (stat ClusterStat, err error) {
if err := c.ensure_connected(); err != nil {
return ClusterStat{}, err
}
c_stat := C.struct_rados_cluster_stat_t{}
ret := C.rados_cluster_stat(c.cluster, &c_stat)
if ret < 0 {
return ClusterStat{}, RadosError(int(ret))
}
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
}
// ParseCmdLineArgs configures the connection from command line arguments.
func (c *Conn) ParseCmdLineArgs(args []string) error {
// add an empty element 0 -- Ceph treats the array as the actual contents
// of argv and skips the first element (the executable name)
argc := C.int(len(args) + 1)
argv := make([]*C.char, argc)
// make the first element a string just in case it is ever examined
argv[0] = C.CString("placeholder")
defer C.free(unsafe.Pointer(argv[0]))
for i, arg := range args {
argv[i+1] = C.CString(arg)
defer C.free(unsafe.Pointer(argv[i+1]))
}
ret := C.rados_conf_parse_argv(c.cluster, argc, &argv[0])
return getRadosError(int(ret))
}
// ParseDefaultConfigEnv configures the connection from the default Ceph
// environment variable(s).
func (c *Conn) ParseDefaultConfigEnv() error {
ret := C.rados_conf_parse_env(c.cluster, nil)
return getRadosError(int(ret))
}
// 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) {
buf := make([]byte, 37)
ret := int(C.rados_cluster_fsid(c.cluster,
(*C.char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf))))
// 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
}
return "", RadosError(int(ret))
}
// GetInstanceID returns a globally unique identifier for the cluster
// connection instance.
func (c *Conn) GetInstanceID() uint64 {
// FIXME: are there any error cases for this?
return uint64(C.rados_get_instance_id(c.cluster))
}
// MakePool creates a new pool with default settings.
func (c *Conn) MakePool(name string) error {
c_name := C.CString(name)
defer C.free(unsafe.Pointer(c_name))
ret := int(C.rados_pool_create(c.cluster, c_name))
return getRadosError(int(ret))
}
// DeletePool deletes a pool and all the data inside the pool.
func (c *Conn) DeletePool(name string) error {
if err := c.ensure_connected(); err != nil {
return err
}
c_name := C.CString(name)
defer C.free(unsafe.Pointer(c_name))
ret := int(C.rados_pool_delete(c.cluster, c_name))
return getRadosError(int(ret))
}
// 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
}
c_name := C.CString(name)
defer C.free(unsafe.Pointer(c_name))
ret := int64(C.rados_pool_lookup(c.cluster, c_name))
if ret < 0 {
return 0, RadosError(ret)
}
return ret, nil
}
// 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
}
c_id := C.int64_t(id)
ret := int(C.rados_pool_reverse_lookup(c.cluster, c_id, (*C.char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf))))
if ret < 0 {
return "", RadosError(ret)
}
return C.GoString((*C.char)(unsafe.Pointer(&buf[0]))), nil
}
// MonCommand sends a command to one of the monitors
func (c *Conn) MonCommand(args []byte) (buffer []byte, info string, err error) {
return c.monCommand(args, nil)
}
// MonCommandWithInputBuffer sends a command to one of the monitors, with an input buffer
func (c *Conn) MonCommandWithInputBuffer(args, inputBuffer []byte) (buffer []byte, info string, err error) {
return c.monCommand(args, inputBuffer)
}
func (c *Conn) monCommand(args, inputBuffer []byte) (buffer []byte, info string, err error) {
argv := C.CString(string(args))
defer C.free(unsafe.Pointer(argv))
var (
outs, outbuf *C.char
outslen, outbuflen C.size_t
)
inbuf := C.CString(string(inputBuffer))
inbufLen := len(inputBuffer)
defer C.free(unsafe.Pointer(inbuf))
ret := C.rados_mon_command(c.cluster,
&argv, 1,
inbuf, // bulk input (e.g. crush map)
C.size_t(inbufLen), // length inbuf
&outbuf, // buffer
&outbuflen, // buffer length
&outs, // status string
&outslen)
if outslen > 0 {
info = C.GoStringN(outs, C.int(outslen))
C.free(unsafe.Pointer(outs))
}
if outbuflen > 0 {
buffer = C.GoBytes(unsafe.Pointer(outbuf), C.int(outbuflen))
C.free(unsafe.Pointer(outbuf))
}
if ret != 0 {
err = RadosError(int(ret))
return nil, info, err
}
return
}
// PGCommand sends a command to one of the PGs
//
// Implements:
// int rados_pg_command(rados_t cluster, const char *pgstr,
// const char **cmd, size_t cmdlen,
// const char *inbuf, size_t inbuflen,
// char **outbuf, size_t *outbuflen,
// char **outs, size_t *outslen);
func (c *Conn) PGCommand(pgid []byte, args [][]byte) (buffer []byte, info string, err error) {
return c.pgCommand(pgid, args, nil)
}
// PGCommandWithInputBuffer sends a command to one of the PGs, with an input buffer
//
// Implements:
// int rados_pg_command(rados_t cluster, const char *pgstr,
// const char **cmd, size_t cmdlen,
// const char *inbuf, size_t inbuflen,
// char **outbuf, size_t *outbuflen,
// char **outs, size_t *outslen);
func (c *Conn) PGCommandWithInputBuffer(pgid []byte, args [][]byte, inputBuffer []byte) (buffer []byte, info string, err error) {
return c.pgCommand(pgid, args, inputBuffer)
}
func (c *Conn) pgCommand(pgid []byte, args [][]byte, inputBuffer []byte) (buffer []byte, info string, err error) {
name := C.CString(string(pgid))
defer C.free(unsafe.Pointer(name))
argc := len(args)
argv := make([]*C.char, argc)
for i, arg := range args {
argv[i] = C.CString(string(arg))
defer C.free(unsafe.Pointer(argv[i]))
}
var (
outs, outbuf *C.char
outslen, outbuflen C.size_t
)
inbuf := C.CString(string(inputBuffer))
inbufLen := len(inputBuffer)
defer C.free(unsafe.Pointer(inbuf))
ret := C.rados_pg_command(c.cluster,
name,
&argv[0],
C.size_t(argc),
inbuf, // bulk input
C.size_t(inbufLen), // length inbuf
&outbuf, // buffer
&outbuflen, // buffer length
&outs, // status string
&outslen)
if outslen > 0 {
info = C.GoStringN(outs, C.int(outslen))
C.free(unsafe.Pointer(outs))
}
if outbuflen > 0 {
buffer = C.GoBytes(unsafe.Pointer(outbuf), C.int(outbuflen))
C.free(unsafe.Pointer(outbuf))
}
if ret != 0 {
err = RadosError(int(ret))
return nil, info, err
}
return
}

4
vendor/github.com/ceph/go-ceph/rados/doc.go generated vendored Normal file
View File

@ -0,0 +1,4 @@
/*
Package rados contains a set of wrappers around Ceph's librados API.
*/
package rados

622
vendor/github.com/ceph/go-ceph/rados/ioctx.go generated vendored Normal file
View File

@ -0,0 +1,622 @@
package rados
// #cgo LDFLAGS: -lrados
// #include <errno.h>
// #include <stdlib.h>
// #include <rados/librados.h>
//
// char* nextChunk(char **idx) {
// char *copy;
// copy = strdup(*idx);
// *idx += strlen(*idx) + 1;
// return copy;
// }
//
// #if __APPLE__
// #define ceph_time_t __darwin_time_t
// #define ceph_suseconds_t __darwin_suseconds_t
// #elif __GLIBC__
// #define ceph_time_t __time_t
// #define ceph_suseconds_t __suseconds_t
// #else
// #define ceph_time_t time_t
// #define ceph_suseconds_t suseconds_t
// #endif
import "C"
import (
"syscall"
"time"
"unsafe"
)
// CreateOption is passed to IOContext.Create() and should be one of
// CreateExclusive or CreateIdempotent.
type CreateOption int
const (
// CreateExclusive if used with IOContext.Create() and the object
// already exists, the function will return an error.
CreateExclusive = C.LIBRADOS_CREATE_EXCLUSIVE
// CreateIdempotent if used with IOContext.Create() and the object
// already exists, the function will not return an error.
CreateIdempotent = C.LIBRADOS_CREATE_IDEMPOTENT
)
// PoolStat represents Ceph pool statistics.
type PoolStat struct {
// space used in bytes
Num_bytes uint64
// space used in KB
Num_kb uint64
// number of objects in the pool
Num_objects uint64
// number of clones of objects
Num_object_clones uint64
// num_objects * num_replicas
Num_object_copies uint64
Num_objects_missing_on_primary uint64
// number of objects found on no OSDs
Num_objects_unfound uint64
// number of objects replicated fewer times than they should be
// (but found on at least one OSD)
Num_objects_degraded uint64
Num_rd uint64
Num_rd_kb uint64
Num_wr uint64
Num_wr_kb uint64
}
// ObjectStat represents an object stat information
type ObjectStat struct {
// current length in bytes
Size uint64
// last modification time
ModTime time.Time
}
// LockInfo represents information on a current Ceph lock
type LockInfo struct {
NumLockers int
Exclusive bool
Tag string
Clients []string
Cookies []string
Addrs []string
}
// IOContext represents a context for performing I/O within a pool.
type IOContext struct {
ioctx C.rados_ioctx_t
}
// Pointer returns a uintptr representation of the IOContext.
func (ioctx *IOContext) Pointer() uintptr {
return uintptr(ioctx.ioctx)
}
// SetNamespace sets the namespace for objects within this IO context (pool).
// Setting namespace to a empty or zero length string sets the pool to the default namespace.
func (ioctx *IOContext) SetNamespace(namespace string) {
var c_ns *C.char
if len(namespace) > 0 {
c_ns = C.CString(namespace)
defer C.free(unsafe.Pointer(c_ns))
}
C.rados_ioctx_set_namespace(ioctx.ioctx, c_ns)
}
// Create a new object with key oid.
//
// Implements:
// void rados_write_op_create(rados_write_op_t write_op, int exclusive,
// const char* category)
func (ioctx *IOContext) Create(oid string, exclusive CreateOption) error {
c_oid := C.CString(oid)
defer C.free(unsafe.Pointer(c_oid))
op := C.rados_create_write_op()
C.rados_write_op_create(op, C.int(exclusive), nil)
ret := C.rados_write_op_operate(op, ioctx.ioctx, c_oid, nil, 0)
C.rados_release_write_op(op)
return getRadosError(int(ret))
}
// Write writes len(data) bytes to the object with key oid starting at byte
// offset offset. It returns an error, if any.
func (ioctx *IOContext) Write(oid string, data []byte, offset uint64) error {
c_oid := C.CString(oid)
defer C.free(unsafe.Pointer(c_oid))
dataPointer := unsafe.Pointer(nil)
if len(data) > 0 {
dataPointer = unsafe.Pointer(&data[0])
}
ret := C.rados_write(ioctx.ioctx, c_oid,
(*C.char)(dataPointer),
(C.size_t)(len(data)),
(C.uint64_t)(offset))
return getRadosError(int(ret))
}
// WriteFull writes len(data) bytes to the object with key oid.
// The object is filled with the provided data. If the object exists,
// it is atomically truncated and then written. It returns an error, if any.
func (ioctx *IOContext) WriteFull(oid string, data []byte) error {
c_oid := C.CString(oid)
defer C.free(unsafe.Pointer(c_oid))
ret := C.rados_write_full(ioctx.ioctx, c_oid,
(*C.char)(unsafe.Pointer(&data[0])),
(C.size_t)(len(data)))
return getRadosError(int(ret))
}
// Append appends len(data) bytes to the object with key oid.
// The object is appended with the provided data. If the object exists,
// it is atomically appended to. It returns an error, if any.
func (ioctx *IOContext) Append(oid string, data []byte) error {
c_oid := C.CString(oid)
defer C.free(unsafe.Pointer(c_oid))
ret := C.rados_append(ioctx.ioctx, c_oid,
(*C.char)(unsafe.Pointer(&data[0])),
(C.size_t)(len(data)))
return getRadosError(int(ret))
}
// Read reads up to len(data) bytes from the object with key oid starting at byte
// offset offset. It returns the number of bytes read and an error, if any.
func (ioctx *IOContext) Read(oid string, data []byte, offset uint64) (int, error) {
c_oid := C.CString(oid)
defer C.free(unsafe.Pointer(c_oid))
var buf *C.char
if len(data) > 0 {
buf = (*C.char)(unsafe.Pointer(&data[0]))
}
ret := C.rados_read(
ioctx.ioctx,
c_oid,
buf,
(C.size_t)(len(data)),
(C.uint64_t)(offset))
if ret >= 0 {
return int(ret), nil
}
return 0, getRadosError(int(ret))
}
// Delete deletes the object with key oid. It returns an error, if any.
func (ioctx *IOContext) Delete(oid string) error {
c_oid := C.CString(oid)
defer C.free(unsafe.Pointer(c_oid))
return getRadosError(int(C.rados_remove(ioctx.ioctx, c_oid)))
}
// Truncate resizes the object with key oid to size size. If the operation
// enlarges the object, the new area is logically filled with zeroes. If the
// operation shrinks the object, the excess data is removed. It returns an
// error, if any.
func (ioctx *IOContext) Truncate(oid string, size uint64) error {
c_oid := C.CString(oid)
defer C.free(unsafe.Pointer(c_oid))
return getRadosError(int(C.rados_trunc(ioctx.ioctx, c_oid, (C.uint64_t)(size))))
}
// Destroy informs librados that the I/O context is no longer in use.
// Resources associated with the context may not be freed immediately, and the
// context should not be used again after calling this method.
func (ioctx *IOContext) Destroy() {
C.rados_ioctx_destroy(ioctx.ioctx)
}
// GetPoolStats returns a set of statistics about the pool associated with this I/O
// context.
//
// Implements:
// int rados_ioctx_pool_stat(rados_ioctx_t io,
// struct rados_pool_stat_t *stats);
func (ioctx *IOContext) GetPoolStats() (stat PoolStat, err error) {
c_stat := C.struct_rados_pool_stat_t{}
ret := C.rados_ioctx_pool_stat(ioctx.ioctx, &c_stat)
if ret < 0 {
return PoolStat{}, getRadosError(int(ret))
}
return PoolStat{
Num_bytes: uint64(c_stat.num_bytes),
Num_kb: uint64(c_stat.num_kb),
Num_objects: uint64(c_stat.num_objects),
Num_object_clones: uint64(c_stat.num_object_clones),
Num_object_copies: uint64(c_stat.num_object_copies),
Num_objects_missing_on_primary: uint64(c_stat.num_objects_missing_on_primary),
Num_objects_unfound: uint64(c_stat.num_objects_unfound),
Num_objects_degraded: uint64(c_stat.num_objects_degraded),
Num_rd: uint64(c_stat.num_rd),
Num_rd_kb: uint64(c_stat.num_rd_kb),
Num_wr: uint64(c_stat.num_wr),
Num_wr_kb: uint64(c_stat.num_wr_kb),
}, nil
}
// GetPoolName returns the name of the pool associated with the I/O context.
func (ioctx *IOContext) GetPoolName() (name string, err error) {
buf := make([]byte, 128)
for {
ret := C.rados_ioctx_get_pool_name(ioctx.ioctx,
(*C.char)(unsafe.Pointer(&buf[0])), C.unsigned(len(buf)))
if ret == -C.ERANGE {
buf = make([]byte, len(buf)*2)
continue
} else if ret < 0 {
return "", getRadosError(int(ret))
}
name = C.GoStringN((*C.char)(unsafe.Pointer(&buf[0])), ret)
return name, nil
}
}
// ObjectListFunc is the type of the function called for each object visited
// by ListObjects.
type ObjectListFunc func(oid string)
// ListObjects lists all of the objects in the pool associated with the I/O
// context, and called the provided listFn function for each object, passing
// to the function the name of the object. Call SetNamespace with
// RadosAllNamespaces before calling this function to return objects from all
// namespaces
func (ioctx *IOContext) ListObjects(listFn ObjectListFunc) error {
var ctx C.rados_list_ctx_t
ret := C.rados_nobjects_list_open(ioctx.ioctx, &ctx)
if ret < 0 {
return getRadosError(int(ret))
}
defer func() { C.rados_nobjects_list_close(ctx) }()
for {
var c_entry *C.char
ret := C.rados_nobjects_list_next(ctx, &c_entry, nil, nil)
if ret == -C.ENOENT {
return nil
} else if ret < 0 {
return getRadosError(int(ret))
}
listFn(C.GoString(c_entry))
}
}
// Stat returns the size of the object and its last modification time
func (ioctx *IOContext) Stat(object string) (stat ObjectStat, err error) {
var c_psize C.uint64_t
var c_pmtime C.time_t
c_object := C.CString(object)
defer C.free(unsafe.Pointer(c_object))
ret := C.rados_stat(
ioctx.ioctx,
c_object,
&c_psize,
&c_pmtime)
if ret < 0 {
return ObjectStat{}, getRadosError(int(ret))
}
return ObjectStat{
Size: uint64(c_psize),
ModTime: time.Unix(int64(c_pmtime), 0),
}, nil
}
// GetXattr gets an xattr with key `name`, it returns the length of
// the key read or an error if not successful
func (ioctx *IOContext) GetXattr(object string, name string, data []byte) (int, error) {
c_object := C.CString(object)
c_name := C.CString(name)
defer C.free(unsafe.Pointer(c_object))
defer C.free(unsafe.Pointer(c_name))
ret := C.rados_getxattr(
ioctx.ioctx,
c_object,
c_name,
(*C.char)(unsafe.Pointer(&data[0])),
(C.size_t)(len(data)))
if ret >= 0 {
return int(ret), nil
}
return 0, getRadosError(int(ret))
}
// SetXattr sets an xattr for an object with key `name` with value as `data`
func (ioctx *IOContext) SetXattr(object string, name string, data []byte) error {
c_object := C.CString(object)
c_name := C.CString(name)
defer C.free(unsafe.Pointer(c_object))
defer C.free(unsafe.Pointer(c_name))
ret := C.rados_setxattr(
ioctx.ioctx,
c_object,
c_name,
(*C.char)(unsafe.Pointer(&data[0])),
(C.size_t)(len(data)))
return getRadosError(int(ret))
}
// ListXattrs lists all the xattrs for an object. The xattrs are returned as a
// mapping of string keys and byte-slice values.
func (ioctx *IOContext) ListXattrs(oid string) (map[string][]byte, error) {
c_oid := C.CString(oid)
defer C.free(unsafe.Pointer(c_oid))
var it C.rados_xattrs_iter_t
ret := C.rados_getxattrs(ioctx.ioctx, c_oid, &it)
if ret < 0 {
return nil, getRadosError(int(ret))
}
defer func() { C.rados_getxattrs_end(it) }()
m := make(map[string][]byte)
for {
var c_name, c_val *C.char
var c_len C.size_t
defer C.free(unsafe.Pointer(c_name))
defer C.free(unsafe.Pointer(c_val))
ret := C.rados_getxattrs_next(it, &c_name, &c_val, &c_len)
if ret < 0 {
return nil, getRadosError(int(ret))
}
// rados api returns a null name,val & 0-length upon
// end of iteration
if c_name == nil {
return m, nil // stop iteration
}
m[C.GoString(c_name)] = C.GoBytes(unsafe.Pointer(c_val), (C.int)(c_len))
}
}
// RmXattr removes an xattr with key `name` from object `oid`
func (ioctx *IOContext) RmXattr(oid string, name string) error {
c_oid := C.CString(oid)
c_name := C.CString(name)
defer C.free(unsafe.Pointer(c_oid))
defer C.free(unsafe.Pointer(c_name))
ret := C.rados_rmxattr(
ioctx.ioctx,
c_oid,
c_name)
return getRadosError(int(ret))
}
// LockExclusive takes an exclusive lock on an object.
func (ioctx *IOContext) LockExclusive(oid, name, cookie, desc string, duration time.Duration, flags *byte) (int, error) {
c_oid := C.CString(oid)
c_name := C.CString(name)
c_cookie := C.CString(cookie)
c_desc := C.CString(desc)
var c_duration C.struct_timeval
if duration != 0 {
tv := syscall.NsecToTimeval(duration.Nanoseconds())
c_duration = C.struct_timeval{tv_sec: C.ceph_time_t(tv.Sec), tv_usec: C.ceph_suseconds_t(tv.Usec)}
}
var c_flags C.uint8_t
if flags != nil {
c_flags = C.uint8_t(*flags)
}
defer C.free(unsafe.Pointer(c_oid))
defer C.free(unsafe.Pointer(c_name))
defer C.free(unsafe.Pointer(c_cookie))
defer C.free(unsafe.Pointer(c_desc))
ret := C.rados_lock_exclusive(
ioctx.ioctx,
c_oid,
c_name,
c_cookie,
c_desc,
&c_duration,
c_flags)
// 0 on success, negative error code on failure
// -EBUSY if the lock is already held by another (client, cookie) pair
// -EEXIST if the lock is already held by the same (client, cookie) pair
switch ret {
case 0:
return int(ret), nil
case -C.EBUSY:
return int(ret), nil
case -C.EEXIST:
return int(ret), nil
default:
return int(ret), RadosError(int(ret))
}
}
// LockShared takes a shared lock on an object.
func (ioctx *IOContext) LockShared(oid, name, cookie, tag, desc string, duration time.Duration, flags *byte) (int, error) {
c_oid := C.CString(oid)
c_name := C.CString(name)
c_cookie := C.CString(cookie)
c_tag := C.CString(tag)
c_desc := C.CString(desc)
var c_duration C.struct_timeval
if duration != 0 {
tv := syscall.NsecToTimeval(duration.Nanoseconds())
c_duration = C.struct_timeval{tv_sec: C.ceph_time_t(tv.Sec), tv_usec: C.ceph_suseconds_t(tv.Usec)}
}
var c_flags C.uint8_t
if flags != nil {
c_flags = C.uint8_t(*flags)
}
defer C.free(unsafe.Pointer(c_oid))
defer C.free(unsafe.Pointer(c_name))
defer C.free(unsafe.Pointer(c_cookie))
defer C.free(unsafe.Pointer(c_tag))
defer C.free(unsafe.Pointer(c_desc))
ret := C.rados_lock_shared(
ioctx.ioctx,
c_oid,
c_name,
c_cookie,
c_tag,
c_desc,
&c_duration,
c_flags)
// 0 on success, negative error code on failure
// -EBUSY if the lock is already held by another (client, cookie) pair
// -EEXIST if the lock is already held by the same (client, cookie) pair
switch ret {
case 0:
return int(ret), nil
case -C.EBUSY:
return int(ret), nil
case -C.EEXIST:
return int(ret), nil
default:
return int(ret), RadosError(int(ret))
}
}
// Unlock releases a shared or exclusive lock on an object.
func (ioctx *IOContext) Unlock(oid, name, cookie string) (int, error) {
c_oid := C.CString(oid)
c_name := C.CString(name)
c_cookie := C.CString(cookie)
defer C.free(unsafe.Pointer(c_oid))
defer C.free(unsafe.Pointer(c_name))
defer C.free(unsafe.Pointer(c_cookie))
// 0 on success, negative error code on failure
// -ENOENT if the lock is not held by the specified (client, cookie) pair
ret := C.rados_unlock(
ioctx.ioctx,
c_oid,
c_name,
c_cookie)
switch ret {
case 0:
return int(ret), nil
case -C.ENOENT:
return int(ret), nil
default:
return int(ret), RadosError(int(ret))
}
}
// ListLockers lists clients that have locked the named object lock and
// information about the lock.
// The number of bytes required in each buffer is put in the corresponding size
// out parameter. If any of the provided buffers are too short, -ERANGE is
// returned after these sizes are filled in.
func (ioctx *IOContext) ListLockers(oid, name string) (*LockInfo, error) {
c_oid := C.CString(oid)
c_name := C.CString(name)
c_tag := (*C.char)(C.malloc(C.size_t(1024)))
c_clients := (*C.char)(C.malloc(C.size_t(1024)))
c_cookies := (*C.char)(C.malloc(C.size_t(1024)))
c_addrs := (*C.char)(C.malloc(C.size_t(1024)))
var c_exclusive C.int
c_tag_len := C.size_t(1024)
c_clients_len := C.size_t(1024)
c_cookies_len := C.size_t(1024)
c_addrs_len := C.size_t(1024)
defer C.free(unsafe.Pointer(c_oid))
defer C.free(unsafe.Pointer(c_name))
defer C.free(unsafe.Pointer(c_tag))
defer C.free(unsafe.Pointer(c_clients))
defer C.free(unsafe.Pointer(c_cookies))
defer C.free(unsafe.Pointer(c_addrs))
ret := C.rados_list_lockers(
ioctx.ioctx,
c_oid,
c_name,
&c_exclusive,
c_tag,
&c_tag_len,
c_clients,
&c_clients_len,
c_cookies,
&c_cookies_len,
c_addrs,
&c_addrs_len)
splitCString := func(items *C.char, itemsLen C.size_t) []string {
currLen := 0
clients := []string{}
for currLen < int(itemsLen) {
client := C.GoString(C.nextChunk(&items))
clients = append(clients, client)
currLen += len(client) + 1
}
return clients
}
if ret < 0 {
return nil, RadosError(int(ret))
}
return &LockInfo{int(ret), c_exclusive == 1, C.GoString(c_tag), splitCString(c_clients, c_clients_len), splitCString(c_cookies, c_cookies_len), splitCString(c_addrs, c_addrs_len)}, nil
}
// BreakLock releases a shared or exclusive lock on an object, which was taken by the specified client.
func (ioctx *IOContext) BreakLock(oid, name, client, cookie string) (int, error) {
c_oid := C.CString(oid)
c_name := C.CString(name)
c_client := C.CString(client)
c_cookie := C.CString(cookie)
defer C.free(unsafe.Pointer(c_oid))
defer C.free(unsafe.Pointer(c_name))
defer C.free(unsafe.Pointer(c_client))
defer C.free(unsafe.Pointer(c_cookie))
// 0 on success, negative error code on failure
// -ENOENT if the lock is not held by the specified (client, cookie) pair
// -EINVAL if the client cannot be parsed
ret := C.rados_break_lock(
ioctx.ioctx,
c_oid,
c_name,
c_client,
c_cookie)
switch ret {
case 0:
return int(ret), nil
case -C.ENOENT:
return int(ret), nil
case -C.EINVAL: // -EINVAL
return int(ret), nil
default:
return int(ret), RadosError(int(ret))
}
}

92
vendor/github.com/ceph/go-ceph/rados/object_iter.go generated vendored Normal file
View File

@ -0,0 +1,92 @@
package rados
// #cgo LDFLAGS: -lrados
// #include <rados/librados.h>
//
import "C"
// Iter supports iterating over objects in the ioctx.
type Iter struct {
ctx C.rados_list_ctx_t
err error
entry string
namespace string
}
// IterToken supports reporting on and seeking to different positions.
type IterToken uint32
// Iter returns a Iterator object that can be used to list the object names in the current pool
func (ioctx *IOContext) Iter() (*Iter, error) {
iter := Iter{}
if cerr := C.rados_nobjects_list_open(ioctx.ioctx, &iter.ctx); cerr < 0 {
return nil, getRadosError(int(cerr))
}
return &iter, nil
}
// Token returns a token marking the current position of the iterator. To be used in combination with Iter.Seek()
func (iter *Iter) Token() IterToken {
return IterToken(C.rados_nobjects_list_get_pg_hash_position(iter.ctx))
}
// Seek moves the iterator to the position indicated by the token.
func (iter *Iter) Seek(token IterToken) {
C.rados_nobjects_list_seek(iter.ctx, C.uint32_t(token))
}
// Next retrieves the next object name in the pool/namespace iterator.
// Upon a successful invocation (return value of true), the Value method should
// be used to obtain the name of the retrieved object name. When the iterator is
// exhausted, Next returns false. The Err method should used to verify whether the
// end of the iterator was reached, or the iterator received an error.
//
// Example:
// iter := pool.Iter()
// defer iter.Close()
// for iter.Next() {
// fmt.Printf("%v\n", iter.Value())
// }
// return iter.Err()
//
func (iter *Iter) Next() bool {
var c_entry *C.char
var c_namespace *C.char
if cerr := C.rados_nobjects_list_next(iter.ctx, &c_entry, nil, &c_namespace); cerr < 0 {
iter.err = getRadosError(int(cerr))
return false
}
iter.entry = C.GoString(c_entry)
iter.namespace = C.GoString(c_namespace)
return true
}
// Value returns the current value of the iterator (object name), after a successful call to Next.
func (iter *Iter) Value() string {
if iter.err != nil {
return ""
}
return iter.entry
}
// Namespace returns the namespace associated with the current value of the iterator (object name), after a successful call to Next.
func (iter *Iter) Namespace() string {
if iter.err != nil {
return ""
}
return iter.namespace
}
// Err checks whether the iterator has encountered an error.
func (iter *Iter) Err() error {
if iter.err == ErrNotFound {
return nil
}
return iter.err
}
// Close the iterator cursor on the server. Be aware that iterators are not closed automatically
// at the end of iteration.
func (iter *Iter) Close() {
C.rados_nobjects_list_close(iter.ctx)
}

228
vendor/github.com/ceph/go-ceph/rados/omap.go generated vendored Normal file
View File

@ -0,0 +1,228 @@
package rados
// #cgo LDFLAGS: -lrados
// #include <stdlib.h>
// #include <rados/librados.h>
//
import "C"
import (
"unsafe"
)
// SetOmap appends the map `pairs` to the omap `oid`
func (ioctx *IOContext) SetOmap(oid string, pairs map[string][]byte) error {
c_oid := C.CString(oid)
defer C.free(unsafe.Pointer(c_oid))
var s C.size_t
var c *C.char
ptrSize := unsafe.Sizeof(c)
c_keys := C.malloc(C.size_t(len(pairs)) * C.size_t(ptrSize))
c_values := C.malloc(C.size_t(len(pairs)) * C.size_t(ptrSize))
c_lengths := C.malloc(C.size_t(len(pairs)) * C.size_t(unsafe.Sizeof(s)))
defer C.free(unsafe.Pointer(c_keys))
defer C.free(unsafe.Pointer(c_values))
defer C.free(unsafe.Pointer(c_lengths))
i := 0
for key, value := range pairs {
// key
c_key_ptr := (**C.char)(unsafe.Pointer(uintptr(c_keys) + uintptr(i)*ptrSize))
*c_key_ptr = C.CString(key)
defer C.free(unsafe.Pointer(*c_key_ptr))
// value and its length
c_value_ptr := (**C.char)(unsafe.Pointer(uintptr(c_values) + uintptr(i)*ptrSize))
var c_length C.size_t
if len(value) > 0 {
*c_value_ptr = (*C.char)(unsafe.Pointer(&value[0]))
c_length = C.size_t(len(value))
} else {
*c_value_ptr = nil
c_length = C.size_t(0)
}
c_length_ptr := (*C.size_t)(unsafe.Pointer(uintptr(c_lengths) + uintptr(i)*ptrSize))
*c_length_ptr = c_length
i++
}
op := C.rados_create_write_op()
C.rados_write_op_omap_set(
op,
(**C.char)(c_keys),
(**C.char)(c_values),
(*C.size_t)(c_lengths),
C.size_t(len(pairs)))
ret := C.rados_write_op_operate(op, ioctx.ioctx, c_oid, nil, 0)
C.rados_release_write_op(op)
return getRadosError(int(ret))
}
// OmapListFunc is the type of the function called for each omap key
// visited by ListOmapValues
type OmapListFunc func(key string, value []byte)
// ListOmapValues iterates over the keys and values in an omap by way of
// a callback function.
//
// `startAfter`: iterate only on the keys after this specified one
// `filterPrefix`: iterate only on the keys beginning with this prefix
// `maxReturn`: iterate no more than `maxReturn` key/value pairs
// `listFn`: the function called at each iteration
func (ioctx *IOContext) ListOmapValues(oid string, startAfter string, filterPrefix string, maxReturn int64, listFn OmapListFunc) error {
c_oid := C.CString(oid)
c_start_after := C.CString(startAfter)
c_filter_prefix := C.CString(filterPrefix)
c_max_return := C.uint64_t(maxReturn)
defer C.free(unsafe.Pointer(c_oid))
defer C.free(unsafe.Pointer(c_start_after))
defer C.free(unsafe.Pointer(c_filter_prefix))
op := C.rados_create_read_op()
var c_iter C.rados_omap_iter_t
var c_prval C.int
C.rados_read_op_omap_get_vals2(
op,
c_start_after,
c_filter_prefix,
c_max_return,
&c_iter,
nil,
&c_prval,
)
ret := C.rados_read_op_operate(op, ioctx.ioctx, c_oid, 0)
if int(ret) != 0 {
return getRadosError(int(ret))
} else if int(c_prval) != 0 {
return RadosError(int(c_prval))
}
for {
var c_key *C.char
var c_val *C.char
var c_len C.size_t
ret = C.rados_omap_get_next(c_iter, &c_key, &c_val, &c_len)
if int(ret) != 0 {
return getRadosError(int(ret))
}
if c_key == nil {
break
}
listFn(C.GoString(c_key), C.GoBytes(unsafe.Pointer(c_val), C.int(c_len)))
}
C.rados_omap_get_end(c_iter)
C.rados_release_read_op(op)
return nil
}
// GetOmapValues fetches a set of keys and their values from an omap and returns then as a map
// `startAfter`: retrieve only the keys after this specified one
// `filterPrefix`: retrieve only the keys beginning with this prefix
// `maxReturn`: retrieve no more than `maxReturn` key/value pairs
func (ioctx *IOContext) GetOmapValues(oid string, startAfter string, filterPrefix string, maxReturn int64) (map[string][]byte, error) {
omap := map[string][]byte{}
err := ioctx.ListOmapValues(
oid, startAfter, filterPrefix, maxReturn,
func(key string, value []byte) {
omap[key] = value
},
)
return omap, err
}
// GetAllOmapValues fetches all the keys and their values from an omap and returns then as a map
// `startAfter`: retrieve only the keys after this specified one
// `filterPrefix`: retrieve only the keys beginning with this prefix
// `iteratorSize`: internal number of keys to fetch during a read operation
func (ioctx *IOContext) GetAllOmapValues(oid string, startAfter string, filterPrefix string, iteratorSize int64) (map[string][]byte, error) {
omap := map[string][]byte{}
omapSize := 0
for {
err := ioctx.ListOmapValues(
oid, startAfter, filterPrefix, iteratorSize,
func(key string, value []byte) {
omap[key] = value
startAfter = key
},
)
if err != nil {
return omap, err
}
// End of omap
if len(omap) == omapSize {
break
}
omapSize = len(omap)
}
return omap, nil
}
// RmOmapKeys removes the specified `keys` from the omap `oid`
func (ioctx *IOContext) RmOmapKeys(oid string, keys []string) error {
c_oid := C.CString(oid)
defer C.free(unsafe.Pointer(c_oid))
var c *C.char
ptrSize := unsafe.Sizeof(c)
c_keys := C.malloc(C.size_t(len(keys)) * C.size_t(ptrSize))
defer C.free(unsafe.Pointer(c_keys))
i := 0
for _, key := range keys {
c_key_ptr := (**C.char)(unsafe.Pointer(uintptr(c_keys) + uintptr(i)*ptrSize))
*c_key_ptr = C.CString(key)
defer C.free(unsafe.Pointer(*c_key_ptr))
i++
}
op := C.rados_create_write_op()
C.rados_write_op_omap_rm_keys(
op,
(**C.char)(c_keys),
C.size_t(len(keys)))
ret := C.rados_write_op_operate(op, ioctx.ioctx, c_oid, nil, 0)
C.rados_release_write_op(op)
return getRadosError(int(ret))
}
// CleanOmap clears the omap `oid`
func (ioctx *IOContext) CleanOmap(oid string) error {
c_oid := C.CString(oid)
defer C.free(unsafe.Pointer(c_oid))
op := C.rados_create_write_op()
C.rados_write_op_omap_clear(op)
ret := C.rados_write_op_operate(op, ioctx.ioctx, c_oid, nil, 0)
C.rados_release_write_op(op)
return getRadosError(int(ret))
}

137
vendor/github.com/ceph/go-ceph/rados/rados.go generated vendored Normal file
View File

@ -0,0 +1,137 @@
package rados
// #cgo LDFLAGS: -lrados
// #include <errno.h>
// #include <stdlib.h>
// #include <rados/librados.h>
import "C"
import (
"fmt"
"runtime"
"unsafe"
"github.com/ceph/go-ceph/errutil"
)
// RadosError represents an error condition returned from the Ceph RADOS APIs.
type RadosError int
// Error returns the error string for the RadosError type.
func (e RadosError) Error() string {
errno, s := errutil.FormatErrno(int(e))
if s == "" {
return fmt.Sprintf("rados: ret=%d", errno)
}
return fmt.Sprintf("rados: ret=%d, %s", errno, s)
}
const (
// AllNamespaces is used to reset a selected namespace to all
// namespaces. See the IOContext SetNamespace function.
AllNamespaces = C.LIBRADOS_ALL_NSPACES
// ErrNotFound indicates a missing resource.
ErrNotFound = RadosError(-C.ENOENT)
// ErrPermissionDenied indicates a permissions issue.
ErrPermissionDenied = RadosError(-C.EPERM)
// ErrObjectExists indicates that an exclusive object creation failed.
ErrObjectExists = RadosError(-C.EEXIST)
// FIXME: for backwards compatibility
// RadosAllNamespaces is used to reset a selected namespace to all
// namespaces. See the IOContext SetNamespace function.
//
// Deprecated: use AllNamespaces instead
RadosAllNamespaces = AllNamespaces
// RadosErrorNotFound indicates a missing resource.
//
// Deprecated: use ErrNotFound instead
RadosErrorNotFound = ErrNotFound
// RadosErrorPermissionDenied indicates a permissions issue.
//
// Deprecated: use ErrPermissionDenied instead
RadosErrorPermissionDenied = ErrPermissionDenied
)
func getRadosError(err int) error {
if err == 0 {
return nil
}
return RadosError(err)
}
// Version returns the major, minor, and patch components of the version of
// the RADOS library linked against.
func Version() (int, int, int) {
var c_major, c_minor, c_patch C.int
C.rados_version(&c_major, &c_minor, &c_patch)
return int(c_major), int(c_minor), int(c_patch)
}
func makeConn() *Conn {
return &Conn{connected: false}
}
func newConn(user *C.char) (*Conn, error) {
conn := makeConn()
ret := C.rados_create(&conn.cluster, user)
if ret != 0 {
return nil, RadosError(int(ret))
}
runtime.SetFinalizer(conn, freeConn)
return conn, nil
}
// NewConn creates a new connection object. It returns the connection and an
// error, if any.
func NewConn() (*Conn, error) {
return newConn(nil)
}
// NewConnWithUser creates a new connection object with a custom username.
// It returns the connection and an error, if any.
func NewConnWithUser(user string) (*Conn, error) {
c_user := C.CString(user)
defer C.free(unsafe.Pointer(c_user))
return newConn(c_user)
}
// NewConnWithClusterAndUser creates a new connection object for a specific cluster and username.
// It returns the connection and an error, if any.
func NewConnWithClusterAndUser(clusterName string, userName string) (*Conn, error) {
c_cluster_name := C.CString(clusterName)
defer C.free(unsafe.Pointer(c_cluster_name))
c_name := C.CString(userName)
defer C.free(unsafe.Pointer(c_name))
conn := makeConn()
ret := C.rados_create2(&conn.cluster, c_cluster_name, c_name, 0)
if ret != 0 {
return nil, RadosError(int(ret))
}
runtime.SetFinalizer(conn, freeConn)
return conn, nil
}
// freeConn releases resources that are allocated while configuring the
// connection to the cluster. rados_shutdown() should only be needed after a
// successful call to rados_connect(), however if the connection has been
// configured with non-default parameters, some of the parameters may be
// allocated before connecting. rados_shutdown() will free the allocated
// resources, even if there has not been a connection yet.
//
// This function is setup as a destructor/finalizer when rados_create() is
// called.
func freeConn(conn *Conn) {
if conn.cluster != nil {
C.rados_shutdown(conn.cluster)
// prevent calling rados_shutdown() more than once
conn.cluster = nil
}
}

4
vendor/github.com/ceph/go-ceph/rbd/doc.go generated vendored Normal file
View File

@ -0,0 +1,4 @@
/*
Package rbd contains a set of wrappers around Ceph's librbd API.
*/
package rbd

169
vendor/github.com/ceph/go-ceph/rbd/options.go generated vendored Normal file
View File

@ -0,0 +1,169 @@
package rbd
// #cgo LDFLAGS: -lrbd
// #include <stdlib.h>
// #include <rbd/librbd.h>
import "C"
import (
"fmt"
"unsafe"
)
const (
// RBD image options.
RbdImageOptionFormat = C.RBD_IMAGE_OPTION_FORMAT
RbdImageOptionFeatures = C.RBD_IMAGE_OPTION_FEATURES
RbdImageOptionOrder = C.RBD_IMAGE_OPTION_ORDER
RbdImageOptionStripeUnit = C.RBD_IMAGE_OPTION_STRIPE_UNIT
RbdImageOptionStripeCount = C.RBD_IMAGE_OPTION_STRIPE_COUNT
RbdImageOptionJournalOrder = C.RBD_IMAGE_OPTION_JOURNAL_ORDER
RbdImageOptionJournalSplayWidth = C.RBD_IMAGE_OPTION_JOURNAL_SPLAY_WIDTH
RbdImageOptionJournalPool = C.RBD_IMAGE_OPTION_JOURNAL_POOL
RbdImageOptionFeaturesSet = C.RBD_IMAGE_OPTION_FEATURES_SET
RbdImageOptionFeaturesClear = C.RBD_IMAGE_OPTION_FEATURES_CLEAR
RbdImageOptionDataPool = C.RBD_IMAGE_OPTION_DATA_POOL
// introduced with Ceph Mimic
//RbdImageOptionFlatten = C.RBD_IMAGE_OPTION_FLATTEN
)
type RbdImageOptions struct {
options C.rbd_image_options_t
}
type RbdImageOption C.int
// NewRbdImageOptions creates a new RbdImageOptions struct. Call
// RbdImageOptions.Destroy() to free the resources.
//
// Implements:
// void rbd_image_options_create(rbd_image_options_t* opts)
func NewRbdImageOptions() *RbdImageOptions {
rio := &RbdImageOptions{}
C.rbd_image_options_create(&rio.options)
return rio
}
// Destroy a RbdImageOptions struct and free the associated resources.
//
// Implements:
// void rbd_image_options_destroy(rbd_image_options_t opts);
func (rio *RbdImageOptions) Destroy() {
C.rbd_image_options_destroy(rio.options)
}
// SetString sets the value of the RbdImageOption to the given string.
//
// Implements:
// int rbd_image_options_set_string(rbd_image_options_t opts, int optname,
// const char* optval);
func (rio *RbdImageOptions) SetString(option RbdImageOption, value string) error {
c_value := C.CString(value)
defer C.free(unsafe.Pointer(c_value))
ret := C.rbd_image_options_set_string(rio.options, C.int(option), c_value)
if ret != 0 {
return fmt.Errorf("%v, could not set option %v to \"%v\"",
getError(ret), option, value)
}
return nil
}
// GetString returns the string value of the RbdImageOption.
//
// Implements:
// int rbd_image_options_get_string(rbd_image_options_t opts, int optname,
// char* optval, size_t maxlen);
func (rio *RbdImageOptions) GetString(option RbdImageOption) (string, error) {
value := make([]byte, 4096)
ret := C.rbd_image_options_get_string(rio.options, C.int(option),
(*C.char)(unsafe.Pointer(&value[0])),
C.size_t(len(value)))
if ret != 0 {
return "", fmt.Errorf("%v, could not get option %v", getError(ret), option)
}
return C.GoString((*C.char)(unsafe.Pointer(&value[0]))), nil
}
// SetUint64 sets the value of the RbdImageOption to the given uint64.
//
// Implements:
// int rbd_image_options_set_uint64(rbd_image_options_t opts, int optname,
// const uint64_t optval);
func (rio *RbdImageOptions) SetUint64(option RbdImageOption, value uint64) error {
c_value := C.uint64_t(value)
ret := C.rbd_image_options_set_uint64(rio.options, C.int(option), c_value)
if ret != 0 {
return fmt.Errorf("%v, could not set option %v to \"%v\"",
getError(ret), option, value)
}
return nil
}
// GetUint64 returns the uint64 value of the RbdImageOption.
//
// Implements:
// int rbd_image_options_get_uint64(rbd_image_options_t opts, int optname,
// uint64_t* optval);
func (rio *RbdImageOptions) GetUint64(option RbdImageOption) (uint64, error) {
var c_value C.uint64_t
ret := C.rbd_image_options_get_uint64(rio.options, C.int(option), &c_value)
if ret != 0 {
return 0, fmt.Errorf("%v, could not get option %v", getError(ret), option)
}
return uint64(c_value), nil
}
// IsSet returns a true if the RbdImageOption is set, false otherwise.
//
// Implements:
// int rbd_image_options_is_set(rbd_image_options_t opts, int optname,
// bool* is_set);
func (rio *RbdImageOptions) IsSet(option RbdImageOption) (bool, error) {
var c_set C.bool
ret := C.rbd_image_options_is_set(rio.options, C.int(option), &c_set)
if ret != 0 {
return false, fmt.Errorf("%v, could not check option %v", getError(ret), option)
}
return bool(c_set), nil
}
// Unset a given RbdImageOption.
//
// Implements:
// int rbd_image_options_unset(rbd_image_options_t opts, int optname)
func (rio *RbdImageOptions) Unset(option RbdImageOption) error {
ret := C.rbd_image_options_unset(rio.options, C.int(option))
if ret != 0 {
return fmt.Errorf("%v, could not unset option %v", getError(ret), option)
}
return nil
}
// Clear all options in the RbdImageOptions.
//
// Implements:
// void rbd_image_options_clear(rbd_image_options_t opts)
func (rio *RbdImageOptions) Clear() {
C.rbd_image_options_clear(rio.options)
}
// IsEmpty returns true if there are no options set in the RbdImageOptions,
// false otherwise.
//
// Implements:
// int rbd_image_options_is_empty(rbd_image_options_t opts)
func (rio *RbdImageOptions) IsEmpty() bool {
ret := C.rbd_image_options_is_empty(rio.options)
return ret != 0
}

1403
vendor/github.com/ceph/go-ceph/rbd/rbd.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

43
vendor/github.com/ceph/go-ceph/rbd/rbd_mimic.go generated vendored Normal file
View File

@ -0,0 +1,43 @@
// +build luminous mimic
// +build !nautilus
//
// Ceph Nautilus includes rbd_list2() and marked rbd_list() deprecated.
package rbd
// #cgo LDFLAGS: -lrbd
// #include <rados/librados.h>
// #include <rbd/librbd.h>
// #include <errno.h>
import "C"
import (
"bytes"
"unsafe"
"github.com/ceph/go-ceph/rados"
)
// GetImageNames returns the list of current RBD images.
func GetImageNames(ioctx *rados.IOContext) (names []string, err error) {
buf := make([]byte, 4096)
for {
size := C.size_t(len(buf))
ret := C.rbd_list(C.rados_ioctx_t(ioctx.Pointer()),
(*C.char)(unsafe.Pointer(&buf[0])), &size)
if ret == -C.ERANGE {
buf = make([]byte, size)
continue
} else if ret < 0 {
return nil, RBDError(ret)
}
tmp := bytes.Split(buf[:size-1], []byte{0})
for _, s := range tmp {
if len(s) > 0 {
name := C.GoString((*C.char)(unsafe.Pointer(&s[0])))
names = append(names, name)
}
}
return names, nil
}
}

45
vendor/github.com/ceph/go-ceph/rbd/rbd_nautilus.go generated vendored Normal file
View File

@ -0,0 +1,45 @@
// +build !luminous,!mimic
//
// Ceph Nautilus is the first release that includes rbd_list2().
package rbd
// #cgo LDFLAGS: -lrbd
// #include <rados/librados.h>
// #include <rbd/librbd.h>
// #include <errno.h>
import "C"
import (
"fmt"
"unsafe"
"github.com/ceph/go-ceph/rados"
)
// GetImageNames returns the list of current RBD images.
func GetImageNames(ioctx *rados.IOContext) ([]string, error) {
size := C.size_t(0)
ret := C.rbd_list2(C.rados_ioctx_t(ioctx.Pointer()), nil, &size)
if ret < 0 && ret != -C.ERANGE {
return nil, RBDError(ret)
} else if ret > 0 {
return nil, fmt.Errorf("rbd_list2() returned %d names, expected 0", ret)
} else if ret == 0 && size == 0 {
return nil, nil
}
// expected: ret == -ERANGE, size contains number of image names
images := make([]C.rbd_image_spec_t, size)
ret = C.rbd_list2(C.rados_ioctx_t(ioctx.Pointer()), (*C.rbd_image_spec_t)(unsafe.Pointer(&images[0])), &size)
if ret < 0 {
return nil, RBDError(ret)
}
defer C.rbd_image_spec_list_cleanup((*C.rbd_image_spec_t)(unsafe.Pointer(&images[0])), size)
names := make([]string, size)
for i, image := range images {
names[i] = C.GoString(image.name)
}
return names, nil
}

101
vendor/github.com/ceph/go-ceph/rbd/snapshot_mimic.go generated vendored Normal file
View File

@ -0,0 +1,101 @@
// +build luminous mimic
// +build !nautilus
//
// Ceph Nautilus introduced rbd_get_parent() and deprecated rbd_get_parent_info().
// Ceph Nautilus introduced rbd_list_children3() and deprecated rbd_list_children().
package rbd
// #cgo LDFLAGS: -lrbd
// #include <rbd/librbd.h>
// #include <errno.h>
import "C"
import (
"bytes"
"unsafe"
)
// GetParentInfo looks for the parent of the image and stores the pool, name
// and snapshot-name in the byte-arrays that are passed as arguments.
//
// Implements:
// int rbd_get_parent_info(rbd_image_t image, char *parent_pool_name,
// size_t ppool_namelen, char *parent_name,
// size_t pnamelen, char *parent_snap_name,
// size_t psnap_namelen)
func (image *Image) GetParentInfo(p_pool, p_name, p_snapname []byte) error {
if err := image.validate(imageIsOpen); err != nil {
return err
}
ret := C.rbd_get_parent_info(
image.image,
(*C.char)(unsafe.Pointer(&p_pool[0])),
(C.size_t)(len(p_pool)),
(*C.char)(unsafe.Pointer(&p_name[0])),
(C.size_t)(len(p_name)),
(*C.char)(unsafe.Pointer(&p_snapname[0])),
(C.size_t)(len(p_snapname)))
if ret == 0 {
return nil
} else {
return RBDError(ret)
}
}
// ListChildren returns arrays with the pools and names of the images that are
// children of the given image. The index of the pools and images arrays can be
// used to link the two items together.
//
// Implements:
// ssize_t rbd_list_children(rbd_image_t image, char *pools,
// size_t *pools_len,
// char *images, size_t *images_len);
func (image *Image) ListChildren() (pools []string, images []string, err error) {
if err := image.validate(imageIsOpen); err != nil {
return nil, nil, err
}
var c_pools_len, c_images_len C.size_t
ret := C.rbd_list_children(image.image,
nil, &c_pools_len,
nil, &c_images_len)
if ret == 0 {
return nil, nil, nil
}
if ret < 0 && ret != -C.ERANGE {
return nil, nil, RBDError(ret)
}
pools_buf := make([]byte, c_pools_len)
images_buf := make([]byte, c_images_len)
ret = C.rbd_list_children(image.image,
(*C.char)(unsafe.Pointer(&pools_buf[0])),
&c_pools_len,
(*C.char)(unsafe.Pointer(&images_buf[0])),
&c_images_len)
if ret < 0 {
return nil, nil, RBDError(ret)
}
tmp := bytes.Split(pools_buf[:c_pools_len-1], []byte{0})
for _, s := range tmp {
if len(s) > 0 {
name := C.GoString((*C.char)(unsafe.Pointer(&s[0])))
pools = append(pools, name)
}
}
tmp = bytes.Split(images_buf[:c_images_len-1], []byte{0})
for _, s := range tmp {
if len(s) > 0 {
name := C.GoString((*C.char)(unsafe.Pointer(&s[0])))
images = append(images, name)
}
}
return pools, images, nil
}

104
vendor/github.com/ceph/go-ceph/rbd/snapshot_nautilus.go generated vendored Normal file
View File

@ -0,0 +1,104 @@
// +build !luminous,!mimic
//
// Ceph Nautilus introduced rbd_get_parent() and deprecated rbd_get_parent_info().
// Ceph Nautilus introduced rbd_list_children3() and deprecated rbd_list_children().
package rbd
// #cgo LDFLAGS: -lrbd
// #include <rbd/librbd.h>
// #include <errno.h>
import "C"
import (
"fmt"
"unsafe"
)
// GetParentInfo looks for the parent of the image and stores the pool, name
// and snapshot-name in the byte-arrays that are passed as arguments.
//
// Implements:
// int rbd_get_parent(rbd_image_t image,
// rbd_linked_image_spec_t *parent_image,
// rbd_snap_spec_t *parent_snap)
func (image *Image) GetParentInfo(pool, name, snapname []byte) error {
if err := image.validate(imageIsOpen); err != nil {
return err
}
parentImage := C.rbd_linked_image_spec_t{}
parentSnap := C.rbd_snap_spec_t{}
ret := C.rbd_get_parent(image.image, &parentImage, &parentSnap)
if ret != 0 {
return RBDError(ret)
}
defer C.rbd_linked_image_spec_cleanup(&parentImage)
defer C.rbd_snap_spec_cleanup(&parentSnap)
strlen := int(C.strlen(parentImage.pool_name))
if len(pool) < strlen {
return RBDError(C.ERANGE)
}
if copy(pool, C.GoString(parentImage.pool_name)) != strlen {
return RBDError(C.ERANGE)
}
strlen = int(C.strlen(parentImage.image_name))
if len(name) < strlen {
return RBDError(C.ERANGE)
}
if copy(name, C.GoString(parentImage.image_name)) != strlen {
return RBDError(C.ERANGE)
}
strlen = int(C.strlen(parentSnap.name))
if len(snapname) < strlen {
return RBDError(C.ERANGE)
}
if copy(snapname, C.GoString(parentSnap.name)) != strlen {
return RBDError(C.ERANGE)
}
return nil
}
// ListChildren returns arrays with the pools and names of the images that are
// children of the given image. The index of the pools and images arrays can be
// used to link the two items together.
//
// Implements:
// int rbd_list_children3(rbd_image_t image, rbd_linked_image_spec_t *images,
// size_t *max_images);
func (image *Image) ListChildren() (pools []string, images []string, err error) {
if err := image.validate(imageIsOpen); err != nil {
return nil, nil, err
}
size := C.size_t(0)
ret := C.rbd_list_children3(image.image, nil, &size)
if ret < 0 && ret != -C.ERANGE {
return nil, nil, RBDError(ret)
} else if ret > 0 {
return nil, nil, fmt.Errorf("rbd_list_children3() returned %d, expected 0", ret)
} else if ret == 0 && size == 0 {
return nil, nil, nil
}
// expected: ret == -ERANGE, size contains number of image names
children := make([]C.rbd_linked_image_spec_t, size)
ret = C.rbd_list_children3(image.image, (*C.rbd_linked_image_spec_t)(unsafe.Pointer(&children[0])), &size)
if ret < 0 {
return nil, nil, RBDError(ret)
}
defer C.rbd_linked_image_spec_list_cleanup((*C.rbd_linked_image_spec_t)(unsafe.Pointer(&children[0])), size)
pools = make([]string, size)
images = make([]string, size)
for i, child := range children {
pools[i] = C.GoString(child.pool_name)
images[i] = C.GoString(child.image_name)
}
return pools, images, nil
}