Rados();
explicit Rados(IoCtx& ioctx);
~Rados();
+ static void from_rados_t(rados_t cluster, Rados &rados);
int init(const char * const id);
int init2(const char * const name, const char * const clustername,
rbd_image_migration_status_t *status);
/* pool mirroring */
+CEPH_RBD_API int rbd_mirror_site_name_get(rados_t cluster,
+ char *name, size_t *max_len);
+CEPH_RBD_API int rbd_mirror_site_name_set(rados_t cluster,
+ const char *name);
+
CEPH_RBD_API int rbd_mirror_mode_get(rados_ioctx_t io_ctx,
rbd_mirror_mode_t *mirror_mode);
CEPH_RBD_API int rbd_mirror_mode_set(rados_ioctx_t io_ctx,
rbd_mirror_mode_t mirror_mode);
+
CEPH_RBD_API int rbd_mirror_peer_add(rados_ioctx_t io_ctx,
char *uuid, size_t uuid_max_length,
const char *cluster_name,
image_migration_status_t *status, size_t status_size);
// RBD pool mirroring support functions
+ int mirror_site_name_get(librados::Rados& rados, std::string* site_name);
+ int mirror_site_name_set(librados::Rados& rados,
+ const std::string& site_name);
+
int mirror_mode_get(IoCtx& io_ctx, rbd_mirror_mode_t *mirror_mode);
int mirror_mode_set(IoCtx& io_ctx, rbd_mirror_mode_t mirror_mode);
+
int mirror_peer_add(IoCtx& io_ctx, std::string *uuid,
const std::string &cluster_name,
const std::string &client_name);
* MON config-key prefix for storing optional remote cluster connectivity
* parameters
*/
-#define RBD_MIRROR_PEER_CONFIG_KEY_PREFIX "rbd/mirror/peer/"
+#define RBD_MIRROR_CONFIG_KEY_PREFIX "rbd/mirror/"
+#define RBD_MIRROR_SITE_NAME_CONFIG_KEY RBD_MIRROR_CONFIG_KEY_PREFIX "site_name"
+#define RBD_MIRROR_PEER_CONFIG_KEY_PREFIX RBD_MIRROR_CONFIG_KEY_PREFIX "peer/"
struct rbd_info {
__le64 max_id;
shutdown();
}
+void librados::Rados::from_rados_t(rados_t cluster, Rados &rados) {
+ if (rados.client) {
+ rados.client->put();
+ }
+ rados.client = static_cast<RadosClient*>(cluster);
+ if (rados.client) {
+ rados.client->get();
+ }
+}
+
int librados::Rados::init(const char * const id)
{
return rados_create((rados_t *)&client, id);
#include "librbd/mirror/PromoteRequest.h"
#include "librbd/mirror/Types.h"
#include "librbd/MirroringWatcher.h"
+#include <boost/algorithm/string/trim.hpp>
#include <boost/scope_exit.hpp>
#define dout_subsys ceph_subsys_rbd
namespace {
+int get_config_key(librados::Rados& rados, const std::string& key,
+ std::string* value) {
+ std::string cmd =
+ "{"
+ "\"prefix\": \"config-key get\", "
+ "\"key\": \"" + key + "\""
+ "}";
+
+ bufferlist in_bl;
+ bufferlist out_bl;
+
+ int r = rados.mon_command(cmd, in_bl, &out_bl, nullptr);
+ if (r == -EINVAL) {
+ return -EOPNOTSUPP;
+ } else if (r < 0 && r != -ENOENT) {
+ return r;
+ }
+
+ *value = out_bl.to_str();
+ return 0;
+}
+
+int set_config_key(librados::Rados& rados, const std::string& key,
+ const std::string& value) {
+ std::string cmd;
+ if (value.empty()) {
+ cmd = "{"
+ "\"prefix\": \"config-key rm\", "
+ "\"key\": \"" + key + "\""
+ "}";
+ } else {
+ cmd = "{"
+ "\"prefix\": \"config-key set\", "
+ "\"key\": \"" + key + "\", "
+ "\"val\": \"" + value + "\""
+ "}";
+ }
+ bufferlist in_bl;
+ bufferlist out_bl;
+
+ int r = rados.mon_command(cmd, in_bl, &out_bl, nullptr);
+ if (r == -EINVAL) {
+ return -EOPNOTSUPP;
+ } else if (r < 0) {
+ return r;
+ }
+
+ return 0;
+}
+
std::string get_peer_config_key_name(int64_t pool_id,
const std::string& peer_uuid) {
return RBD_MIRROR_PEER_CONFIG_KEY_PREFIX + stringify(pool_id) + "/" +
int remove_peer_config_key(librados::IoCtx& io_ctx,
const std::string& peer_uuid) {
int64_t pool_id = io_ctx.get_id();
- std::string cmd =
- "{"
- "\"prefix\": \"config-key rm\", "
- "\"key\": \"" + get_peer_config_key_name(pool_id, peer_uuid) + "\""
- "}";
+ auto key = get_peer_config_key_name(pool_id, peer_uuid);
- bufferlist in_bl;
- bufferlist out_bl;
librados::Rados rados(io_ctx);
- int r = rados.mon_command(cmd, in_bl, &out_bl, nullptr);
+ int r = set_config_key(rados, key, "");
if (r < 0 && r != -ENOENT && r != -EPERM) {
return r;
}
return 0;
}
+template <typename I>
+int Mirror<I>::site_name_get(librados::Rados& rados, std::string* name) {
+ CephContext *cct = reinterpret_cast<CephContext *>(rados.cct());
+ ldout(cct, 20) << dendl;
+
+ int r = get_config_key(rados, RBD_MIRROR_SITE_NAME_CONFIG_KEY, name);
+ if (r == -EOPNOTSUPP) {
+ return r;
+ } else if (r == -ENOENT || name->empty()) {
+ // default to the cluster fsid
+ r = rados.cluster_fsid(name);
+ if (r < 0) {
+ lderr(cct) << "failed to retrieve cluster fsid: " << cpp_strerror(r)
+ << dendl;
+ }
+ return r;
+ } else if (r < 0) {
+ lderr(cct) << "failed to retrieve site name: " << cpp_strerror(r)
+ << dendl;
+ return r;
+ }
+
+ return 0;
+}
+
+template <typename I>
+int Mirror<I>::site_name_set(librados::Rados& rados, const std::string& name) {
+ CephContext *cct = reinterpret_cast<CephContext *>(rados.cct());
+
+ std::string site_name{name};
+ boost::algorithm::trim(site_name);
+ ldout(cct, 20) << "site_name=" << site_name << dendl;
+
+ int r = set_config_key(rados, RBD_MIRROR_SITE_NAME_CONFIG_KEY, name);
+ if (r == -EOPNOTSUPP) {
+ return r;
+ } else if (r < 0 && r != -ENOENT) {
+ lderr(cct) << "failed to update site name: " << cpp_strerror(r)
+ << dendl;
+ return r;
+ }
+
+ return 0;
+}
+
template <typename I>
int Mirror<I>::mode_get(librados::IoCtx& io_ctx,
rbd_mirror_mode_t *mirror_mode) {
ldout(cct, 20) << "uuid=" << uuid << dendl;
attributes->clear();
- std::string cmd =
- "{"
- "\"prefix\": \"config-key get\", "
- "\"key\": \"" + get_peer_config_key_name(io_ctx.get_id(), uuid) + "\""
- "}";
-
- bufferlist in_bl;
- bufferlist out_bl;
librados::Rados rados(io_ctx);
- int r = rados.mon_command(cmd, in_bl, &out_bl, nullptr);
- if (r == -ENOENT || out_bl.length() == 0) {
+ std::string value;
+ int r = get_config_key(rados, get_peer_config_key_name(io_ctx.get_id(), uuid),
+ &value);
+ if (r == -ENOENT || value.empty()) {
return -ENOENT;
} else if (r < 0) {
lderr(cct) << "failed to retrieve peer attributes: " << cpp_strerror(r)
bool json_valid = false;
json_spirit::mValue json_root;
- if(json_spirit::read(out_bl.to_str(), json_root)) {
+ if(json_spirit::read(value, json_root)) {
try {
auto& json_obj = json_root.get_obj();
for (auto& pairs : json_obj) {
}
ss << "}";
- std::string cmd =
- "{"
- "\"prefix\": \"config-key set\", "
- "\"key\": \"" + get_peer_config_key_name(io_ctx.get_id(), uuid) + "\", "
- "\"val\": \"" + ss.str() + "\""
- "}";
- bufferlist in_bl;
- bufferlist out_bl;
-
librados::Rados rados(io_ctx);
- r = rados.mon_command(cmd, in_bl, &out_bl, nullptr);
- if (r < 0) {
+ r = set_config_key(rados, get_peer_config_key_name(io_ctx.get_id(), uuid),
+ ss.str());
+ if (r < 0 && r != -ENOENT) {
lderr(cct) << "failed to update peer attributes: " << cpp_strerror(r)
<< dendl;
return r;
typedef std::map<std::string, mirror_image_status_t> IdToMirrorImageStatus;
typedef std::map<mirror_image_status_state_t, int> MirrorImageStatusStates;
+ static int site_name_get(librados::Rados& rados, std::string* name);
+ static int site_name_set(librados::Rados& rados, const std::string& name);
+
static int mode_get(librados::IoCtx& io_ctx, rbd_mirror_mode_t *mirror_mode);
static int mode_set(librados::IoCtx& io_ctx, rbd_mirror_mode_t mirror_mode);
return librbd::api::Mirror<>::mode_get(io_ctx, mirror_mode);
}
+ int RBD::mirror_site_name_get(librados::Rados& rados,
+ std::string* site_name) {
+ return librbd::api::Mirror<>::site_name_get(rados, site_name);
+ }
+
+ int RBD::mirror_site_name_set(librados::Rados& rados,
+ const std::string& site_name) {
+ return librbd::api::Mirror<>::site_name_set(rados, site_name);
+ }
+
int RBD::mirror_mode_set(IoCtx& io_ctx, rbd_mirror_mode_t mirror_mode) {
return librbd::api::Mirror<>::mode_set(io_ctx, mirror_mode);
}
}
/* pool mirroring */
+extern "C" int rbd_mirror_site_name_get(rados_t cluster, char *name,
+ size_t *max_len) {
+ librados::Rados rados;
+ librados::Rados::from_rados_t(cluster, rados);
+
+ std::string site_name;
+ int r = librbd::api::Mirror<>::site_name_get(rados, &site_name);
+ if (r < 0) {
+ return r;
+ }
+
+ auto total_len = site_name.size() + 1;
+ if (*max_len < total_len) {
+ *max_len = total_len;
+ return -ERANGE;
+ }
+ *max_len = total_len;
+
+ strcpy(name, site_name.c_str());
+ return 0;
+}
+
+extern "C" int rbd_mirror_site_name_set(rados_t cluster, const char *name) {
+ librados::Rados rados;
+ librados::Rados::from_rados_t(cluster, rados);
+ return librbd::api::Mirror<>::site_name_set(rados, name);
+}
+
extern "C" int rbd_mirror_mode_get(rados_ioctx_t p,
rbd_mirror_mode_t *mirror_mode) {
librados::IoCtx io_ctx;
RBD_MAX_BLOCK_NAME_SIZE
RBD_MAX_IMAGE_NAME_SIZE
+ ctypedef void* rados_t
ctypedef void* rados_ioctx_t
ctypedef void* rbd_image_t
ctypedef void* rbd_image_options_t
size_t status_size)
void rbd_migration_status_cleanup(rbd_image_migration_status_t *status)
+ int rbd_mirror_site_name_get(rados_t cluster, char *name, size_t *max_len)
+ int rbd_mirror_site_name_set(rados_t cluster, const char *name)
+
int rbd_mirror_mode_get(rados_ioctx_t io, rbd_mirror_mode_t *mirror_mode)
int rbd_mirror_mode_set(rados_ioctx_t io, rbd_mirror_mode_t mirror_mode)
+
int rbd_mirror_peer_add(rados_ioctx_t io, char *uuid,
size_t uuid_max_length, const char *cluster_name,
const char *client_name)
return OSError(msg, errno=ret)
+cdef rados_t convert_rados(rados.Rados rados) except? NULL:
+ return <rados_t>rados.cluster
+
cdef rados_ioctx_t convert_ioctx(rados.Ioctx ioctx) except? NULL:
return <rados_ioctx_t>ioctx.io
return status
+ def mirror_site_name_get(self, rados):
+ """
+ Get the local cluster's friendly site name
+
+ :param rados: cluster connection
+ :type rados: :class: rados.Rados
+ :returns: str - local site name
+ """
+ cdef:
+ rados_t _rados = convert_rados(rados)
+ char *_site_name = NULL
+ size_t _max_size = 512
+ try:
+ while True:
+ _site_name = <char *>realloc_chk(_site_name, _max_size)
+ with nogil:
+ ret = rbd_mirror_site_name_get(_rados, _site_name,
+ &_max_size)
+ if ret >= 0:
+ break
+ elif ret != -errno.ERANGE:
+ raise make_ex(ret, 'error getting site name')
+ return decode_cstr(_site_name)
+ finally:
+ free(_site_name)
+
+ def mirror_site_name_set(self, rados, site_name):
+ """
+ Set the local cluster's friendly site name
+
+ :param rados: cluster connection
+ :type rados: :class: rados.Rados
+ :param site_name: friendly site name
+ :type str:
+ """
+ site_name = cstr(site_name, 'site_name')
+ cdef:
+ rados_t _rados = convert_rados(rados)
+ char *_site_name = site_name
+ with nogil:
+ ret = rbd_mirror_site_name_set(_rados, _site_name)
+ if ret != 0:
+ raise make_ex(ret, 'error setting mirror site name')
+
def mirror_mode_get(self, ioctx):
"""
Get pool mirror mode.
shutdown();
}
+void Rados::from_rados_t(rados_t p, Rados &rados) {
+ if (rados.client != nullptr) {
+ reinterpret_cast<TestRadosClient*>(rados.client)->put();
+ rados.client = nullptr;
+ }
+
+ auto impl = reinterpret_cast<TestRadosClient*>(p);
+ if (impl) {
+ impl->get();
+ rados.client = reinterpret_cast<RadosClient*>(impl);
+ }
+}
+
AioCompletion *Rados::aio_create_completion(void *cb_arg,
callback_t cb_complete,
callback_t cb_safe) {
ASSERT_EQ(0, status.last_update);
}
}
+
+TEST_F(TestMirroring, SiteName) {
+ REQUIRE(!is_librados_test_stub(_rados));
+
+ const std::string expected_site_name("us-east-1a");
+ ASSERT_EQ(0, m_rbd.mirror_site_name_set(_rados, expected_site_name));
+
+ std::string site_name;
+ ASSERT_EQ(0, m_rbd.mirror_site_name_get(_rados, &site_name));
+ ASSERT_EQ(expected_site_name, site_name);
+
+ ASSERT_EQ(0, m_rbd.mirror_site_name_set(_rados, ""));
+
+ std::string fsid;
+ ASSERT_EQ(0, _rados.cluster_fsid(&fsid));
+ ASSERT_EQ(0, m_rbd.mirror_site_name_get(_rados, &site_name));
+ ASSERT_EQ(fsid, site_name);
+}
remove_image()
self.rbd.mirror_mode_set(ioctx, self.initial_mirror_mode)
+ def test_site_name(self):
+ site_name = "us-west-1"
+ self.rbd.mirror_site_name_set(rados, site_name)
+ eq(site_name, self.rbd.mirror_site_name_get(rados))
+ self.rbd.mirror_site_name_set(rados, "")
+ eq(rados.get_fsid(), self.rbd.mirror_site_name_get(rados))
def test_mirror_peer(self):
eq([], list(self.rbd.mirror_peer_list(ioctx)))