diff --git a/doc.go b/doc.go index b66f423..e3867a0 100644 --- a/doc.go +++ b/doc.go @@ -4,6 +4,6 @@ Set of wrappers around Ceph APIs. package rados import ( - _ "github.com/noahdesu/go-ceph/rados" - _ "github.com/noahdesu/go-ceph/rbd" + _ "github.com/noahdesu/go-ceph/rados" + _ "github.com/noahdesu/go-ceph/rbd" ) diff --git a/package_test.go b/package_test.go index b25139e..73ef3e0 100644 --- a/package_test.go +++ b/package_test.go @@ -1,12 +1,12 @@ package rados import ( - "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/assert" + "testing" ) func TestImports(t *testing.T) { - if assert.Equal(t, 1, 1) != true { - t.Error("Something is wrong.") - } + if assert.Equal(t, 1, 1) != true { + t.Error("Something is wrong.") + } } diff --git a/rados/conn.go b/rados/conn.go index cdae3d6..af3cfeb 100644 --- a/rados/conn.go +++ b/rados/conn.go @@ -10,254 +10,254 @@ import "bytes" // ClusterStat represents Ceph cluster statistics. type ClusterStat struct { - Kb uint64 - Kb_used uint64 - Kb_avail uint64 - Num_objects uint64 + 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 + cluster C.rados_t } // 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)) + c_id := C.CString(id) + defer C.free(unsafe.Pointer(c_id)) - var strlen C.size_t - var strout *C.char + 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) + 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 - } else { - return "", RadosError(int(ret)) - } + if ret == 0 { + reply := C.GoStringN(strout, (C.int)(strlen)) + return reply, nil + } else { + 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 nil - } else { - return RadosError(int(ret)) - } + ret := C.rados_connect(c.cluster) + if ret == 0 { + return nil + } else { + return RadosError(int(ret)) + } } // Shutdown disconnects from the cluster. func (c *Conn) Shutdown() { - C.rados_shutdown(c.cluster) + C.rados_shutdown(c.cluster) } // 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) - if ret == 0 { - return nil - } else { - return RadosError(int(ret)) - } + c_path := C.CString(path) + defer C.free(unsafe.Pointer(c_path)) + ret := C.rados_conf_read_file(c.cluster, c_path) + if ret == 0 { + return nil + } else { + return RadosError(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) - if ret == 0 { - return nil - } else { - return RadosError(int(ret)) - } + ret := C.rados_conf_read_file(c.cluster, nil) + if ret == 0 { + return nil + } else { + return RadosError(int(ret)) + } } 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 - } else { - return nil, RadosError(int(ret)) - } + 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 + } else { + 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)) - } + 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 - } + 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) - } - } + 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 - } + 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) - if ret < 0 { - return RadosError(int(ret)) - } else { - return nil - } + 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) + if ret < 0 { + return RadosError(int(ret)) + } else { + return nil + } } // 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 - } else { - return "", RadosError(ret) - } + 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 + } else { + 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) - if ret < 0 { - return RadosError(int(ret)) - } else { - return nil - } + ret := C.rados_wait_for_latest_osdmap(c.cluster) + if ret < 0 { + return RadosError(int(ret)) + } else { + return nil + } } // GetClusterStat returns statistics about the cluster associated with the // connection. func (c *Conn) GetClusterStats() (stat ClusterStat, err error) { - 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)) - } else { - 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 - } + 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)) + } else { + 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) + // 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])) + // 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])) - } + 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]) - if ret < 0 { - return RadosError(int(ret)) - } else { - return nil - } + ret := C.rados_conf_parse_argv(c.cluster, argc, &argv[0]) + if ret < 0 { + return RadosError(int(ret)) + } else { + return nil + } } // 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) - if ret == 0 { - return nil - } else { - return RadosError(int(ret)) - } + ret := C.rados_conf_parse_env(c.cluster, nil) + if ret == 0 { + return nil + } else { + return RadosError(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 - } else { - return "", RadosError(int(ret)) - } + 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 + } else { + 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)) + // 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)) - if ret == 0 { - return nil - } else { - return RadosError(ret) - } + c_name := C.CString(name) + defer C.free(unsafe.Pointer(c_name)) + ret := int(C.rados_pool_create(c.cluster, c_name)) + if ret == 0 { + return nil + } else { + return RadosError(ret) + } } // DeletePool deletes a pool and all the data inside the pool. func (c *Conn) DeletePool(name string) error { - c_name :=C.CString(name) - defer C.free(unsafe.Pointer(c_name)) - ret := int(C.rados_pool_delete(c.cluster, c_name)) - if ret == 0 { - return nil - } else { - return RadosError(ret) - } + c_name := C.CString(name) + defer C.free(unsafe.Pointer(c_name)) + ret := int(C.rados_pool_delete(c.cluster, c_name)) + if ret == 0 { + return nil + } else { + return RadosError(ret) + } } // MonCommand sends a command to one of the monitors diff --git a/rados/ioctx.go b/rados/ioctx.go index 4229bde..4200c40 100644 --- a/rados/ioctx.go +++ b/rados/ioctx.go @@ -9,92 +9,92 @@ import "unsafe" // 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 + // 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 } // IOContext represents a context for performing I/O within a pool. type IOContext struct { - ioctx C.rados_ioctx_t + ioctx C.rados_ioctx_t } // Pointer returns a uintptr representation of the IOContext. func (ioctx *IOContext) Pointer() uintptr { - return uintptr(ioctx.ioctx) + return uintptr(ioctx.ioctx) } // 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)) + c_oid := C.CString(oid) + defer C.free(unsafe.Pointer(c_oid)) - ret := C.rados_write(ioctx.ioctx, c_oid, - (*C.char)(unsafe.Pointer(&data[0])), - (C.size_t)(len(data)), - (C.uint64_t)(offset)) + ret := C.rados_write(ioctx.ioctx, c_oid, + (*C.char)(unsafe.Pointer(&data[0])), + (C.size_t)(len(data)), + (C.uint64_t)(offset)) - if ret == 0 { - return nil - } else { - return RadosError(int(ret)) - } + if ret == 0 { + return nil + } else { + return RadosError(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) { - if len(data) == 0 { - return 0, nil - } + if len(data) == 0 { + return 0, nil + } - c_oid := C.CString(oid) - defer C.free(unsafe.Pointer(c_oid)) + c_oid := C.CString(oid) + defer C.free(unsafe.Pointer(c_oid)) - ret := C.rados_read( - ioctx.ioctx, - c_oid, - (*C.char)(unsafe.Pointer(&data[0])), - (C.size_t)(len(data)), - (C.uint64_t)(offset)) + ret := C.rados_read( + ioctx.ioctx, + c_oid, + (*C.char)(unsafe.Pointer(&data[0])), + (C.size_t)(len(data)), + (C.uint64_t)(offset)) - if ret >= 0 { - return int(ret), nil - } else { - return 0, RadosError(int(ret)) - } + if ret >= 0 { + return int(ret), nil + } else { + return 0, RadosError(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)) + c_oid := C.CString(oid) + defer C.free(unsafe.Pointer(c_oid)) - ret := C.rados_remove(ioctx.ioctx, c_oid) + ret := C.rados_remove(ioctx.ioctx, c_oid) - if ret == 0 { - return nil - } else { - return RadosError(int(ret)) - } + if ret == 0 { + return nil + } else { + return RadosError(int(ret)) + } } // Truncate resizes the object with key oid to size size. If the operation @@ -102,65 +102,65 @@ func (ioctx *IOContext) Delete(oid string) error { // 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)) + c_oid := C.CString(oid) + defer C.free(unsafe.Pointer(c_oid)) - ret := C.rados_trunc(ioctx.ioctx, c_oid, (C.uint64_t)(size)) + ret := C.rados_trunc(ioctx.ioctx, c_oid, (C.uint64_t)(size)) - if ret == 0 { - return nil - } else { - return RadosError(int(ret)) - } + if ret == 0 { + return nil + } else { + return RadosError(int(ret)) + } } // 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) + C.rados_ioctx_destroy(ioctx.ioctx) } // Stat returns a set of statistics about the pool associated with this I/O // context. 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{}, RadosError(int(ret)) - } else { - 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 - } + c_stat := C.struct_rados_pool_stat_t{} + ret := C.rados_ioctx_pool_stat(ioctx.ioctx, &c_stat) + if ret < 0 { + return PoolStat{}, RadosError(int(ret)) + } else { + 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 == -34 { // FIXME - buf = make([]byte, len(buf)*2) - continue - } else if ret < 0 { - return "", RadosError(ret) - } - name = C.GoStringN((*C.char)(unsafe.Pointer(&buf[0])), ret) - return name, nil - } + 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 == -34 { // FIXME + buf = make([]byte, len(buf)*2) + continue + } else if ret < 0 { + return "", RadosError(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 @@ -171,23 +171,23 @@ type ObjectListFunc func(oid string) // context, and called the provided listFn function for each object, passing // to the function the name of the object. func (ioctx *IOContext) ListObjects(listFn ObjectListFunc) error { - var ctx C.rados_list_ctx_t - ret := C.rados_objects_list_open(ioctx.ioctx, &ctx) - if ret < 0 { - return RadosError(ret) - } - defer func() { C.rados_objects_list_close(ctx) }() + var ctx C.rados_list_ctx_t + ret := C.rados_objects_list_open(ioctx.ioctx, &ctx) + if ret < 0 { + return RadosError(ret) + } + defer func() { C.rados_objects_list_close(ctx) }() - for { - var c_entry *C.char - ret := C.rados_objects_list_next(ctx, &c_entry, nil) - if ret == -2 { // FIXME - return nil - } else if ret < 0 { - return RadosError(ret) - } - listFn(C.GoString(c_entry)) - } + for { + var c_entry *C.char + ret := C.rados_objects_list_next(ctx, &c_entry, nil) + if ret == -2 { // FIXME + return nil + } else if ret < 0 { + return RadosError(ret) + } + listFn(C.GoString(c_entry)) + } - panic("invalid state") + panic("invalid state") } diff --git a/rados/rados.go b/rados/rados.go index fc73136..eadad11 100644 --- a/rados/rados.go +++ b/rados/rados.go @@ -6,32 +6,32 @@ package rados import "C" import ( - "fmt" + "fmt" ) type RadosError int func (e RadosError) Error() string { - return fmt.Sprintf("rados: ret=%d", e) + return fmt.Sprintf("rados: ret=%d", e) } // 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) + 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) } // NewConn creates a new connection object. It returns the connection and an // error, if any. func NewConn() (*Conn, error) { - conn := &Conn{} - ret := C.rados_create(&conn.cluster, nil) + conn := &Conn{} + ret := C.rados_create(&conn.cluster, nil) - if ret == 0 { - return conn, nil - } else { - return nil, RadosError(int(ret)) - } + if ret == 0 { + return conn, nil + } else { + return nil, RadosError(int(ret)) + } } diff --git a/rados/rados_test.go b/rados/rados_test.go index 26cf689..4bbe99f 100644 --- a/rados/rados_test.go +++ b/rados/rados_test.go @@ -1,6 +1,7 @@ package rados_test import "testing" + //import "bytes" import "github.com/noahdesu/go-ceph/rados" import "github.com/stretchr/testify/assert" @@ -15,371 +16,371 @@ import "sort" import "encoding/json" func GetUUID() string { - out, _ := exec.Command("uuidgen").Output() - return string(out[:36]) + out, _ := exec.Command("uuidgen").Output() + return string(out[:36]) } func TestVersion(t *testing.T) { - var major, minor, patch = rados.Version() - assert.False(t, major < 0 || major > 1000, "invalid major") - assert.False(t, minor < 0 || minor > 1000, "invalid minor") - assert.False(t, patch < 0 || patch > 1000, "invalid patch") + var major, minor, patch = rados.Version() + assert.False(t, major < 0 || major > 1000, "invalid major") + assert.False(t, minor < 0 || minor > 1000, "invalid minor") + assert.False(t, patch < 0 || patch > 1000, "invalid patch") } func TestGetSetConfigOption(t *testing.T) { - conn, _ := rados.NewConn() + conn, _ := rados.NewConn() - // rejects invalid options - err := conn.SetConfigOption("wefoijweojfiw", "welfkwjelkfj") - assert.Error(t, err, "Invalid option") + // rejects invalid options + err := conn.SetConfigOption("wefoijweojfiw", "welfkwjelkfj") + assert.Error(t, err, "Invalid option") - // verify SetConfigOption changes a values - log_file_val, err := conn.GetConfigOption("log_file") - assert.NotEqual(t, log_file_val, "/dev/null") + // verify SetConfigOption changes a values + log_file_val, err := conn.GetConfigOption("log_file") + assert.NotEqual(t, log_file_val, "/dev/null") - err = conn.SetConfigOption("log_file", "/dev/null") - assert.NoError(t, err, "Invalid option") + err = conn.SetConfigOption("log_file", "/dev/null") + assert.NoError(t, err, "Invalid option") - log_file_val, err = conn.GetConfigOption("log_file") - assert.Equal(t, log_file_val, "/dev/null") + log_file_val, err = conn.GetConfigOption("log_file") + assert.Equal(t, log_file_val, "/dev/null") } func TestParseDefaultConfigEnv(t *testing.T) { - conn, _ := rados.NewConn() + conn, _ := rados.NewConn() - log_file_val, _ := conn.GetConfigOption("log_file") - assert.NotEqual(t, log_file_val, "/dev/null") + log_file_val, _ := conn.GetConfigOption("log_file") + assert.NotEqual(t, log_file_val, "/dev/null") - err := os.Setenv("CEPH_ARGS", "--log-file /dev/null") - assert.NoError(t, err) + err := os.Setenv("CEPH_ARGS", "--log-file /dev/null") + assert.NoError(t, err) - err = conn.ParseDefaultConfigEnv() - assert.NoError(t, err) + err = conn.ParseDefaultConfigEnv() + assert.NoError(t, err) - log_file_val, _ = conn.GetConfigOption("log_file") - assert.Equal(t, log_file_val, "/dev/null") + log_file_val, _ = conn.GetConfigOption("log_file") + assert.Equal(t, log_file_val, "/dev/null") } func TestParseCmdLineArgs(t *testing.T) { - conn, _ := rados.NewConn() - conn.ReadDefaultConfigFile() + conn, _ := rados.NewConn() + conn.ReadDefaultConfigFile() - mon_host_val, _ := conn.GetConfigOption("mon_host") - assert.NotEqual(t, mon_host_val, "1.1.1.1") + mon_host_val, _ := conn.GetConfigOption("mon_host") + assert.NotEqual(t, mon_host_val, "1.1.1.1") - args := []string{ "--mon-host", "1.1.1.1" } - err := conn.ParseCmdLineArgs(args) - assert.NoError(t, err) + args := []string{"--mon-host", "1.1.1.1"} + err := conn.ParseCmdLineArgs(args) + assert.NoError(t, err) - mon_host_val, _ = conn.GetConfigOption("mon_host") - assert.Equal(t, mon_host_val, "1.1.1.1") + mon_host_val, _ = conn.GetConfigOption("mon_host") + assert.Equal(t, mon_host_val, "1.1.1.1") } func TestGetClusterStats(t *testing.T) { - conn, _ := rados.NewConn() - conn.ReadDefaultConfigFile() - conn.Connect() + conn, _ := rados.NewConn() + conn.ReadDefaultConfigFile() + conn.Connect() - poolname := GetUUID() - err := conn.MakePool(poolname) - assert.NoError(t, err) + poolname := GetUUID() + err := conn.MakePool(poolname) + assert.NoError(t, err) - pool, err := conn.OpenIOContext(poolname) - assert.NoError(t, err) + pool, err := conn.OpenIOContext(poolname) + assert.NoError(t, err) - // grab current stats - prev_stat, err := conn.GetClusterStats() - fmt.Printf("prev_stat: %+v\n", prev_stat) - assert.NoError(t, err) + // grab current stats + prev_stat, err := conn.GetClusterStats() + fmt.Printf("prev_stat: %+v\n", prev_stat) + assert.NoError(t, err) - // make some changes to the cluster - buf := make([]byte, 1<<20) - for i := 0; i < 10; i++ { - objname := GetUUID() - pool.Write(objname, buf, 0) - } + // make some changes to the cluster + buf := make([]byte, 1<<20) + for i := 0; i < 10; i++ { + objname := GetUUID() + pool.Write(objname, buf, 0) + } - // wait a while for the stats to change - for i := 0; i < 30; i++ { - stat, err := conn.GetClusterStats() - assert.NoError(t, err) + // wait a while for the stats to change + for i := 0; i < 30; i++ { + stat, err := conn.GetClusterStats() + assert.NoError(t, err) - // wait for something to change - if stat == prev_stat { - fmt.Printf("curr_stat: %+v (trying again...)\n", stat) - time.Sleep(time.Second) - } else { - // success - fmt.Printf("curr_stat: %+v (change detected)\n", stat) - conn.Shutdown() - return - } - } + // wait for something to change + if stat == prev_stat { + fmt.Printf("curr_stat: %+v (trying again...)\n", stat) + time.Sleep(time.Second) + } else { + // success + fmt.Printf("curr_stat: %+v (change detected)\n", stat) + conn.Shutdown() + return + } + } - pool.Destroy() - conn.Shutdown() - t.Error("Cluster stats aren't changing") + pool.Destroy() + conn.Shutdown() + t.Error("Cluster stats aren't changing") } func TestGetFSID(t *testing.T) { - conn, _ := rados.NewConn() - conn.ReadDefaultConfigFile() - conn.Connect() + conn, _ := rados.NewConn() + conn.ReadDefaultConfigFile() + conn.Connect() - fsid, err := conn.GetFSID() - assert.NoError(t, err) - assert.NotEqual(t, fsid, "") + fsid, err := conn.GetFSID() + assert.NoError(t, err) + assert.NotEqual(t, fsid, "") - conn.Shutdown() + conn.Shutdown() } func TestGetInstanceID(t *testing.T) { - conn, _ := rados.NewConn() - conn.ReadDefaultConfigFile() - conn.Connect() + conn, _ := rados.NewConn() + conn.ReadDefaultConfigFile() + conn.Connect() - id := conn.GetInstanceID() - assert.NotEqual(t, id, 0) + id := conn.GetInstanceID() + assert.NotEqual(t, id, 0) - conn.Shutdown() + conn.Shutdown() } func TestMakeDeletePool(t *testing.T) { - conn, _ := rados.NewConn() - conn.ReadDefaultConfigFile() - conn.Connect() + conn, _ := rados.NewConn() + conn.ReadDefaultConfigFile() + conn.Connect() - // get current list of pool - pools, err := conn.ListPools() - assert.NoError(t, err) + // get current list of pool + pools, err := conn.ListPools() + assert.NoError(t, err) - // check that new pool name is unique - new_name := GetUUID() - for _, poolname := range pools { - if new_name == poolname { - t.Error("Random pool name exists!") - return - } - } + // check that new pool name is unique + new_name := GetUUID() + for _, poolname := range pools { + if new_name == poolname { + t.Error("Random pool name exists!") + return + } + } - // create pool - err = conn.MakePool(new_name) - assert.NoError(t, err) + // create pool + err = conn.MakePool(new_name) + assert.NoError(t, err) - // get updated list of pools - pools, err = conn.ListPools() - assert.NoError(t, err) + // get updated list of pools + pools, err = conn.ListPools() + assert.NoError(t, err) - // verify that the new pool name exists - found := false - for _, poolname := range pools { - if new_name == poolname { - found = true - } - } + // verify that the new pool name exists + found := false + for _, poolname := range pools { + if new_name == poolname { + found = true + } + } - if !found { - t.Error("Cannot find newly created pool") - } + if !found { + t.Error("Cannot find newly created pool") + } - // delete the pool - err = conn.DeletePool(new_name) - assert.NoError(t, err) + // delete the pool + err = conn.DeletePool(new_name) + assert.NoError(t, err) - // verify that it is gone + // verify that it is gone - // get updated list of pools - pools, err = conn.ListPools() - assert.NoError(t, err) + // get updated list of pools + pools, err = conn.ListPools() + assert.NoError(t, err) - // verify that the new pool name exists - found = false - for _, poolname := range pools { - if new_name == poolname { - found = true - } - } + // verify that the new pool name exists + found = false + for _, poolname := range pools { + if new_name == poolname { + found = true + } + } - if found { - t.Error("Deleted pool still exists") - } + if found { + t.Error("Deleted pool still exists") + } - conn.Shutdown() + conn.Shutdown() } func TestPingMonitor(t *testing.T) { - conn, _ := rados.NewConn() - conn.ReadDefaultConfigFile() - conn.Connect() + conn, _ := rados.NewConn() + conn.ReadDefaultConfigFile() + conn.Connect() - // mon id that should work with vstart.sh - reply, err := conn.PingMonitor("a") - if err == nil { - assert.NotEqual(t, reply, "") - return - } + // mon id that should work with vstart.sh + reply, err := conn.PingMonitor("a") + if err == nil { + assert.NotEqual(t, reply, "") + return + } - // mon id that should work with micro-osd.sh - reply, err = conn.PingMonitor("0") - if err == nil { - assert.NotEqual(t, reply, "") - return - } + // mon id that should work with micro-osd.sh + reply, err = conn.PingMonitor("0") + if err == nil { + assert.NotEqual(t, reply, "") + return + } - // try to use a hostname as the monitor id - mon_addr, _ := conn.GetConfigOption("mon_host") - hosts, _ := net.LookupAddr(mon_addr) - for _, host := range hosts { - reply, err := conn.PingMonitor(host) - if err == nil { - assert.NotEqual(t, reply, "") - return - } - } + // try to use a hostname as the monitor id + mon_addr, _ := conn.GetConfigOption("mon_host") + hosts, _ := net.LookupAddr(mon_addr) + for _, host := range hosts { + reply, err := conn.PingMonitor(host) + if err == nil { + assert.NotEqual(t, reply, "") + return + } + } - t.Error("Could not find a valid monitor id") + t.Error("Could not find a valid monitor id") - conn.Shutdown() + conn.Shutdown() } func TestReadConfigFile(t *testing.T) { - conn, _ := rados.NewConn() + conn, _ := rados.NewConn() - // check current log_file value - log_file_val, err := conn.GetConfigOption("log_file") - assert.NoError(t, err) - assert.NotEqual(t, log_file_val, "/dev/null") + // check current log_file value + log_file_val, err := conn.GetConfigOption("log_file") + assert.NoError(t, err) + assert.NotEqual(t, log_file_val, "/dev/null") - // create a temporary ceph.conf file that changes the log_file conf - // option. - file, err := ioutil.TempFile("/tmp", "go-rados") - assert.NoError(t, err) + // create a temporary ceph.conf file that changes the log_file conf + // option. + file, err := ioutil.TempFile("/tmp", "go-rados") + assert.NoError(t, err) - _, err = io.WriteString(file, "[global]\nlog_file = /dev/null\n") - assert.NoError(t, err) + _, err = io.WriteString(file, "[global]\nlog_file = /dev/null\n") + assert.NoError(t, err) - // parse the config file - err = conn.ReadConfigFile(file.Name()) - assert.NoError(t, err) + // parse the config file + err = conn.ReadConfigFile(file.Name()) + assert.NoError(t, err) - // check current log_file value - log_file_val, err = conn.GetConfigOption("log_file") - assert.NoError(t, err) - assert.Equal(t, log_file_val, "/dev/null") + // check current log_file value + log_file_val, err = conn.GetConfigOption("log_file") + assert.NoError(t, err) + assert.Equal(t, log_file_val, "/dev/null") - // cleanup - file.Close() - os.Remove(file.Name()) + // cleanup + file.Close() + os.Remove(file.Name()) } func TestWaitForLatestOSDMap(t *testing.T) { - conn, _ := rados.NewConn() - conn.ReadDefaultConfigFile() - conn.Connect() + conn, _ := rados.NewConn() + conn.ReadDefaultConfigFile() + conn.Connect() - err := conn.WaitForLatestOSDMap() - assert.NoError(t, err) + err := conn.WaitForLatestOSDMap() + assert.NoError(t, err) - conn.Shutdown() + conn.Shutdown() } func TestReadWrite(t *testing.T) { - conn, _ := rados.NewConn() - conn.ReadDefaultConfigFile() - conn.Connect() + conn, _ := rados.NewConn() + conn.ReadDefaultConfigFile() + conn.Connect() - // make pool - pool_name := GetUUID() - err := conn.MakePool(pool_name) - assert.NoError(t, err) + // make pool + pool_name := GetUUID() + err := conn.MakePool(pool_name) + assert.NoError(t, err) - pool, err := conn.OpenIOContext(pool_name) - assert.NoError(t, err) + pool, err := conn.OpenIOContext(pool_name) + assert.NoError(t, err) - bytes_in := []byte("input data") - err = pool.Write("obj", bytes_in, 0) - assert.NoError(t, err) + bytes_in := []byte("input data") + err = pool.Write("obj", bytes_in, 0) + assert.NoError(t, err) - bytes_out := make([]byte, len(bytes_in)) - n_out, err := pool.Read("obj", bytes_out, 0) + bytes_out := make([]byte, len(bytes_in)) + n_out, err := pool.Read("obj", bytes_out, 0) - assert.Equal(t, n_out, len(bytes_in)) - assert.Equal(t, bytes_in, bytes_out) + assert.Equal(t, n_out, len(bytes_in)) + assert.Equal(t, bytes_in, bytes_out) - pool.Destroy() + pool.Destroy() } func TestGetPoolStats(t *testing.T) { - conn, _ := rados.NewConn() - conn.ReadDefaultConfigFile() - conn.Connect() + conn, _ := rados.NewConn() + conn.ReadDefaultConfigFile() + conn.Connect() - poolname := GetUUID() - err := conn.MakePool(poolname) - assert.NoError(t, err) + poolname := GetUUID() + err := conn.MakePool(poolname) + assert.NoError(t, err) - pool, err := conn.OpenIOContext(poolname) - assert.NoError(t, err) + pool, err := conn.OpenIOContext(poolname) + assert.NoError(t, err) - // grab current stats - prev_stat, err := pool.GetPoolStats() - fmt.Printf("prev_stat: %+v\n", prev_stat) - assert.NoError(t, err) + // grab current stats + prev_stat, err := pool.GetPoolStats() + fmt.Printf("prev_stat: %+v\n", prev_stat) + assert.NoError(t, err) - // make some changes to the cluster - buf := make([]byte, 1<<20) - for i := 0; i < 10; i++ { - objname := GetUUID() - pool.Write(objname, buf, 0) - } + // make some changes to the cluster + buf := make([]byte, 1<<20) + for i := 0; i < 10; i++ { + objname := GetUUID() + pool.Write(objname, buf, 0) + } - // wait a while for the stats to change - for i := 0; i < 30; i++ { - stat, err := pool.GetPoolStats() - assert.NoError(t, err) + // wait a while for the stats to change + for i := 0; i < 30; i++ { + stat, err := pool.GetPoolStats() + assert.NoError(t, err) - // wait for something to change - if stat == prev_stat { - fmt.Printf("curr_stat: %+v (trying again...)\n", stat) - time.Sleep(time.Second) - } else { - // success - fmt.Printf("curr_stat: %+v (change detected)\n", stat) - conn.Shutdown() - return - } - } + // wait for something to change + if stat == prev_stat { + fmt.Printf("curr_stat: %+v (trying again...)\n", stat) + time.Sleep(time.Second) + } else { + // success + fmt.Printf("curr_stat: %+v (change detected)\n", stat) + conn.Shutdown() + return + } + } - pool.Destroy() - conn.Shutdown() - t.Error("Pool stats aren't changing") + pool.Destroy() + conn.Shutdown() + t.Error("Pool stats aren't changing") } func TestGetPoolName(t *testing.T) { - conn, _ := rados.NewConn() - conn.ReadDefaultConfigFile() - conn.Connect() + conn, _ := rados.NewConn() + conn.ReadDefaultConfigFile() + conn.Connect() - poolname := GetUUID() - err := conn.MakePool(poolname) - assert.NoError(t, err) + poolname := GetUUID() + err := conn.MakePool(poolname) + assert.NoError(t, err) - ioctx, err := conn.OpenIOContext(poolname) - assert.NoError(t, err) + ioctx, err := conn.OpenIOContext(poolname) + assert.NoError(t, err) - poolname_ret, err := ioctx.GetPoolName() - assert.NoError(t, err) + poolname_ret, err := ioctx.GetPoolName() + assert.NoError(t, err) - assert.Equal(t, poolname, poolname_ret) + assert.Equal(t, poolname, poolname_ret) - ioctx.Destroy() - conn.Shutdown() + ioctx.Destroy() + conn.Shutdown() } func TestMonCommand(t *testing.T) { conn, _ := rados.NewConn() - conn.ReadDefaultConfigFile() - conn.Connect() + conn.ReadDefaultConfigFile() + conn.Connect() command, err := json.Marshal(map[string]string{"prefix": "df", "format": "json"}) assert.NoError(t, err) @@ -388,50 +389,50 @@ func TestMonCommand(t *testing.T) { assert.NoError(t, err) assert.Equal(t, info, "") - var message map[string]interface{} + var message map[string]interface{} err = json.Unmarshal(buf, &message) assert.NoError(t, err) - conn.Shutdown() + conn.Shutdown() } func TestObjectIterator(t *testing.T) { - conn, _ := rados.NewConn() - conn.ReadDefaultConfigFile() - conn.Connect() + conn, _ := rados.NewConn() + conn.ReadDefaultConfigFile() + conn.Connect() - poolname := GetUUID() - err := conn.MakePool(poolname) - assert.NoError(t, err) + poolname := GetUUID() + err := conn.MakePool(poolname) + assert.NoError(t, err) - ioctx, err := conn.OpenIOContext(poolname) - assert.NoError(t, err) + ioctx, err := conn.OpenIOContext(poolname) + assert.NoError(t, err) - objectList := []string{} - err = ioctx.ListObjects(func(oid string) { - objectList = append(objectList, oid) - }) - assert.NoError(t, err) - assert.True(t, len(objectList) == 0) + objectList := []string{} + err = ioctx.ListObjects(func(oid string) { + objectList = append(objectList, oid) + }) + assert.NoError(t, err) + assert.True(t, len(objectList) == 0) - createdList := []string{} - for i := 0; i < 200; i++ { - oid := GetUUID() - bytes_in := []byte("input data") - err = ioctx.Write(oid, bytes_in, 0) - assert.NoError(t, err) - createdList = append(createdList, oid) - } - assert.True(t, len(createdList) == 200) + createdList := []string{} + for i := 0; i < 200; i++ { + oid := GetUUID() + bytes_in := []byte("input data") + err = ioctx.Write(oid, bytes_in, 0) + assert.NoError(t, err) + createdList = append(createdList, oid) + } + assert.True(t, len(createdList) == 200) - err = ioctx.ListObjects(func(oid string) { - objectList = append(objectList, oid) - }) - assert.NoError(t, err) - assert.Equal(t, len(objectList), len(createdList)) + err = ioctx.ListObjects(func(oid string) { + objectList = append(objectList, oid) + }) + assert.NoError(t, err) + assert.Equal(t, len(objectList), len(createdList)) - sort.Strings(objectList) - sort.Strings(createdList) + sort.Strings(objectList) + sort.Strings(createdList) - assert.Equal(t, objectList, createdList) + assert.Equal(t, objectList, createdList) } diff --git a/rbd/rbd.go b/rbd/rbd.go index 8f2c922..ef7e1f1 100644 --- a/rbd/rbd.go +++ b/rbd/rbd.go @@ -7,125 +7,126 @@ package rbd import "C" import ( - "github.com/noahdesu/go-ceph/rados" - "fmt" - "unsafe" - "bytes" - "errors" - "io" + "bytes" + "errors" + "fmt" + "github.com/noahdesu/go-ceph/rados" + "io" + "unsafe" ) // type RBDError int + var ImageNotOpen = errors.New("RBD image not open") // type ImageInfo struct { - Size uint64 - Obj_size uint64 - Num_objs uint64 - Order int - Block_name_prefix string - Parent_pool int64 - Parent_name string + Size uint64 + Obj_size uint64 + Num_objs uint64 + Order int + Block_name_prefix string + Parent_pool int64 + Parent_name string } // type SnapInfo struct { - Id uint64 - Size uint64 - Name string + Id uint64 + Size uint64 + Name string } // type Locker struct { - Client string - Cookie string - Addr string + Client string + Cookie string + Addr string } // type Image struct { - io.Reader - io.Writer - io.Seeker - io.ReaderAt - io.WriterAt - name string - offset int64 - ioctx *rados.IOContext - image C.rbd_image_t + io.Reader + io.Writer + io.Seeker + io.ReaderAt + io.WriterAt + name string + offset int64 + ioctx *rados.IOContext + image C.rbd_image_t } // type Snapshot struct { - image *Image - name string + image *Image + name string } // func split(buf []byte) (values []string) { - tmp := bytes.Split(buf[:len(buf)-1], []byte{0}) - for _, s := range tmp { - if len(s) > 0 { - go_s := C.GoString((*C.char)(unsafe.Pointer(&s[0]))) - values = append(values, go_s) - } - } - return values + tmp := bytes.Split(buf[:len(buf)-1], []byte{0}) + for _, s := range tmp { + if len(s) > 0 { + go_s := C.GoString((*C.char)(unsafe.Pointer(&s[0]))) + values = append(values, go_s) + } + } + return values } // func (e RBDError) Error() string { - return fmt.Sprintf("rbd: ret=%d", e) + return fmt.Sprintf("rbd: ret=%d", e) } // func GetError(err C.int) error { - if err != 0 { - return RBDError(err) - } else { - return nil - } + if err != 0 { + return RBDError(err) + } else { + return nil + } } // func Version() (int, int, int) { - var c_major, c_minor, c_patch C.int - C.rbd_version(&c_major, &c_minor, &c_patch) - return int(c_major), int(c_minor), int(c_patch) + var c_major, c_minor, c_patch C.int + C.rbd_version(&c_major, &c_minor, &c_patch) + return int(c_major), int(c_minor), int(c_patch) } // 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 == -34 { // FIXME - 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 - } + 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 == -34 { // FIXME + 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 + } } // func GetImage(ioctx *rados.IOContext, name string) *Image { - return &Image{ - ioctx: ioctx, - name: name, - } + return &Image{ + ioctx: ioctx, + name: name, + } } // int rbd_create(rados_ioctx_t io, const char *name, uint64_t size, int *order); @@ -135,37 +136,37 @@ func GetImage(ioctx *rados.IOContext, name string) *Image { // uint64_t features, int *order, // uint64_t stripe_unit, uint64_t stripe_count); func Create(ioctx *rados.IOContext, name string, size uint64, - args ...uint64) (image *Image, err error) { - var ret C.int - var c_order C.int - var c_name *C.char = C.CString(name) - defer C.free(unsafe.Pointer(c_name)) + args ...uint64) (image *Image, err error) { + var ret C.int + var c_order C.int + var c_name *C.char = C.CString(name) + defer C.free(unsafe.Pointer(c_name)) - switch len(args) { - case 2: - ret = C.rbd_create3(C.rados_ioctx_t(ioctx.Pointer()), - c_name, C.uint64_t(size), - C.uint64_t(args[0]), &c_order, - C.uint64_t(args[1]), C.uint64_t(args[2])) - case 1: - ret = C.rbd_create2(C.rados_ioctx_t(ioctx.Pointer()), - c_name, C.uint64_t(size), - C.uint64_t(args[0]), &c_order) - case 0: - ret = C.rbd_create(C.rados_ioctx_t(ioctx.Pointer()), - c_name, C.uint64_t(size), &c_order) - default: - return nil, errors.New("Wrong number of argument") - } + switch len(args) { + case 2: + ret = C.rbd_create3(C.rados_ioctx_t(ioctx.Pointer()), + c_name, C.uint64_t(size), + C.uint64_t(args[0]), &c_order, + C.uint64_t(args[1]), C.uint64_t(args[2])) + case 1: + ret = C.rbd_create2(C.rados_ioctx_t(ioctx.Pointer()), + c_name, C.uint64_t(size), + C.uint64_t(args[0]), &c_order) + case 0: + ret = C.rbd_create(C.rados_ioctx_t(ioctx.Pointer()), + c_name, C.uint64_t(size), &c_order) + default: + return nil, errors.New("Wrong number of argument") + } - if ret < 0 { - return nil, RBDError(int(ret)) - } + if ret < 0 { + return nil, RBDError(int(ret)) + } - return &Image{ - ioctx: ioctx, - name: name, - }, nil + return &Image{ + ioctx: ioctx, + name: name, + }, nil } // int rbd_clone(rados_ioctx_t p_ioctx, const char *p_name, @@ -176,225 +177,225 @@ func Create(ioctx *rados.IOContext, name string, size uint64, // const char *c_name, uint64_t features, int *c_order, // uint64_t stripe_unit, int stripe_count); func (image *Image) Clone(snapname string, c_ioctx *rados.IOContext, c_name string, features uint64) (*Image, error) { - var c_order C.int; - var c_p_name *C.char = C.CString(image.name) - var c_p_snapname *C.char = C.CString(snapname) - var c_c_name *C.char = C.CString(c_name) - defer C.free(unsafe.Pointer(c_p_name)) - defer C.free(unsafe.Pointer(c_p_snapname)) - defer C.free(unsafe.Pointer(c_c_name)) + var c_order C.int + var c_p_name *C.char = C.CString(image.name) + var c_p_snapname *C.char = C.CString(snapname) + var c_c_name *C.char = C.CString(c_name) + defer C.free(unsafe.Pointer(c_p_name)) + defer C.free(unsafe.Pointer(c_p_snapname)) + defer C.free(unsafe.Pointer(c_c_name)) - ret := C.rbd_clone(C.rados_ioctx_t(image.ioctx.Pointer()), - c_p_name, c_p_snapname, - C.rados_ioctx_t(c_ioctx.Pointer()), - c_c_name, C.uint64_t(features), &c_order) - if ret < 0 { - return nil, RBDError(int(ret)) - } + ret := C.rbd_clone(C.rados_ioctx_t(image.ioctx.Pointer()), + c_p_name, c_p_snapname, + C.rados_ioctx_t(c_ioctx.Pointer()), + c_c_name, C.uint64_t(features), &c_order) + if ret < 0 { + return nil, RBDError(int(ret)) + } - return &Image{ - ioctx: c_ioctx, - name: c_name, - }, nil + return &Image{ + ioctx: c_ioctx, + name: c_name, + }, nil } // int rbd_remove(rados_ioctx_t io, const char *name); // int rbd_remove_with_progress(rados_ioctx_t io, const char *name, // librbd_progress_fn_t cb, void *cbdata); func (image *Image) Remove() error { - var c_name *C.char = C.CString(image.name) - defer C.free(unsafe.Pointer(c_name)) - return GetError(C.rbd_remove(C.rados_ioctx_t(image.ioctx.Pointer()), c_name)) + var c_name *C.char = C.CString(image.name) + defer C.free(unsafe.Pointer(c_name)) + return GetError(C.rbd_remove(C.rados_ioctx_t(image.ioctx.Pointer()), c_name)) } // int rbd_rename(rados_ioctx_t src_io_ctx, const char *srcname, const char *destname); func (image *Image) Rename(destname string) error { - var c_srcname *C.char = C.CString(image.name) - var c_destname *C.char = C.CString(destname) - defer C.free(unsafe.Pointer(c_srcname)) - defer C.free(unsafe.Pointer(c_destname)) - err := RBDError(C.rbd_rename(C.rados_ioctx_t(image.ioctx.Pointer()), - c_srcname, c_destname)) - if err == 0 { - image.name = destname - return nil - } - return err + var c_srcname *C.char = C.CString(image.name) + var c_destname *C.char = C.CString(destname) + defer C.free(unsafe.Pointer(c_srcname)) + defer C.free(unsafe.Pointer(c_destname)) + err := RBDError(C.rbd_rename(C.rados_ioctx_t(image.ioctx.Pointer()), + c_srcname, c_destname)) + if err == 0 { + image.name = destname + return nil + } + return err } // int rbd_open(rados_ioctx_t io, const char *name, rbd_image_t *image, const char *snap_name); // int rbd_open_read_only(rados_ioctx_t io, const char *name, rbd_image_t *image, // const char *snap_name); func (image *Image) Open(args ...interface{}) error { - var c_image C.rbd_image_t - var c_name *C.char = C.CString(image.name) - var c_snap_name *C.char - var ret C.int - var read_only bool = false + var c_image C.rbd_image_t + var c_name *C.char = C.CString(image.name) + var c_snap_name *C.char + var ret C.int + var read_only bool = false - defer C.free(unsafe.Pointer(c_name)) - for _, arg := range args { - switch t := arg.(type) { - case string: - if t != "" { - c_snap_name = C.CString(t) - defer C.free(unsafe.Pointer(c_snap_name)) - } - case bool: - read_only = t - default: - return errors.New("Unexpected argument") - } - } + defer C.free(unsafe.Pointer(c_name)) + for _, arg := range args { + switch t := arg.(type) { + case string: + if t != "" { + c_snap_name = C.CString(t) + defer C.free(unsafe.Pointer(c_snap_name)) + } + case bool: + read_only = t + default: + return errors.New("Unexpected argument") + } + } - if (read_only) { - ret = C.rbd_open_read_only(C.rados_ioctx_t(image.ioctx.Pointer()), c_name, - &c_image, c_snap_name) - } else { - ret = C.rbd_open(C.rados_ioctx_t(image.ioctx.Pointer()), c_name, - &c_image, c_snap_name) - } + if read_only { + ret = C.rbd_open_read_only(C.rados_ioctx_t(image.ioctx.Pointer()), c_name, + &c_image, c_snap_name) + } else { + ret = C.rbd_open(C.rados_ioctx_t(image.ioctx.Pointer()), c_name, + &c_image, c_snap_name) + } - image.image = c_image + image.image = c_image - if ret != 0 { - return RBDError(ret) - } - return nil + if ret != 0 { + return RBDError(ret) + } + return nil } // int rbd_close(rbd_image_t image); func (image *Image) Close() error { - if image.image == nil { - return ImageNotOpen - } + if image.image == nil { + return ImageNotOpen + } - ret := C.rbd_close(image.image) - if ret != 0 { - return RBDError(ret) - } - image.image = nil - return nil + ret := C.rbd_close(image.image) + if ret != 0 { + return RBDError(ret) + } + image.image = nil + return nil } // int rbd_resize(rbd_image_t image, uint64_t size); func (image *Image) Resize(size uint64) error { - if image.image == nil { - return ImageNotOpen - } + if image.image == nil { + return ImageNotOpen + } - return GetError(C.rbd_resize(image.image, C.uint64_t(size))) + return GetError(C.rbd_resize(image.image, C.uint64_t(size))) } // int rbd_stat(rbd_image_t image, rbd_image_info_t *info, size_t infosize); func (image *Image) Stat() (info *ImageInfo, err error) { - if image.image == nil { - return nil, ImageNotOpen - } + if image.image == nil { + return nil, ImageNotOpen + } - var c_stat C.rbd_image_info_t - ret := C.rbd_stat(image.image, - &c_stat, C.size_t(unsafe.Sizeof(info))) - if ret < 0 { - return info, RBDError(int(ret)) - } + var c_stat C.rbd_image_info_t + ret := C.rbd_stat(image.image, + &c_stat, C.size_t(unsafe.Sizeof(info))) + if ret < 0 { + return info, RBDError(int(ret)) + } - return &ImageInfo{ - Size: uint64(c_stat.size), - Obj_size: uint64(c_stat.obj_size), - Num_objs: uint64(c_stat.num_objs), - Order: int(c_stat.order), - Block_name_prefix: C.GoString((*C.char)(&c_stat.block_name_prefix[0])), - Parent_pool: int64(c_stat.parent_pool), - Parent_name: C.GoString((*C.char)(&c_stat.parent_name[0]))}, nil + return &ImageInfo{ + Size: uint64(c_stat.size), + Obj_size: uint64(c_stat.obj_size), + Num_objs: uint64(c_stat.num_objs), + Order: int(c_stat.order), + Block_name_prefix: C.GoString((*C.char)(&c_stat.block_name_prefix[0])), + Parent_pool: int64(c_stat.parent_pool), + Parent_name: C.GoString((*C.char)(&c_stat.parent_name[0]))}, nil } // int rbd_get_old_format(rbd_image_t image, uint8_t *old); func (image *Image) IsOldFormat() (old_format bool, err error) { - if image.image == nil { - return false, ImageNotOpen - } + if image.image == nil { + return false, ImageNotOpen + } - var c_old_format C.uint8_t - ret := C.rbd_get_old_format(image.image, - &c_old_format) - if ret < 0 { - return false, RBDError(int(ret)) - } + var c_old_format C.uint8_t + ret := C.rbd_get_old_format(image.image, + &c_old_format) + if ret < 0 { + return false, RBDError(int(ret)) + } - return c_old_format != 0, nil + return c_old_format != 0, nil } // int rbd_size(rbd_image_t image, uint64_t *size); func (image *Image) GetSize() (size uint64, err error) { - if image.image == nil { - return 0, ImageNotOpen - } + if image.image == nil { + return 0, ImageNotOpen + } - ret := C.rbd_get_size(image.image, - (*C.uint64_t)(&size)) - if ret < 0 { - return 0, RBDError(int(ret)) - } + ret := C.rbd_get_size(image.image, + (*C.uint64_t)(&size)) + if ret < 0 { + return 0, RBDError(int(ret)) + } - return size, nil + return size, nil } // int rbd_get_features(rbd_image_t image, uint64_t *features); func (image *Image) GetFeatures() (features uint64, err error) { - if image.image == nil { - return 0, ImageNotOpen - } + if image.image == nil { + return 0, ImageNotOpen + } - ret := C.rbd_get_features(image.image, - (*C.uint64_t)(&features)) - if ret < 0 { - return 0, RBDError(int(ret)) - } + ret := C.rbd_get_features(image.image, + (*C.uint64_t)(&features)) + if ret < 0 { + return 0, RBDError(int(ret)) + } - return features, nil + return features, nil } // int rbd_get_stripe_unit(rbd_image_t image, uint64_t *stripe_unit); func (image *Image) GetStripeUnit() (stripe_unit uint64, err error) { - if image.image == nil { - return 0, ImageNotOpen - } + if image.image == nil { + return 0, ImageNotOpen + } - ret := C.rbd_get_stripe_unit(image.image, (*C.uint64_t)(&stripe_unit)) - if ret < 0 { - return 0, RBDError(int(ret)) - } + ret := C.rbd_get_stripe_unit(image.image, (*C.uint64_t)(&stripe_unit)) + if ret < 0 { + return 0, RBDError(int(ret)) + } - return stripe_unit, nil + return stripe_unit, nil } // int rbd_get_stripe_count(rbd_image_t image, uint64_t *stripe_count); func (image *Image) GetStripeCount() (stripe_count uint64, err error) { - if image.image == nil { - return 0, ImageNotOpen - } + if image.image == nil { + return 0, ImageNotOpen + } - ret := C.rbd_get_stripe_count(image.image, (*C.uint64_t)(&stripe_count)) - if ret < 0 { - return 0, RBDError(int(ret)) - } + ret := C.rbd_get_stripe_count(image.image, (*C.uint64_t)(&stripe_count)) + if ret < 0 { + return 0, RBDError(int(ret)) + } - return stripe_count, nil + return stripe_count, nil } // int rbd_get_overlap(rbd_image_t image, uint64_t *overlap); func (image *Image) GetOverlap() (overlap uint64, err error) { - if image.image == nil { - return 0, ImageNotOpen - } + if image.image == nil { + return 0, ImageNotOpen + } - ret := C.rbd_get_overlap(image.image, (*C.uint64_t)(&overlap)) - if ret < 0 { - return overlap, RBDError(int(ret)) - } + ret := C.rbd_get_overlap(image.image, (*C.uint64_t)(&overlap)) + if ret < 0 { + return overlap, RBDError(int(ret)) + } - return overlap, nil + return overlap, nil } // int rbd_copy(rbd_image_t image, rados_ioctx_t dest_io_ctx, const char *destname); @@ -404,89 +405,89 @@ func (image *Image) GetOverlap() (overlap uint64, err error) { // int rbd_copy_with_progress2(rbd_image_t src, rbd_image_t dest, // librbd_progress_fn_t cb, void *cbdata); func (image *Image) Copy(args ...interface{}) error { - if image.image == nil { - return ImageNotOpen - } + if image.image == nil { + return ImageNotOpen + } - switch t := args[0].(type) { - case rados.IOContext: - switch t2 := args[1].(type) { - case string: - var c_destname *C.char = C.CString(t2) - defer C.free(unsafe.Pointer(c_destname)) - return RBDError(C.rbd_copy(image.image, - C.rados_ioctx_t(t.Pointer()), - c_destname)) - default: - return errors.New("Must specify destname") - } - case Image: - var dest Image = t - if dest.image == nil { - return errors.New(fmt.Sprintf("RBD image %s is not open", dest.name)) - } - return GetError(C.rbd_copy2(image.image, - dest.image)) - default: - return errors.New("Must specify either destination pool " + - "or destination image") - } + switch t := args[0].(type) { + case rados.IOContext: + switch t2 := args[1].(type) { + case string: + var c_destname *C.char = C.CString(t2) + defer C.free(unsafe.Pointer(c_destname)) + return RBDError(C.rbd_copy(image.image, + C.rados_ioctx_t(t.Pointer()), + c_destname)) + default: + return errors.New("Must specify destname") + } + case Image: + var dest Image = t + if dest.image == nil { + return errors.New(fmt.Sprintf("RBD image %s is not open", dest.name)) + } + return GetError(C.rbd_copy2(image.image, + dest.image)) + default: + return errors.New("Must specify either destination pool " + + "or destination image") + } } // int rbd_flatten(rbd_image_t image); func (image *Image) Flatten() error { - if image.image == nil { - return errors.New(fmt.Sprintf("RBD image %s is not open", image.name)) - } + if image.image == nil { + return errors.New(fmt.Sprintf("RBD image %s is not open", image.name)) + } - return GetError(C.rbd_flatten(image.image)) + return GetError(C.rbd_flatten(image.image)) } // 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 image.image == nil { - return nil, nil, ImageNotOpen - } + if image.image == nil { + return nil, nil, ImageNotOpen + } - var c_pools_len, c_images_len C.size_t + 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, RBDError(int(ret)) - } + ret := C.rbd_list_children(image.image, + nil, &c_pools_len, + nil, &c_images_len) + if ret < 0 { + return nil, nil, RBDError(int(ret)) + } - pools_buf := make([]byte, c_pools_len) - images_buf := make([]byte, c_images_len) + 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(int(ret)) - } + 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(int(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(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) - } - } + 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 + return pools, images, nil } // ssize_t rbd_list_lockers(rbd_image_t image, int *exclusive, @@ -495,94 +496,94 @@ func (image *Image) ListChildren() (pools []string, images []string, err error) // char *cookies, size_t *cookies_len, // char *addrs, size_t *addrs_len); func (image *Image) ListLockers() (tag string, lockers []Locker, err error) { - if image.image == nil { - return "", nil, ImageNotOpen - } + if image.image == nil { + return "", nil, ImageNotOpen + } - var c_exclusive C.int - var c_tag_len, c_clients_len, c_cookies_len, c_addrs_len C.size_t + var c_exclusive C.int + var c_tag_len, c_clients_len, c_cookies_len, c_addrs_len C.size_t - C.rbd_list_lockers(image.image, &c_exclusive, - nil, (*C.size_t)(&c_tag_len), - nil, (*C.size_t)(&c_clients_len), - nil, (*C.size_t)(&c_cookies_len), - nil, (*C.size_t)(&c_addrs_len)) + C.rbd_list_lockers(image.image, &c_exclusive, + nil, (*C.size_t)(&c_tag_len), + nil, (*C.size_t)(&c_clients_len), + nil, (*C.size_t)(&c_cookies_len), + nil, (*C.size_t)(&c_addrs_len)) - tag_buf := make([]byte, c_tag_len) - clients_buf := make([]byte, c_clients_len) - cookies_buf := make([]byte, c_cookies_len) - addrs_buf := make([]byte, c_addrs_len) + tag_buf := make([]byte, c_tag_len) + clients_buf := make([]byte, c_clients_len) + cookies_buf := make([]byte, c_cookies_len) + addrs_buf := make([]byte, c_addrs_len) - C.rbd_list_lockers(image.image, &c_exclusive, - (*C.char)(unsafe.Pointer(&tag_buf[0])), (*C.size_t)(&c_tag_len), - (*C.char)(unsafe.Pointer(&clients_buf[0])), (*C.size_t)(&c_clients_len), - (*C.char)(unsafe.Pointer(&cookies_buf[0])), (*C.size_t)(&c_cookies_len), - (*C.char)(unsafe.Pointer(&addrs_buf[0])), (*C.size_t)(&c_addrs_len)) + C.rbd_list_lockers(image.image, &c_exclusive, + (*C.char)(unsafe.Pointer(&tag_buf[0])), (*C.size_t)(&c_tag_len), + (*C.char)(unsafe.Pointer(&clients_buf[0])), (*C.size_t)(&c_clients_len), + (*C.char)(unsafe.Pointer(&cookies_buf[0])), (*C.size_t)(&c_cookies_len), + (*C.char)(unsafe.Pointer(&addrs_buf[0])), (*C.size_t)(&c_addrs_len)) - clients := split(clients_buf) - cookies := split(cookies_buf) - addrs := split(addrs_buf) + clients := split(clients_buf) + cookies := split(cookies_buf) + addrs := split(addrs_buf) - lockers = make([]Locker, c_clients_len) - for i := 0; i < int(c_clients_len); i++ { - lockers[i] = Locker{Client: clients[i], - Cookie: cookies[i], - Addr: addrs[i]} - } + lockers = make([]Locker, c_clients_len) + for i := 0; i < int(c_clients_len); i++ { + lockers[i] = Locker{Client: clients[i], + Cookie: cookies[i], + Addr: addrs[i]} + } - return string(tag_buf), lockers, nil + return string(tag_buf), lockers, nil } // int rbd_lock_exclusive(rbd_image_t image, const char *cookie); func (image *Image) LockExclusive(cookie string) error { - if image.image == nil { - return ImageNotOpen - } + if image.image == nil { + return ImageNotOpen + } - var c_cookie *C.char = C.CString(cookie) - defer C.free(unsafe.Pointer(c_cookie)) + var c_cookie *C.char = C.CString(cookie) + defer C.free(unsafe.Pointer(c_cookie)) - return GetError(C.rbd_lock_exclusive(image.image, c_cookie)) + return GetError(C.rbd_lock_exclusive(image.image, c_cookie)) } // int rbd_lock_shared(rbd_image_t image, const char *cookie, const char *tag); func (image *Image) LockShared(cookie string, tag string) error { - if image.image == nil { - return ImageNotOpen - } + if image.image == nil { + return ImageNotOpen + } - var c_cookie *C.char = C.CString(cookie) - var c_tag *C.char = C.CString(tag) - defer C.free(unsafe.Pointer(c_cookie)) - defer C.free(unsafe.Pointer(c_tag)) + var c_cookie *C.char = C.CString(cookie) + var c_tag *C.char = C.CString(tag) + defer C.free(unsafe.Pointer(c_cookie)) + defer C.free(unsafe.Pointer(c_tag)) - return GetError(C.rbd_lock_shared(image.image, c_cookie, c_tag)) + return GetError(C.rbd_lock_shared(image.image, c_cookie, c_tag)) } // int rbd_lock_shared(rbd_image_t image, const char *cookie, const char *tag); func (image *Image) Unlock(cookie string) error { - if image.image == nil { - return ImageNotOpen - } + if image.image == nil { + return ImageNotOpen + } - var c_cookie *C.char = C.CString(cookie) - defer C.free(unsafe.Pointer(c_cookie)) + var c_cookie *C.char = C.CString(cookie) + defer C.free(unsafe.Pointer(c_cookie)) - return GetError(C.rbd_unlock(image.image, c_cookie)) + return GetError(C.rbd_unlock(image.image, c_cookie)) } // int rbd_break_lock(rbd_image_t image, const char *client, const char *cookie); func (image *Image) BreakLock(client string, cookie string) error { - if image.image == nil { - return ImageNotOpen - } + if image.image == nil { + return ImageNotOpen + } - var c_client *C.char = C.CString(client) - var c_cookie *C.char = C.CString(cookie) - defer C.free(unsafe.Pointer(c_client)) - defer C.free(unsafe.Pointer(c_cookie)) + var c_client *C.char = C.CString(client) + var c_cookie *C.char = C.CString(cookie) + defer C.free(unsafe.Pointer(c_client)) + defer C.free(unsafe.Pointer(c_cookie)) - return GetError(C.rbd_break_lock(image.image, c_client, c_cookie)) + return GetError(C.rbd_break_lock(image.image, c_client, c_cookie)) } // ssize_t rbd_read(rbd_image_t image, uint64_t ofs, size_t len, char *buf); @@ -595,205 +596,205 @@ func (image *Image) BreakLock(client string, cookie string) error { // uint64_t ofs, uint64_t len, // int (*cb)(uint64_t, size_t, int, void *), void *arg); func (image *Image) Read(data []byte) (n int, err error) { - if image.image == nil { - return 0, ImageNotOpen - } + if image.image == nil { + return 0, ImageNotOpen + } - if len(data) == 0 { - return 0, nil - } + if len(data) == 0 { + return 0, nil + } - ret := int(C.rbd_read( - image.image, - (C.uint64_t)(image.offset), - (C.size_t)(len(data)), - (*C.char)(unsafe.Pointer(&data[0])))) + ret := int(C.rbd_read( + image.image, + (C.uint64_t)(image.offset), + (C.size_t)(len(data)), + (*C.char)(unsafe.Pointer(&data[0])))) - if ret < 0 { - return 0, RBDError(ret) - } + if ret < 0 { + return 0, RBDError(ret) + } - image.offset += int64(ret) - if ret < n { - return ret, io.EOF - } + image.offset += int64(ret) + if ret < n { + return ret, io.EOF + } - return ret, nil + return ret, nil } // ssize_t rbd_write(rbd_image_t image, uint64_t ofs, size_t len, const char *buf); func (image *Image) Write(data []byte) (n int, err error) { - ret := int(C.rbd_write(image.image, C.uint64_t(image.offset), - C.size_t(len(data)), (*C.char)(unsafe.Pointer(&data[0])))) + ret := int(C.rbd_write(image.image, C.uint64_t(image.offset), + C.size_t(len(data)), (*C.char)(unsafe.Pointer(&data[0])))) - if ret >= 0 { - image.offset += int64(ret) - } + if ret >= 0 { + image.offset += int64(ret) + } - if ret != len(data) { - err = RBDError(-1) - } + if ret != len(data) { + err = RBDError(-1) + } - return ret, err + return ret, err } func (image *Image) Seek(offset int64, whence int) (int64, error) { - switch whence { - case 0: - image.offset = offset - case 1: - image.offset += offset - case 2: - stats, err := image.Stat() - if err != nil { - return 0, err - } - image.offset = int64(stats.Size) - offset - default: - return 0, errors.New("Wrong value for whence") - } - return image.offset, nil + switch whence { + case 0: + image.offset = offset + case 1: + image.offset += offset + case 2: + stats, err := image.Stat() + if err != nil { + return 0, err + } + image.offset = int64(stats.Size) - offset + default: + return 0, errors.New("Wrong value for whence") + } + return image.offset, nil } // int rbd_discard(rbd_image_t image, uint64_t ofs, uint64_t len); func (image *Image) Discard(ofs uint64, length uint64) error { - return RBDError(C.rbd_discard(image.image, C.uint64_t(ofs), - C.uint64_t(length))) + return RBDError(C.rbd_discard(image.image, C.uint64_t(ofs), + C.uint64_t(length))) } func (image *Image) ReadAt(data []byte, off int64) (n int, err error) { - _, err = image.Seek(off, 0) - if err != nil { - return 0, err - } - return image.Read(data) + _, err = image.Seek(off, 0) + if err != nil { + return 0, err + } + return image.Read(data) } func (image *Image) WriteAt(data []byte, off int64) (n int, err error) { - _, err = image.Seek(off, 0) - if err != nil { - return 0, err - } - return image.Write(data) + _, err = image.Seek(off, 0) + if err != nil { + return 0, err + } + return image.Write(data) } // int rbd_flush(rbd_image_t image); func (image *Image) Flush() error { - return GetError(C.rbd_flush(image.image)) + return GetError(C.rbd_flush(image.image)) } // int rbd_snap_list(rbd_image_t image, rbd_snap_info_t *snaps, int *max_snaps); // void rbd_snap_list_end(rbd_snap_info_t *snaps); func (image *Image) GetSnapshotNames() (snaps []SnapInfo, err error) { - if image.image == nil { - return nil, ImageNotOpen - } + if image.image == nil { + return nil, ImageNotOpen + } - var c_max_snaps C.int = 0 + var c_max_snaps C.int = 0 - ret := C.rbd_snap_list(image.image, nil, &c_max_snaps) + ret := C.rbd_snap_list(image.image, nil, &c_max_snaps) - c_snaps := make([]C.rbd_snap_info_t, c_max_snaps) - snaps = make([]SnapInfo, c_max_snaps) + c_snaps := make([]C.rbd_snap_info_t, c_max_snaps) + snaps = make([]SnapInfo, c_max_snaps) - ret = C.rbd_snap_list(image.image, - &c_snaps[0], &c_max_snaps) - if ret < 0 { - return nil, RBDError(int(ret)) - } + ret = C.rbd_snap_list(image.image, + &c_snaps[0], &c_max_snaps) + if ret < 0 { + return nil, RBDError(int(ret)) + } - for i, s := range c_snaps { - snaps[i] = SnapInfo{Id: uint64(s.id), - Size: uint64(s.size), - Name: C.GoString(s.name)} - } + for i, s := range c_snaps { + snaps[i] = SnapInfo{Id: uint64(s.id), + Size: uint64(s.size), + Name: C.GoString(s.name)} + } - C.rbd_snap_list_end(&c_snaps[0]) - return snaps[:len(snaps)-1], nil + C.rbd_snap_list_end(&c_snaps[0]) + return snaps[:len(snaps)-1], nil } // int rbd_snap_create(rbd_image_t image, const char *snapname); func (image *Image) CreateSnapshot(snapname string) (*Snapshot, error) { - if image.image == nil { - return nil, ImageNotOpen - } + if image.image == nil { + return nil, ImageNotOpen + } - var c_snapname *C.char = C.CString(snapname) - defer C.free(unsafe.Pointer(c_snapname)) + var c_snapname *C.char = C.CString(snapname) + defer C.free(unsafe.Pointer(c_snapname)) - ret := C.rbd_snap_create(image.image, c_snapname) - if ret < 0 { - return nil, RBDError(int(ret)) - } + ret := C.rbd_snap_create(image.image, c_snapname) + if ret < 0 { + return nil, RBDError(int(ret)) + } - return &Snapshot{ - image: image, - name: snapname, - }, nil + return &Snapshot{ + image: image, + name: snapname, + }, nil } // func (image *Image) GetSnapshot(snapname string) *Snapshot { - return &Snapshot{ - image: image, - name: snapname, - } + return &Snapshot{ + image: image, + name: snapname, + } } // int rbd_snap_remove(rbd_image_t image, const char *snapname); func (snapshot *Snapshot) Remove() error { - var c_snapname *C.char = C.CString(snapshot.name) - defer C.free(unsafe.Pointer(c_snapname)) + var c_snapname *C.char = C.CString(snapshot.name) + defer C.free(unsafe.Pointer(c_snapname)) - return GetError(C.rbd_snap_remove(snapshot.image.image, c_snapname)) + return GetError(C.rbd_snap_remove(snapshot.image.image, c_snapname)) } // int rbd_snap_rollback(rbd_image_t image, const char *snapname); // int rbd_snap_rollback_with_progress(rbd_image_t image, const char *snapname, // librbd_progress_fn_t cb, void *cbdata); func (snapshot *Snapshot) Rollback() error { - var c_snapname *C.char = C.CString(snapshot.name) - defer C.free(unsafe.Pointer(c_snapname)) + var c_snapname *C.char = C.CString(snapshot.name) + defer C.free(unsafe.Pointer(c_snapname)) - return GetError(C.rbd_snap_rollback(snapshot.image.image, c_snapname)) + return GetError(C.rbd_snap_rollback(snapshot.image.image, c_snapname)) } // int rbd_snap_protect(rbd_image_t image, const char *snap_name); func (snapshot *Snapshot) Protect() error { - var c_snapname *C.char = C.CString(snapshot.name) - defer C.free(unsafe.Pointer(c_snapname)) + var c_snapname *C.char = C.CString(snapshot.name) + defer C.free(unsafe.Pointer(c_snapname)) - return GetError(C.rbd_snap_protect(snapshot.image.image, c_snapname)) + return GetError(C.rbd_snap_protect(snapshot.image.image, c_snapname)) } // int rbd_snap_unprotect(rbd_image_t image, const char *snap_name); func (snapshot *Snapshot) Unprotect() error { - var c_snapname *C.char = C.CString(snapshot.name) - defer C.free(unsafe.Pointer(c_snapname)) + var c_snapname *C.char = C.CString(snapshot.name) + defer C.free(unsafe.Pointer(c_snapname)) - return GetError(C.rbd_snap_unprotect(snapshot.image.image, c_snapname)) + return GetError(C.rbd_snap_unprotect(snapshot.image.image, c_snapname)) } // int rbd_snap_is_protected(rbd_image_t image, const char *snap_name, // int *is_protected); func (snapshot *Snapshot) IsProtected() (bool, error) { - var c_is_protected C.int - var c_snapname *C.char = C.CString(snapshot.name) - defer C.free(unsafe.Pointer(c_snapname)) + var c_is_protected C.int + var c_snapname *C.char = C.CString(snapshot.name) + defer C.free(unsafe.Pointer(c_snapname)) - ret := C.rbd_snap_is_protected(snapshot.image.image, c_snapname, - &c_is_protected) - if ret < 0 { - return false, RBDError(int(ret)) - } + ret := C.rbd_snap_is_protected(snapshot.image.image, c_snapname, + &c_is_protected) + if ret < 0 { + return false, RBDError(int(ret)) + } - return c_is_protected != 0, nil + return c_is_protected != 0, nil } // int rbd_snap_set(rbd_image_t image, const char *snapname); func (snapshot *Snapshot) Set() error { - var c_snapname *C.char = C.CString(snapshot.name) - defer C.free(unsafe.Pointer(c_snapname)) + var c_snapname *C.char = C.CString(snapshot.name) + defer C.free(unsafe.Pointer(c_snapname)) - return GetError(C.rbd_snap_set(snapshot.image.image, c_snapname)) + return GetError(C.rbd_snap_set(snapshot.image.image, c_snapname)) } diff --git a/rbd/rbd_test.go b/rbd/rbd_test.go index d7756f0..adb3708 100644 --- a/rbd/rbd_test.go +++ b/rbd/rbd_test.go @@ -1,163 +1,163 @@ package rbd_test import ( - "testing" - "github.com/noahdesu/go-ceph/rados" - "github.com/noahdesu/go-ceph/rbd" - "github.com/stretchr/testify/assert" - "os/exec" - "sort" - "encoding/json" + "encoding/json" + "github.com/noahdesu/go-ceph/rados" + "github.com/noahdesu/go-ceph/rbd" + "github.com/stretchr/testify/assert" + "os/exec" + "sort" + "testing" ) func GetUUID() string { - out, _ := exec.Command("uuidgen").Output() - return string(out[:36]) + out, _ := exec.Command("uuidgen").Output() + return string(out[:36]) } func TestVersion(t *testing.T) { - var major, minor, patch = rbd.Version() - assert.False(t, major < 0 || major > 1000, "invalid major") - assert.False(t, minor < 0 || minor > 1000, "invalid minor") - assert.False(t, patch < 0 || patch > 1000, "invalid patch") + var major, minor, patch = rbd.Version() + assert.False(t, major < 0 || major > 1000, "invalid major") + assert.False(t, minor < 0 || minor > 1000, "invalid minor") + assert.False(t, patch < 0 || patch > 1000, "invalid patch") } func TestGetImageNames(t *testing.T) { - conn, _ := rados.NewConn() - conn.ReadDefaultConfigFile() - conn.Connect() + conn, _ := rados.NewConn() + conn.ReadDefaultConfigFile() + conn.Connect() - poolname := GetUUID() - err := conn.MakePool(poolname) - assert.NoError(t, err) + poolname := GetUUID() + err := conn.MakePool(poolname) + assert.NoError(t, err) - ioctx, err := conn.OpenIOContext(poolname) - assert.NoError(t, err) + ioctx, err := conn.OpenIOContext(poolname) + assert.NoError(t, err) - createdList := []string{} - for i := 0; i < 10; i++ { - name := GetUUID() - _, err := rbd.Create(ioctx, name, 1<<22) - assert.NoError(t, err) - createdList = append(createdList, name) - } + createdList := []string{} + for i := 0; i < 10; i++ { + name := GetUUID() + _, err := rbd.Create(ioctx, name, 1<<22) + assert.NoError(t, err) + createdList = append(createdList, name) + } - imageNames, err := rbd.GetImageNames(ioctx) - assert.NoError(t, err) + imageNames, err := rbd.GetImageNames(ioctx) + assert.NoError(t, err) - sort.Strings(createdList) - sort.Strings(imageNames) - assert.Equal(t, createdList, imageNames) + sort.Strings(createdList) + sort.Strings(imageNames) + assert.Equal(t, createdList, imageNames) - for _, name := range(createdList) { - img := rbd.GetImage(ioctx, name) - err := img.Remove() - assert.NoError(t, err) - } + for _, name := range createdList { + img := rbd.GetImage(ioctx, name) + err := img.Remove() + assert.NoError(t, err) + } - ioctx.Destroy() - conn.DeletePool(poolname) - conn.Shutdown() + ioctx.Destroy() + conn.DeletePool(poolname) + conn.Shutdown() } func TestIOReaderWriter(t *testing.T) { - conn, _ := rados.NewConn() - conn.ReadDefaultConfigFile() - conn.Connect() + conn, _ := rados.NewConn() + conn.ReadDefaultConfigFile() + conn.Connect() - poolname := GetUUID() - err := conn.MakePool(poolname) - assert.NoError(t, err) + poolname := GetUUID() + err := conn.MakePool(poolname) + assert.NoError(t, err) - ioctx, err := conn.OpenIOContext(poolname) - assert.NoError(t, err) + ioctx, err := conn.OpenIOContext(poolname) + assert.NoError(t, err) - name := GetUUID() - img, err := rbd.Create(ioctx, name, 1<<22) - assert.NoError(t, err) + name := GetUUID() + img, err := rbd.Create(ioctx, name, 1<<22) + assert.NoError(t, err) - err = img.Open() - assert.NoError(t, err) + err = img.Open() + assert.NoError(t, err) - stats, err := img.Stat() - assert.NoError(t, err) + stats, err := img.Stat() + assert.NoError(t, err) - encoder := json.NewEncoder(img) - encoder.Encode(stats) + encoder := json.NewEncoder(img) + encoder.Encode(stats) - err = img.Flush() - assert.NoError(t, err) + err = img.Flush() + assert.NoError(t, err) - _, err = img.Seek(0, 0) - assert.NoError(t, err) + _, err = img.Seek(0, 0) + assert.NoError(t, err) - var stats2 *rbd.ImageInfo - decoder := json.NewDecoder(img) - decoder.Decode(&stats2) + var stats2 *rbd.ImageInfo + decoder := json.NewDecoder(img) + decoder.Decode(&stats2) - assert.Equal(t, &stats, &stats2) + assert.Equal(t, &stats, &stats2) - _, err = img.Seek(0, 0) - bytes_in := []byte("input data") - _, err = img.Write(bytes_in) - assert.NoError(t, err) + _, err = img.Seek(0, 0) + bytes_in := []byte("input data") + _, err = img.Write(bytes_in) + assert.NoError(t, err) - _, err = img.Seek(0, 0) - assert.NoError(t, err) + _, err = img.Seek(0, 0) + assert.NoError(t, err) - bytes_out := make([]byte, len(bytes_in)) - n_out, err := img.Read(bytes_out) + bytes_out := make([]byte, len(bytes_in)) + n_out, err := img.Read(bytes_out) - assert.Equal(t, n_out, len(bytes_in)) - assert.Equal(t, bytes_in, bytes_out) + assert.Equal(t, n_out, len(bytes_in)) + assert.Equal(t, bytes_in, bytes_out) - err = img.Close() - assert.NoError(t, err) + err = img.Close() + assert.NoError(t, err) - img.Remove() - assert.NoError(t, err) + img.Remove() + assert.NoError(t, err) - ioctx.Destroy() - conn.DeletePool(poolname) - conn.Shutdown() + ioctx.Destroy() + conn.DeletePool(poolname) + conn.Shutdown() } func TestCreateSnapshot(t *testing.T) { - conn, _ := rados.NewConn() - conn.ReadDefaultConfigFile() - conn.Connect() + conn, _ := rados.NewConn() + conn.ReadDefaultConfigFile() + conn.Connect() - poolname := GetUUID() - err := conn.MakePool(poolname) - assert.NoError(t, err) + poolname := GetUUID() + err := conn.MakePool(poolname) + assert.NoError(t, err) - ioctx, err := conn.OpenIOContext(poolname) - assert.NoError(t, err) + ioctx, err := conn.OpenIOContext(poolname) + assert.NoError(t, err) - name := GetUUID() - img, err := rbd.Create(ioctx, name, 1<<22) - assert.NoError(t, err) + name := GetUUID() + img, err := rbd.Create(ioctx, name, 1<<22) + assert.NoError(t, err) - err = img.Open() - assert.NoError(t, err) + err = img.Open() + assert.NoError(t, err) - snapshot, err := img.CreateSnapshot("mysnap") - assert.NoError(t, err) + snapshot, err := img.CreateSnapshot("mysnap") + assert.NoError(t, err) - err = img.Close() - err = img.Open("mysnap") - assert.NoError(t, err) + err = img.Close() + err = img.Open("mysnap") + assert.NoError(t, err) - snapshot.Remove() - assert.NoError(t, err) + snapshot.Remove() + assert.NoError(t, err) - err = img.Close() - assert.NoError(t, err) + err = img.Close() + assert.NoError(t, err) - img.Remove() - assert.NoError(t, err) + img.Remove() + assert.NoError(t, err) - ioctx.Destroy() - conn.DeletePool(poolname) - conn.Shutdown() + ioctx.Destroy() + conn.DeletePool(poolname) + conn.Shutdown() }