CEPH_RBD_API void rbd_mirror_image_instance_id_list_cleanup(char **image_ids,
char **instance_ids,
size_t len);
+CEPH_RBD_API int rbd_mirror_image_info_list(
+ rados_ioctx_t io_ctx, rbd_mirror_image_mode_t *mode_filter,
+ const char *start_id, size_t max, char **image_ids,
+ rbd_mirror_image_mode_t *mode_entries,
+ rbd_mirror_image_info_t *info_entries, size_t *num_entries);
+CEPH_RBD_API void rbd_mirror_image_info_list_cleanup(
+ char **image_ids, rbd_mirror_image_info_t *info_entries,
+ size_t num_entries);
/* pool metadata */
CEPH_RBD_API int rbd_pool_metadata_get(rados_ioctx_t io_ctx, const char *key,
CEPH_RBD_API int rbd_mirror_image_get_info(rbd_image_t image,
rbd_mirror_image_info_t *mirror_image_info,
size_t info_size);
+CEPH_RBD_API void rbd_mirror_image_get_info_cleanup(
+ rbd_mirror_image_info_t *mirror_image_info);
CEPH_RBD_API int rbd_mirror_image_get_mode(rbd_image_t image,
rbd_mirror_image_mode_t *mode);
std::map<mirror_image_status_state_t, int> *states);
int mirror_image_instance_id_list(IoCtx& io_ctx, const std::string &start_id,
size_t max, std::map<std::string, std::string> *sevice_ids);
+ int mirror_image_info_list(IoCtx& io_ctx, mirror_image_mode_t *mode_filter,
+ const std::string &start_id, size_t max,
+ std::map<std::string, std::pair<mirror_image_mode_t,
+ mirror_image_info_t>> *entries);
/// mirror_peer_ commands are deprecated to mirror_peer_site_ equivalents
int mirror_peer_add(IoCtx& io_ctx, std::string *uuid,
return 0;
}
+template <typename I>
+int Mirror<I>::image_info_list(
+ librados::IoCtx& io_ctx, mirror_image_mode_t *mode_filter,
+ const std::string &start_id, size_t max,
+ std::map<std::string, std::pair<mirror_image_mode_t,
+ mirror_image_info_t>> *entries) {
+ CephContext *cct = reinterpret_cast<CephContext *>(io_ctx.cct());
+ ldout(cct, 20) << "pool=" << io_ctx.get_pool_name() << ", mode_filter="
+ << (mode_filter ? stringify(*mode_filter) : "null")
+ << ", start_id=" << start_id << ", max=" << max << dendl;
+
+ std::string last_read = start_id;
+ entries->clear();
+
+ while (entries->size() < max) {
+ map<std::string, cls::rbd::MirrorImage> images;
+ map<std::string, cls::rbd::MirrorImageStatus> statuses;
+
+ int r = librbd::cls_client::mirror_image_status_list(&io_ctx, last_read,
+ max, &images,
+ &statuses);
+ if (r < 0 && r != -ENOENT) {
+ lderr(cct) << "failed to list mirror image statuses: "
+ << cpp_strerror(r) << dendl;
+ return r;
+ }
+
+ if (images.empty()) {
+ break;
+ }
+
+ for (auto &it : images) {
+ auto &image_id = it.first;
+ auto &image = it.second;
+ auto mode = static_cast<mirror_image_mode_t>(image.mode);
+
+ if ((mode_filter && mode != *mode_filter) ||
+ image.state != cls::rbd::MIRROR_IMAGE_STATE_ENABLED) {
+ continue;
+ }
+
+ // need to call get_info for every image to retrieve promotion state
+ // TODO: optimize
+
+ mirror_image_info_t info;
+ I *image_ctx = I::create("", image_id, nullptr, io_ctx, true);
+ r = image_ctx->state->open(0);
+ if (r < 0) {
+ continue;
+ }
+ r = image_get_info(image_ctx, &info);
+ image_ctx->state->close();
+ if (r >= 0) {
+ (*entries)[image_id] = {mode, info};
+ }
+ }
+
+ last_read = images.rbegin()->first;
+ }
+
+ return 0;
+}
+
template <typename I>
int Mirror<I>::image_snapshot_create(I *ictx, uint64_t *snap_id) {
CephContext *cct = ictx->cct;
size_t max,
std::map<std::string, std::string> *ids);
+ static int image_info_list(
+ librados::IoCtx& io_ctx, mirror_image_mode_t *mode_filter,
+ const std::string &start_id, size_t max,
+ std::map<std::string, std::pair<mirror_image_mode_t,
+ mirror_image_info_t>> *entries);
+
static int image_enable(ImageCtxT *ictx, mirror_image_mode_t mode,
bool relax_same_pool_parent_check);
static int image_disable(ImageCtxT *ictx, bool force);
instance_ids);
}
+ int RBD::mirror_image_info_list(
+ IoCtx& io_ctx, mirror_image_mode_t *mode_filter,
+ const std::string &start_id, size_t max,
+ std::map<std::string, std::pair<mirror_image_mode_t,
+ mirror_image_info_t>> *entries) {
+ return librbd::api::Mirror<>::image_info_list(io_ctx, mode_filter, start_id,
+ max, entries);
+ }
+
int RBD::group_create(IoCtx& io_ctx, const char *group_name)
{
TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
extern "C" void rbd_mirror_image_global_status_cleanup(
rbd_mirror_image_global_status_t *global_status) {
free(global_status->name);
- free(global_status->info.global_id);
+ rbd_mirror_image_get_info_cleanup(&global_status->info);
for (auto idx = 0U; idx < global_status->site_statuses_count; ++idx) {
free(global_status->site_statuses[idx].fsid);
free(global_status->site_statuses[idx].description);
for (size_t i = 0; i < len; i++) {
free(image_ids[i]);
free(images[i].name);
- free(images[i].info.global_id);
+ rbd_mirror_image_get_info_cleanup(&images[i].info);
free(images[i].description);
}
}
}
}
+extern "C" int rbd_mirror_image_info_list(
+ rados_ioctx_t p, rbd_mirror_image_mode_t *mode_filter,
+ const char *start_id, size_t max, char **image_ids,
+ rbd_mirror_image_mode_t *mode_entries,
+ rbd_mirror_image_info_t *info_entries, size_t *num_entries) {
+ librados::IoCtx io_ctx;
+ librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
+ std::map<std::string, std::pair<librbd::mirror_image_mode_t,
+ librbd::mirror_image_info_t>> cpp_entries;
+
+ int r = librbd::api::Mirror<>::image_info_list(io_ctx, mode_filter, start_id,
+ max, &cpp_entries);
+ if (r < 0) {
+ return r;
+ }
+
+ ceph_assert(cpp_entries.size() <= max);
+
+ for (auto &it : cpp_entries) {
+ *(image_ids++) = strdup(it.first.c_str());
+ *(mode_entries++) = it.second.first;
+ mirror_image_info_cpp_to_c(it.second.second, info_entries++);
+ }
+ *num_entries = cpp_entries.size();
+
+ return 0;
+}
+
+extern "C" void rbd_mirror_image_info_list_cleanup(
+ char **image_ids, rbd_mirror_image_info_t *info_entries,
+ size_t num_entries) {
+ for (size_t i = 0; i < num_entries; i++) {
+ free(*(image_ids++));
+ rbd_mirror_image_get_info_cleanup(info_entries++);
+ }
+}
+
/* helpers */
extern "C" void rbd_image_spec_cleanup(rbd_image_spec_t *image)
return 0;
}
+extern "C" void rbd_mirror_image_get_info_cleanup(
+ rbd_mirror_image_info_t *mirror_image_info)
+{
+ free(mirror_image_info->global_id);
+}
+
extern "C" int rbd_mirror_image_get_mode(rbd_image_t image,
rbd_mirror_image_mode_t *mode)
{
void rbd_mirror_image_instance_id_list_cleanup(char **image_ids,
char **instance_ids,
size_t len)
+ int rbd_mirror_image_info_list(rados_ioctx_t io_ctx,
+ rbd_mirror_image_mode_t *mode_filter,
+ const char *start_id, size_t max,
+ char **image_ids,
+ rbd_mirror_image_mode_t *mode_entries,
+ rbd_mirror_image_info_t *info_entries,
+ size_t *num_entries)
+ void rbd_mirror_image_info_list_cleanup(char **image_ids,
+ rbd_mirror_image_info_t *info_entries,
+ size_t num_entries)
int rbd_pool_metadata_get(rados_ioctx_t io_ctx, const char *key,
char *value, size_t *val_len)
int rbd_mirror_image_get_info(rbd_image_t image,
rbd_mirror_image_info_t *mirror_image_info,
size_t info_size)
+ void rbd_mirror_image_get_info_cleanup(
+ rbd_mirror_image_info_t *mirror_image_info)
int rbd_mirror_image_get_mode(rbd_image_t image,
rbd_mirror_image_mode_t *mode)
int rbd_mirror_image_get_global_status(
"""
return MirrorImageInstanceIdIterator(ioctx)
+ def mirror_image_info_list(self, ioctx, mode_filter=None):
+ """
+ Iterate over the mirror image instance ids of a pool.
+
+ :param ioctx: determines which RADOS pool is read
+ :param mode_filter: list images in this image mirror mode
+ :type ioctx: :class:`rados.Ioctx`
+ :returns: :class:`MirrorImageInfoIterator`
+ """
+ return MirrorImageInfoIterator(ioctx, mode_filter)
+
def pool_metadata_get(self, ioctx, key):
"""
Get pool metadata for the given key.
free(self.last_read)
self.last_read = strdup("")
+cdef class MirrorImageInfoIterator(object):
+ """
+ Iterator over mirror image info for a pool.
+
+ Yields ``(image_id, info)`` tuple.
+ """
+
+ cdef:
+ rados_ioctx_t ioctx
+ rbd_mirror_image_mode_t mode_filter
+ rbd_mirror_image_mode_t *mode_filter_ptr
+ size_t max_read
+ char *last_read
+ char **image_ids
+ rbd_mirror_image_info_t *info_entries
+ rbd_mirror_image_mode_t *mode_entries
+ size_t size
+
+ def __init__(self, ioctx, mode_filter):
+ self.ioctx = convert_ioctx(ioctx)
+ if mode_filter is not None:
+ self.mode_filter = mode_filter
+ self.mode_filter_ptr = &self.mode_filter
+ else:
+ self.mode_filter_ptr = NULL
+ self.max_read = 1024
+ self.last_read = strdup("")
+ self.image_ids = <char **>realloc_chk(NULL,
+ sizeof(char *) * self.max_read)
+ self.info_entries = <rbd_mirror_image_info_t *>realloc_chk(NULL,
+ sizeof(rbd_mirror_image_info_t) * self.max_read)
+ self.mode_entries = <rbd_mirror_image_mode_t *>realloc_chk(NULL,
+ sizeof(rbd_mirror_image_mode_t) * self.max_read)
+ self.size = 0
+ self.get_next_chunk()
+
+ def __iter__(self):
+ while self.size > 0:
+ for i in range(self.size):
+ yield (decode_cstr(self.image_ids[i]),
+ {
+ 'mode' : int(self.mode_entries[i]),
+ 'global_id' : decode_cstr(self.info_entries[i].global_id),
+ 'state' : int(self.info_entries[i].state),
+ 'primary' : self.info_entries[i].primary,
+ })
+ if self.size < self.max_read:
+ break
+ self.get_next_chunk()
+
+ def __dealloc__(self):
+ rbd_mirror_image_info_list_cleanup(self.image_ids, self.info_entries,
+ self.size)
+ if self.last_read:
+ free(self.last_read)
+ if self.image_ids:
+ free(self.image_ids)
+ if self.info_entries:
+ free(self.info_entries)
+ if self.mode_entries:
+ free(self.mode_entries)
+
+ def get_next_chunk(self):
+ if self.size > 0:
+ rbd_mirror_image_info_list_cleanup(self.image_ids,
+ self.info_entries, self.size)
+ self.size = 0
+ with nogil:
+ ret = rbd_mirror_image_info_list(self.ioctx, self.mode_filter_ptr,
+ self.last_read, self.max_read,
+ self.image_ids, self.mode_entries,
+ self.info_entries, &self.size)
+ if ret < 0:
+ raise make_ex(ret, 'error listing mirror image info')
+ if self.size > 0:
+ last_read = cstr(self.image_ids[self.size - 1], 'last_read')
+ free(self.last_read)
+ self.last_read = strdup(last_read)
+ else:
+ free(self.last_read)
+ self.last_read = strdup("")
+
cdef class PoolMetadataIterator(object):
"""
Iterator over pool metadata list.
'state' : int(c_info.state),
'primary' : c_info.primary,
}
- free(c_info.global_id)
+ rbd_mirror_image_get_info_cleanup(&c_info)
return info
def mirror_image_get_mode(self):
RBD_MIRROR_MODE_DISABLED, RBD_MIRROR_MODE_IMAGE,
RBD_MIRROR_MODE_POOL, RBD_MIRROR_IMAGE_ENABLED,
RBD_MIRROR_IMAGE_DISABLED, MIRROR_IMAGE_STATUS_STATE_UNKNOWN,
- RBD_MIRROR_IMAGE_MODE_SNAPSHOT,
+ RBD_MIRROR_IMAGE_MODE_JOURNAL, RBD_MIRROR_IMAGE_MODE_SNAPSHOT,
RBD_LOCK_MODE_EXCLUSIVE, RBD_OPERATION_FEATURE_GROUP,
RBD_SNAP_NAMESPACE_TYPE_TRASH,
RBD_SNAP_NAMESPACE_TYPE_MIRROR_PRIMARY,
info = self.image.mirror_image_get_info()
self.check_info(info, global_id, RBD_MIRROR_IMAGE_ENABLED, False)
+ entries = dict(self.rbd.mirror_image_info_list(ioctx))
+ info['mode'] = RBD_MIRROR_IMAGE_MODE_JOURNAL;
+ eq(info, entries[self.image.id()])
+
self.image.mirror_image_resync()
self.image.mirror_image_promote(True)
info = self.image.mirror_image_get_info()
self.check_info(info, global_id, RBD_MIRROR_IMAGE_ENABLED, True)
+ entries = dict(self.rbd.mirror_image_info_list(ioctx))
+ info['mode'] = RBD_MIRROR_IMAGE_MODE_JOURNAL;
+ eq(info, entries[self.image.id()])
+
fail = False
try:
self.image.mirror_image_resync()
mode = self.image.mirror_image_get_mode()
eq(RBD_MIRROR_IMAGE_MODE_SNAPSHOT, mode)
+ info = self.image.mirror_image_get_info()
+ eq(True, info['primary'])
+ entries = dict(
+ self.rbd.mirror_image_info_list(ioctx,
+ RBD_MIRROR_IMAGE_MODE_SNAPSHOT))
+ info['mode'] = RBD_MIRROR_IMAGE_MODE_SNAPSHOT;
+ eq(info, entries[self.image.id()])
+
snap_id = self.image.mirror_image_create_snapshot()
snaps = list(self.image.list_snaps())