mirror of
https://github.com/ceph/ceph
synced 2025-02-24 19:47:44 +00:00
librbd: added new 'migration_prepare_import' API methods
These related methods accept a JSON-encoded source-spec that describes how to read from the source image. The migration is a one-way operation, so children/groups/etc won't be updated to point to the new destination image. Signed-off-by: Jason Dillaman <dillaman@redhat.com>
This commit is contained in:
parent
e5398d1429
commit
d6133f9bf2
@ -476,6 +476,9 @@ CEPH_RBD_API int rbd_migration_prepare(rados_ioctx_t ioctx,
|
|||||||
rados_ioctx_t dest_ioctx,
|
rados_ioctx_t dest_ioctx,
|
||||||
const char *dest_image_name,
|
const char *dest_image_name,
|
||||||
rbd_image_options_t opts);
|
rbd_image_options_t opts);
|
||||||
|
CEPH_RBD_API int rbd_migration_prepare_import(
|
||||||
|
const char *source_spec, rados_ioctx_t dest_ioctx,
|
||||||
|
const char *dest_image_name, rbd_image_options_t opts);
|
||||||
CEPH_RBD_API int rbd_migration_execute(rados_ioctx_t ioctx,
|
CEPH_RBD_API int rbd_migration_execute(rados_ioctx_t ioctx,
|
||||||
const char *image_name);
|
const char *image_name);
|
||||||
CEPH_RBD_API int rbd_migration_execute_with_progress(rados_ioctx_t ioctx,
|
CEPH_RBD_API int rbd_migration_execute_with_progress(rados_ioctx_t ioctx,
|
||||||
|
@ -294,6 +294,8 @@ public:
|
|||||||
int migration_prepare(IoCtx& io_ctx, const char *image_name,
|
int migration_prepare(IoCtx& io_ctx, const char *image_name,
|
||||||
IoCtx& dest_io_ctx, const char *dest_image_name,
|
IoCtx& dest_io_ctx, const char *dest_image_name,
|
||||||
ImageOptions& opts);
|
ImageOptions& opts);
|
||||||
|
int migration_prepare_import(const char *source_spec, IoCtx& dest_io_ctx,
|
||||||
|
const char *dest_image_name, ImageOptions& opts);
|
||||||
int migration_execute(IoCtx& io_ctx, const char *image_name);
|
int migration_execute(IoCtx& io_ctx, const char *image_name);
|
||||||
int migration_execute_with_progress(IoCtx& io_ctx, const char *image_name,
|
int migration_execute_with_progress(IoCtx& io_ctx, const char *image_name,
|
||||||
ProgressContext &prog_ctx);
|
ProgressContext &prog_ctx);
|
||||||
|
@ -34,7 +34,9 @@
|
|||||||
#include "librbd/image/RemoveRequest.h"
|
#include "librbd/image/RemoveRequest.h"
|
||||||
#include "librbd/image/Types.h"
|
#include "librbd/image/Types.h"
|
||||||
#include "librbd/internal.h"
|
#include "librbd/internal.h"
|
||||||
|
#include "librbd/migration/FormatInterface.h"
|
||||||
#include "librbd/migration/NativeFormat.h"
|
#include "librbd/migration/NativeFormat.h"
|
||||||
|
#include "librbd/migration/SourceSpecBuilder.h"
|
||||||
#include "librbd/mirror/DisableRequest.h"
|
#include "librbd/mirror/DisableRequest.h"
|
||||||
#include "librbd/mirror/EnableRequest.h"
|
#include "librbd/mirror/EnableRequest.h"
|
||||||
|
|
||||||
@ -464,8 +466,7 @@ int Migration<I>::prepare(librados::IoCtx& io_ctx,
|
|||||||
lderr(cct) << "librbd does not support requested features" << dendl;
|
lderr(cct) << "librbd does not support requested features" << dendl;
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
features &= ~RBD_FEATURES_INTERNAL;
|
features &= ~RBD_FEATURES_IMPLICIT_ENABLE;
|
||||||
features &= ~RBD_FEATURE_DIRTY_CACHE;
|
|
||||||
features |= RBD_FEATURE_MIGRATING;
|
features |= RBD_FEATURE_MIGRATING;
|
||||||
opts.set(RBD_IMAGE_OPTION_FEATURES, features);
|
opts.set(RBD_IMAGE_OPTION_FEATURES, features);
|
||||||
|
|
||||||
@ -497,11 +498,15 @@ int Migration<I>::prepare(librados::IoCtx& io_ctx,
|
|||||||
auto dst_image_ctx = I::create(
|
auto dst_image_ctx = I::create(
|
||||||
dest_image_name, util::generate_image_id(dest_io_ctx), nullptr,
|
dest_image_name, util::generate_image_id(dest_io_ctx), nullptr,
|
||||||
dest_io_ctx, false);
|
dest_io_ctx, false);
|
||||||
|
src_image_ctx->image_lock.lock_shared();
|
||||||
cls::rbd::MigrationSpec dst_migration_spec{
|
cls::rbd::MigrationSpec dst_migration_spec{
|
||||||
cls::rbd::MIGRATION_HEADER_TYPE_DST, dest_io_ctx.get_id(),
|
cls::rbd::MIGRATION_HEADER_TYPE_DST,
|
||||||
dest_io_ctx.get_namespace(), "", "", "", {}, 0,
|
src_image_ctx->md_ctx.get_id(), src_image_ctx->md_ctx.get_namespace(),
|
||||||
false, cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, flatten > 0,
|
src_image_ctx->name, src_image_ctx->id, "", {}, 0, false,
|
||||||
|
cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, flatten > 0,
|
||||||
cls::rbd::MIGRATION_STATE_PREPARING, ""};
|
cls::rbd::MIGRATION_STATE_PREPARING, ""};
|
||||||
|
src_image_ctx->image_lock.unlock_shared();
|
||||||
|
|
||||||
Migration migration(src_image_ctx, dst_image_ctx, dst_migration_spec,
|
Migration migration(src_image_ctx, dst_image_ctx, dst_migration_spec,
|
||||||
opts, nullptr);
|
opts, nullptr);
|
||||||
r = migration.prepare();
|
r = migration.prepare();
|
||||||
@ -512,6 +517,88 @@ int Migration<I>::prepare(librados::IoCtx& io_ctx,
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename I>
|
||||||
|
int Migration<I>::prepare_import(
|
||||||
|
const std::string& source_spec, librados::IoCtx& dest_io_ctx,
|
||||||
|
const std::string &dest_image_name, ImageOptions& opts) {
|
||||||
|
if (source_spec.empty() || !dest_io_ctx.is_valid() ||
|
||||||
|
dest_image_name.empty()) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cct = reinterpret_cast<CephContext *>(dest_io_ctx.cct());
|
||||||
|
ldout(cct, 10) << source_spec << " -> "
|
||||||
|
<< dest_io_ctx.get_pool_name() << "/"
|
||||||
|
<< dest_image_name << ", opts=" << opts << dendl;
|
||||||
|
|
||||||
|
auto src_image_ctx = I::create("", "", nullptr, dest_io_ctx, true);
|
||||||
|
BOOST_SCOPE_EXIT_TPL(src_image_ctx) {
|
||||||
|
src_image_ctx->state->close();
|
||||||
|
} BOOST_SCOPE_EXIT_END;
|
||||||
|
|
||||||
|
migration::SourceSpecBuilder<I> source_spec_builder(src_image_ctx);
|
||||||
|
|
||||||
|
json_spirit::mObject source_spec_object;
|
||||||
|
int r = source_spec_builder.parse_source_spec(source_spec,
|
||||||
|
&source_spec_object);
|
||||||
|
if (r < 0) {
|
||||||
|
lderr(cct) << "failed to parse source spec: " << cpp_strerror(r)
|
||||||
|
<< dendl;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<migration::FormatInterface> format;
|
||||||
|
r = source_spec_builder.build_format(source_spec_object, &format);
|
||||||
|
if (r < 0) {
|
||||||
|
lderr(cct) << "failed to build migration format handler: "
|
||||||
|
<< cpp_strerror(r) << dendl;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
C_SaferCond open_ctx;
|
||||||
|
format->open(&open_ctx);
|
||||||
|
r = open_ctx.wait();
|
||||||
|
if (r < 0) {
|
||||||
|
lderr(cct) << "failed to open migration source: " << cpp_strerror(r)
|
||||||
|
<< dendl;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t image_format = 2;
|
||||||
|
if (opts.get(RBD_IMAGE_OPTION_FORMAT, &image_format) != 0) {
|
||||||
|
opts.set(RBD_IMAGE_OPTION_FORMAT, image_format);
|
||||||
|
}
|
||||||
|
if (image_format != 2) {
|
||||||
|
lderr(cct) << "unsupported destination image format: " << image_format
|
||||||
|
<< dendl;
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t features_set = 0;
|
||||||
|
opts.get(RBD_IMAGE_OPTION_FEATURES_SET, &features_set);
|
||||||
|
opts.set(RBD_IMAGE_OPTION_FEATURES_SET, features_set | RBD_FEATURE_MIGRATING);
|
||||||
|
|
||||||
|
ldout(cct, 20) << "updated opts=" << opts << dendl;
|
||||||
|
|
||||||
|
auto dst_image_ctx = I::create(
|
||||||
|
dest_image_name, util::generate_image_id(dest_io_ctx), nullptr,
|
||||||
|
dest_io_ctx, false);
|
||||||
|
cls::rbd::MigrationSpec dst_migration_spec{
|
||||||
|
cls::rbd::MIGRATION_HEADER_TYPE_DST, -1, "", "", "",
|
||||||
|
json_spirit::write(source_spec_object), {},
|
||||||
|
0, false, cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, true,
|
||||||
|
cls::rbd::MIGRATION_STATE_PREPARING, ""};
|
||||||
|
|
||||||
|
Migration migration(src_image_ctx, dst_image_ctx, dst_migration_spec,
|
||||||
|
opts, nullptr);
|
||||||
|
return migration.prepare_import();
|
||||||
|
if (r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename I>
|
template <typename I>
|
||||||
int Migration<I>::execute(librados::IoCtx& io_ctx,
|
int Migration<I>::execute(librados::IoCtx& io_ctx,
|
||||||
const std::string &image_name,
|
const std::string &image_name,
|
||||||
@ -552,10 +639,15 @@ int Migration<I>::execute(librados::IoCtx& io_ctx,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ldout(cct, 5) << "migrating " << src_image_ctx->md_ctx.get_pool_name() << "/"
|
ldout(cct, 5) << "migrating ";
|
||||||
<< src_image_ctx->name << " -> "
|
if (!dst_migration_spec.source_spec.empty()) {
|
||||||
<< dst_image_ctx->md_ctx.get_pool_name()
|
*_dout << dst_migration_spec.source_spec;
|
||||||
<< "/" << dst_image_ctx->name << dendl;
|
} else {
|
||||||
|
*_dout << src_image_ctx->md_ctx.get_pool_name() << "/"
|
||||||
|
<< src_image_ctx->name;
|
||||||
|
}
|
||||||
|
*_dout << " -> " << dst_image_ctx->md_ctx.get_pool_name() << "/"
|
||||||
|
<< dst_image_ctx->name << dendl;
|
||||||
|
|
||||||
ImageOptions opts;
|
ImageOptions opts;
|
||||||
Migration migration(src_image_ctx, dst_image_ctx, dst_migration_spec,
|
Migration migration(src_image_ctx, dst_image_ctx, dst_migration_spec,
|
||||||
@ -585,18 +677,24 @@ int Migration<I>::abort(librados::IoCtx& io_ctx, const std::string &image_name,
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
ldout(cct, 5) << "canceling incomplete migration "
|
ldout(cct, 5) << "canceling incomplete migration ";
|
||||||
<< src_image_ctx->md_ctx.get_pool_name() << "/"
|
if (!dst_migration_spec.source_spec.empty()) {
|
||||||
<< src_image_ctx->name
|
*_dout << dst_migration_spec.source_spec;
|
||||||
<< " -> " << dst_image_ctx->md_ctx.get_pool_name() << "/"
|
} else {
|
||||||
<< dst_image_ctx->name << dendl;
|
*_dout << src_image_ctx->md_ctx.get_pool_name() << "/"
|
||||||
|
<< src_image_ctx->name;
|
||||||
|
}
|
||||||
|
*_dout << " -> " << dst_image_ctx->md_ctx.get_pool_name() << "/"
|
||||||
|
<< dst_image_ctx->name << dendl;
|
||||||
|
|
||||||
ImageOptions opts;
|
ImageOptions opts;
|
||||||
Migration migration(src_image_ctx, dst_image_ctx, dst_migration_spec,
|
Migration migration(src_image_ctx, dst_image_ctx, dst_migration_spec,
|
||||||
opts, &prog_ctx);
|
opts, &prog_ctx);
|
||||||
r = migration.abort();
|
r = migration.abort();
|
||||||
|
|
||||||
src_image_ctx->state->close();
|
if (src_image_ctx != nullptr) {
|
||||||
|
src_image_ctx->state->close();
|
||||||
|
}
|
||||||
|
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
return r;
|
return r;
|
||||||
@ -642,10 +740,15 @@ int Migration<I>::commit(librados::IoCtx& io_ctx,
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
ldout(cct, 5) << "migrating " << src_image_ctx->md_ctx.get_pool_name() << "/"
|
ldout(cct, 5) << "migrating ";
|
||||||
<< src_image_ctx->name << " -> "
|
if (!dst_migration_spec.source_spec.empty()) {
|
||||||
<< dst_image_ctx->md_ctx.get_pool_name()
|
*_dout << dst_migration_spec.source_spec;
|
||||||
<< "/" << dst_image_ctx->name << dendl;
|
} else {
|
||||||
|
*_dout << src_image_ctx->md_ctx.get_pool_name() << "/"
|
||||||
|
<< src_image_ctx->name;
|
||||||
|
}
|
||||||
|
*_dout << " -> " << dst_image_ctx->md_ctx.get_pool_name() << "/"
|
||||||
|
<< dst_image_ctx->name << dendl;
|
||||||
|
|
||||||
ImageOptions opts;
|
ImageOptions opts;
|
||||||
Migration migration(src_image_ctx, dst_image_ctx, dst_migration_spec,
|
Migration migration(src_image_ctx, dst_image_ctx, dst_migration_spec,
|
||||||
@ -678,10 +781,15 @@ int Migration<I>::status(librados::IoCtx& io_ctx,
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
ldout(cct, 5) << "migrating " << src_image_ctx->md_ctx.get_pool_name() << "/"
|
ldout(cct, 5) << "migrating ";
|
||||||
<< src_image_ctx->name << " -> "
|
if (!dst_migration_spec.source_spec.empty()) {
|
||||||
<< dst_image_ctx->md_ctx.get_pool_name()
|
*_dout << dst_migration_spec.source_spec;
|
||||||
<< "/" << dst_image_ctx->name << dendl;
|
} else {
|
||||||
|
*_dout << src_image_ctx->md_ctx.get_pool_name() << "/"
|
||||||
|
<< src_image_ctx->name;
|
||||||
|
}
|
||||||
|
*_dout << " -> " << dst_image_ctx->md_ctx.get_pool_name() << "/"
|
||||||
|
<< dst_image_ctx->name << dendl;
|
||||||
|
|
||||||
ImageOptions opts;
|
ImageOptions opts;
|
||||||
Migration migration(src_image_ctx, dst_image_ctx, dst_migration_spec,
|
Migration migration(src_image_ctx, dst_image_ctx, dst_migration_spec,
|
||||||
@ -791,6 +899,25 @@ int Migration<I>::prepare() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename I>
|
||||||
|
int Migration<I>::prepare_import() {
|
||||||
|
ldout(m_cct, 10) << dendl;
|
||||||
|
|
||||||
|
BOOST_SCOPE_EXIT_TPL(&m_dst_image_ctx) {
|
||||||
|
if (m_dst_image_ctx != nullptr) {
|
||||||
|
m_dst_image_ctx->state->close();
|
||||||
|
}
|
||||||
|
} BOOST_SCOPE_EXIT_END;
|
||||||
|
|
||||||
|
int r = create_dst_image(&m_dst_image_ctx);
|
||||||
|
if (r < 0) {
|
||||||
|
abort();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename I>
|
template <typename I>
|
||||||
int Migration<I>::execute() {
|
int Migration<I>::execute() {
|
||||||
ldout(m_cct, 10) << dendl;
|
ldout(m_cct, 10) << dendl;
|
||||||
@ -847,21 +974,22 @@ int Migration<I>::abort() {
|
|||||||
ldout(m_cct, 10) << dendl;
|
ldout(m_cct, 10) << dendl;
|
||||||
|
|
||||||
int r;
|
int r;
|
||||||
|
if (m_src_image_ctx != nullptr) {
|
||||||
m_src_image_ctx->owner_lock.lock_shared();
|
m_src_image_ctx->owner_lock.lock_shared();
|
||||||
if (m_src_image_ctx->exclusive_lock != nullptr &&
|
if (m_src_image_ctx->exclusive_lock != nullptr &&
|
||||||
!m_src_image_ctx->exclusive_lock->is_lock_owner()) {
|
!m_src_image_ctx->exclusive_lock->is_lock_owner()) {
|
||||||
C_SaferCond ctx;
|
C_SaferCond ctx;
|
||||||
m_src_image_ctx->exclusive_lock->acquire_lock(&ctx);
|
m_src_image_ctx->exclusive_lock->acquire_lock(&ctx);
|
||||||
m_src_image_ctx->owner_lock.unlock_shared();
|
m_src_image_ctx->owner_lock.unlock_shared();
|
||||||
r = ctx.wait();
|
r = ctx.wait();
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
lderr(m_cct) << "error acquiring exclusive lock: " << cpp_strerror(r)
|
lderr(m_cct) << "error acquiring exclusive lock: " << cpp_strerror(r)
|
||||||
<< dendl;
|
<< dendl;
|
||||||
return r;
|
return r;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m_src_image_ctx->owner_lock.unlock_shared();
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
m_src_image_ctx->owner_lock.unlock_shared();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
group_info_t group_info;
|
group_info_t group_info;
|
||||||
@ -902,19 +1030,21 @@ int Migration<I>::abort() {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy dst HEAD -> src HEAD
|
SteppedProgressContext progress_ctx(
|
||||||
SteppedProgressContext progress_ctx(m_prog_ctx, 2);
|
m_prog_ctx, (m_src_image_ctx != nullptr ? 2 : 1));
|
||||||
revert_data(m_dst_image_ctx, m_src_image_ctx, &progress_ctx);
|
if (m_src_image_ctx != nullptr) {
|
||||||
progress_ctx.next_step();
|
// copy dst HEAD -> src HEAD
|
||||||
|
revert_data(m_dst_image_ctx, m_src_image_ctx, &progress_ctx);
|
||||||
|
progress_ctx.next_step();
|
||||||
|
|
||||||
ldout(m_cct, 10) << "relinking children" << dendl;
|
ldout(m_cct, 10) << "relinking children" << dendl;
|
||||||
r = relink_children(m_dst_image_ctx, m_src_image_ctx);
|
r = relink_children(m_dst_image_ctx, m_src_image_ctx);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
return r;
|
return r;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ldout(m_cct, 10) << "removing dst image snapshots" << dendl;
|
ldout(m_cct, 10) << "removing dst image snapshots" << dendl;
|
||||||
|
|
||||||
std::vector<librbd::snap_info_t> snaps;
|
std::vector<librbd::snap_info_t> snaps;
|
||||||
r = Snapshot<I>::list(m_dst_image_ctx, snaps);
|
r = Snapshot<I>::list(m_dst_image_ctx, snaps);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
@ -966,24 +1096,26 @@ int Migration<I>::abort() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r = relink_src_image(m_src_image_ctx);
|
if (m_src_image_ctx != nullptr) {
|
||||||
if (r < 0) {
|
r = relink_src_image(m_src_image_ctx);
|
||||||
return r;
|
if (r < 0) {
|
||||||
}
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
r = add_group(m_src_image_ctx, group_info);
|
r = add_group(m_src_image_ctx, group_info);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = remove_migration(m_src_image_ctx);
|
r = remove_migration(m_src_image_ctx);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = enable_mirroring(m_src_image_ctx, m_mirroring, m_mirror_image_mode);
|
r = enable_mirroring(m_src_image_ctx, m_mirroring, m_mirror_image_mode);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
return r;
|
return r;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ldout(m_cct, 10) << "succeeded" << dendl;
|
ldout(m_cct, 10) << "succeeded" << dendl;
|
||||||
@ -1007,9 +1139,11 @@ int Migration<I>::commit() {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = remove_src_image(&m_src_image_ctx);
|
if (m_src_image_ctx != nullptr) {
|
||||||
if (r < 0) {
|
r = remove_src_image(&m_src_image_ctx);
|
||||||
return r;
|
if (r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r = enable_mirroring(m_dst_image_ctx, m_mirroring, m_mirror_image_mode);
|
r = enable_mirroring(m_dst_image_ctx, m_mirroring, m_mirror_image_mode);
|
||||||
@ -1061,26 +1195,34 @@ int Migration<I>::status(image_migration_status_t *status) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename I>
|
||||||
|
int Migration<I>::set_state(I* image_ctx, const std::string& image_description,
|
||||||
|
cls::rbd::MigrationState state,
|
||||||
|
const std::string &description) {
|
||||||
|
int r = cls_client::migration_set_state(&image_ctx->md_ctx,
|
||||||
|
image_ctx->header_oid,
|
||||||
|
state, description);
|
||||||
|
if (r < 0) {
|
||||||
|
lderr(m_cct) << "failed to set " << image_description << " "
|
||||||
|
<< "migration header: " << cpp_strerror(r) << dendl;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename I>
|
template <typename I>
|
||||||
int Migration<I>::set_state(cls::rbd::MigrationState state,
|
int Migration<I>::set_state(cls::rbd::MigrationState state,
|
||||||
const std::string &description) {
|
const std::string &description) {
|
||||||
int r;
|
int r;
|
||||||
if (m_src_image_ctx != nullptr) {
|
if (m_src_image_ctx != nullptr) {
|
||||||
r = cls_client::migration_set_state(&m_src_image_ctx->md_ctx,
|
r = set_state(m_src_image_ctx, "source", state, description);
|
||||||
m_src_image_ctx->header_oid,
|
|
||||||
state, description);
|
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
lderr(m_cct) << "failed to set source migration header: "
|
|
||||||
<< cpp_strerror(r) << dendl;
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r = cls_client::migration_set_state(&m_dst_io_ctx, m_dst_header_oid, state,
|
r = set_state(m_dst_image_ctx, "destination", state, description);
|
||||||
description);
|
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
lderr(m_cct) << "failed to set destination migration header: "
|
|
||||||
<< cpp_strerror(r) << dendl;
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1348,7 +1490,7 @@ int Migration<I>::create_dst_image(I** image_ctx) {
|
|||||||
m_src_image_ctx->op_work_queue, &on_create);
|
m_src_image_ctx->op_work_queue, &on_create);
|
||||||
req->send();
|
req->send();
|
||||||
} else {
|
} else {
|
||||||
r = util::create_ioctx(m_src_image_ctx->md_ctx, "destination image",
|
r = util::create_ioctx(m_src_image_ctx->md_ctx, "parent image",
|
||||||
parent_spec.pool_id, parent_spec.pool_namespace,
|
parent_spec.pool_id, parent_spec.pool_namespace,
|
||||||
&parent_io_ctx);
|
&parent_io_ctx);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
@ -1410,25 +1552,23 @@ int Migration<I>::create_dst_image(I** image_ctx) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
C_SaferCond on_metadata_copy;
|
if (!m_src_image_ctx->header_oid.empty()) {
|
||||||
auto metadata_copy_req = librbd::deep_copy::MetadataCopyRequest<I>::create(
|
C_SaferCond on_metadata_copy;
|
||||||
m_src_image_ctx, dst_image_ctx, &on_metadata_copy);
|
auto metadata_copy_req = librbd::deep_copy::MetadataCopyRequest<I>::create(
|
||||||
metadata_copy_req->send();
|
m_src_image_ctx, dst_image_ctx, &on_metadata_copy);
|
||||||
r = on_metadata_copy.wait();
|
metadata_copy_req->send();
|
||||||
if (r < 0) {
|
r = on_metadata_copy.wait();
|
||||||
lderr(m_cct) << "failed to copy metadata: " << cpp_strerror(r) << dendl;
|
if (r < 0) {
|
||||||
return r;
|
lderr(m_cct) << "failed to copy metadata: " << cpp_strerror(r) << dendl;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_src_image_ctx->image_lock.lock_shared();
|
m_dst_migration_spec.snap_seqs = snap_seqs;
|
||||||
m_dst_migration_spec = {cls::rbd::MIGRATION_HEADER_TYPE_DST,
|
m_dst_migration_spec.overlap = size;
|
||||||
m_src_image_ctx->md_ctx.get_id(),
|
m_dst_migration_spec.mirroring = m_mirroring;
|
||||||
m_src_image_ctx->md_ctx.get_namespace(),
|
m_dst_migration_spec.mirror_image_mode = m_mirror_image_mode;
|
||||||
m_src_image_ctx->name, m_src_image_ctx->id,
|
m_dst_migration_spec.flatten = m_flatten;
|
||||||
"", snap_seqs, size, m_mirroring, m_mirror_image_mode,
|
|
||||||
m_flatten, cls::rbd::MIGRATION_STATE_PREPARING, ""};
|
|
||||||
m_src_image_ctx->image_lock.unlock_shared();
|
|
||||||
|
|
||||||
r = cls_client::migration_set(&m_dst_io_ctx, m_dst_header_oid,
|
r = cls_client::migration_set(&m_dst_io_ctx, m_dst_header_oid,
|
||||||
m_dst_migration_spec);
|
m_dst_migration_spec);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
@ -1437,26 +1577,37 @@ int Migration<I>::create_dst_image(I** image_ctx) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = update_group(m_src_image_ctx, dst_image_ctx);
|
if (m_dst_migration_spec.source_spec.empty()) {
|
||||||
|
r = update_group(m_src_image_ctx, dst_image_ctx);
|
||||||
|
if (r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = set_state(m_src_image_ctx, "source",
|
||||||
|
cls::rbd::MIGRATION_STATE_PREPARED, "");
|
||||||
|
if (r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r = set_state(dst_image_ctx, "destination",
|
||||||
|
cls::rbd::MIGRATION_STATE_PREPARED, "");
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = set_state(cls::rbd::MIGRATION_STATE_PREPARED, "");
|
if (m_dst_migration_spec.source_spec.empty()) {
|
||||||
if (r < 0) {
|
r = dst_image_ctx->state->refresh();
|
||||||
return r;
|
if (r < 0) {
|
||||||
}
|
lderr(m_cct) << "failed to refresh destination image: " << cpp_strerror(r)
|
||||||
|
<< dendl;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
r = dst_image_ctx->state->refresh();
|
r = relink_children(m_src_image_ctx, dst_image_ctx);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
lderr(m_cct) << "failed to refresh destination image: " << cpp_strerror(r)
|
return r;
|
||||||
<< dendl;
|
}
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = relink_children(m_src_image_ctx, dst_image_ctx);
|
|
||||||
if (r < 0) {
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -23,6 +23,10 @@ public:
|
|||||||
static int prepare(librados::IoCtx& io_ctx, const std::string &image_name,
|
static int prepare(librados::IoCtx& io_ctx, const std::string &image_name,
|
||||||
librados::IoCtx& dest_io_ctx,
|
librados::IoCtx& dest_io_ctx,
|
||||||
const std::string &dest_image_name, ImageOptions& opts);
|
const std::string &dest_image_name, ImageOptions& opts);
|
||||||
|
static int prepare_import(const std::string& source_spec,
|
||||||
|
librados::IoCtx& dest_io_ctx,
|
||||||
|
const std::string &dest_image_name,
|
||||||
|
ImageOptions& opts);
|
||||||
static int execute(librados::IoCtx& io_ctx, const std::string &image_name,
|
static int execute(librados::IoCtx& io_ctx, const std::string &image_name,
|
||||||
ProgressContext &prog_ctx);
|
ProgressContext &prog_ctx);
|
||||||
static int abort(librados::IoCtx& io_ctx, const std::string &image_name,
|
static int abort(librados::IoCtx& io_ctx, const std::string &image_name,
|
||||||
@ -56,11 +60,15 @@ private:
|
|||||||
ImageOptions& opts, ProgressContext *prog_ctx);
|
ImageOptions& opts, ProgressContext *prog_ctx);
|
||||||
|
|
||||||
int prepare();
|
int prepare();
|
||||||
|
int prepare_import();
|
||||||
int execute();
|
int execute();
|
||||||
int abort();
|
int abort();
|
||||||
int commit();
|
int commit();
|
||||||
int status(image_migration_status_t *status);
|
int status(image_migration_status_t *status);
|
||||||
|
|
||||||
|
int set_state(ImageCtxT* image_ctx, const std::string& image_description,
|
||||||
|
cls::rbd::MigrationState state,
|
||||||
|
const std::string &description);
|
||||||
int set_state(cls::rbd::MigrationState state, const std::string &description);
|
int set_state(cls::rbd::MigrationState state, const std::string &description);
|
||||||
|
|
||||||
int list_src_snaps(ImageCtxT* image_ctx,
|
int list_src_snaps(ImageCtxT* image_ctx,
|
||||||
|
@ -923,6 +923,13 @@ namespace librbd {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int RBD::migration_prepare_import(const char *source_spec, IoCtx& dest_io_ctx,
|
||||||
|
const char *dest_image_name,
|
||||||
|
ImageOptions& opts) {
|
||||||
|
return librbd::api::Migration<>::prepare_import(source_spec, dest_io_ctx,
|
||||||
|
dest_image_name, opts);
|
||||||
|
}
|
||||||
|
|
||||||
int RBD::migration_execute(IoCtx& io_ctx, const char *image_name)
|
int RBD::migration_execute(IoCtx& io_ctx, const char *image_name)
|
||||||
{
|
{
|
||||||
TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
|
TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
|
||||||
@ -4370,6 +4377,16 @@ extern "C" int rbd_migration_prepare(rados_ioctx_t p, const char *image_name,
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" int rbd_migration_prepare_import(
|
||||||
|
const char *source_spec, rados_ioctx_t dest_p,
|
||||||
|
const char *dest_image_name, rbd_image_options_t opts_) {
|
||||||
|
librados::IoCtx dest_io_ctx;
|
||||||
|
librados::IoCtx::from_rados_ioctx_t(dest_p, dest_io_ctx);
|
||||||
|
librbd::ImageOptions opts(opts_);
|
||||||
|
return librbd::api::Migration<>::prepare_import(source_spec, dest_io_ctx,
|
||||||
|
dest_image_name, opts);
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" int rbd_migration_execute(rados_ioctx_t p, const char *image_name)
|
extern "C" int rbd_migration_execute(rados_ioctx_t p, const char *image_name)
|
||||||
{
|
{
|
||||||
librados::IoCtx io_ctx;
|
librados::IoCtx io_ctx;
|
||||||
|
@ -370,6 +370,10 @@ cdef extern from "rbd/librbd.h" nogil:
|
|||||||
rados_ioctx_t dest_io_ctx,
|
rados_ioctx_t dest_io_ctx,
|
||||||
const char *dest_image_name,
|
const char *dest_image_name,
|
||||||
rbd_image_options_t opts)
|
rbd_image_options_t opts)
|
||||||
|
int rbd_migration_prepare_import(const char *source_spec,
|
||||||
|
rados_ioctx_t dest_io_ctx,
|
||||||
|
const char *dest_image_name,
|
||||||
|
rbd_image_options_t opts)
|
||||||
int rbd_migration_execute_with_progress(rados_ioctx_t io_ctx,
|
int rbd_migration_execute_with_progress(rados_ioctx_t io_ctx,
|
||||||
const char *image_name,
|
const char *image_name,
|
||||||
librbd_progress_fn_t cb,
|
librbd_progress_fn_t cb,
|
||||||
@ -1688,6 +1692,67 @@ class RBD(object):
|
|||||||
if ret < 0:
|
if ret < 0:
|
||||||
raise make_ex(ret, 'error migrating image %s' % (image_name))
|
raise make_ex(ret, 'error migrating image %s' % (image_name))
|
||||||
|
|
||||||
|
def migration_prepare_import(self, source_spec, dest_ioctx, dest_image_name,
|
||||||
|
features=None, order=None, stripe_unit=None,
|
||||||
|
stripe_count=None, data_pool=None):
|
||||||
|
"""
|
||||||
|
Prepare an RBD image migration.
|
||||||
|
|
||||||
|
:param source_spec: JSON-encoded source-spec
|
||||||
|
:type source_spec: str
|
||||||
|
:param dest_ioctx: determines which pool to migration into
|
||||||
|
:type dest_ioctx: :class:`rados.Ioctx`
|
||||||
|
:param dest_image_name: the name of the destination image (may be the same image)
|
||||||
|
:type dest_image_name: str
|
||||||
|
:param features: bitmask of features to enable; if set, must include layering
|
||||||
|
:type features: int
|
||||||
|
:param order: the image is split into (2**order) byte objects
|
||||||
|
:type order: int
|
||||||
|
:param stripe_unit: stripe unit in bytes (default None to let librbd decide)
|
||||||
|
:type stripe_unit: int
|
||||||
|
:param stripe_count: objects to stripe over before looping
|
||||||
|
:type stripe_count: int
|
||||||
|
:param data_pool: optional separate pool for data blocks
|
||||||
|
:type data_pool: str
|
||||||
|
:raises: :class:`TypeError`
|
||||||
|
:raises: :class:`InvalidArgument`
|
||||||
|
:raises: :class:`ImageExists`
|
||||||
|
:raises: :class:`FunctionNotSupported`
|
||||||
|
:raises: :class:`ArgumentOutOfRange`
|
||||||
|
"""
|
||||||
|
source_spec = cstr(source_spec, 'source_spec')
|
||||||
|
dest_image_name = cstr(dest_image_name, 'dest_image_name')
|
||||||
|
cdef:
|
||||||
|
char *_source_spec = source_spec
|
||||||
|
rados_ioctx_t _dest_ioctx = convert_ioctx(dest_ioctx)
|
||||||
|
char *_dest_image_name = dest_image_name
|
||||||
|
rbd_image_options_t opts
|
||||||
|
|
||||||
|
rbd_image_options_create(&opts)
|
||||||
|
try:
|
||||||
|
if features is not None:
|
||||||
|
rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_FEATURES,
|
||||||
|
features)
|
||||||
|
if order is not None:
|
||||||
|
rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_ORDER,
|
||||||
|
order)
|
||||||
|
if stripe_unit is not None:
|
||||||
|
rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_UNIT,
|
||||||
|
stripe_unit)
|
||||||
|
if stripe_count is not None:
|
||||||
|
rbd_image_options_set_uint64(opts, RBD_IMAGE_OPTION_STRIPE_COUNT,
|
||||||
|
stripe_count)
|
||||||
|
if data_pool is not None:
|
||||||
|
rbd_image_options_set_string(opts, RBD_IMAGE_OPTION_DATA_POOL,
|
||||||
|
data_pool)
|
||||||
|
with nogil:
|
||||||
|
ret = rbd_migration_prepare_import(_source_spec, _dest_ioctx,
|
||||||
|
_dest_image_name, opts)
|
||||||
|
finally:
|
||||||
|
rbd_image_options_destroy(opts)
|
||||||
|
if ret < 0:
|
||||||
|
raise make_ex(ret, 'error migrating image %s' % (source_spec))
|
||||||
|
|
||||||
def migration_execute(self, ioctx, image_name, on_progress=None):
|
def migration_execute(self, ioctx, image_name, on_progress=None):
|
||||||
"""
|
"""
|
||||||
Execute a prepared RBD image migration.
|
Execute a prepared RBD image migration.
|
||||||
|
@ -2619,6 +2619,36 @@ class TestMigration(object):
|
|||||||
RBD().migration_commit(ioctx, image_name)
|
RBD().migration_commit(ioctx, image_name)
|
||||||
remove_image()
|
remove_image()
|
||||||
|
|
||||||
|
def test_migration_import(self):
|
||||||
|
create_image()
|
||||||
|
with Image(ioctx, image_name) as image:
|
||||||
|
image_id = image.id()
|
||||||
|
|
||||||
|
source_spec = json.dumps(
|
||||||
|
{'type': 'native',
|
||||||
|
'pool_id': ioctx.get_pool_id(),
|
||||||
|
'pool_namespace': '',
|
||||||
|
'image_name': image_name,
|
||||||
|
'image_id': image_id})
|
||||||
|
dst_image_name = get_temp_image_name()
|
||||||
|
RBD().migration_prepare_import(source_spec, ioctx, dst_image_name,
|
||||||
|
features=63, order=23, stripe_unit=1<<23,
|
||||||
|
stripe_count=1, data_pool=None)
|
||||||
|
|
||||||
|
status = RBD().migration_status(ioctx, dst_image_name)
|
||||||
|
eq('', status['source_image_name'])
|
||||||
|
eq(dst_image_name, status['dest_image_name'])
|
||||||
|
eq(RBD_IMAGE_MIGRATION_STATE_PREPARED, status['state'])
|
||||||
|
|
||||||
|
with Image(ioctx, dst_image_name) as image:
|
||||||
|
source_spec = image.migration_source_spec()
|
||||||
|
eq("native", source_spec["type"])
|
||||||
|
|
||||||
|
RBD().migration_execute(ioctx, dst_image_name)
|
||||||
|
RBD().migration_commit(ioctx, dst_image_name)
|
||||||
|
RBD().remove(ioctx, dst_image_name)
|
||||||
|
RBD().remove(ioctx, image_name)
|
||||||
|
|
||||||
def test_migration_with_progress(self):
|
def test_migration_with_progress(self):
|
||||||
d = {'received_callback': False}
|
d = {'received_callback': False}
|
||||||
def progress_cb(current, total):
|
def progress_cb(current, total):
|
||||||
|
Loading…
Reference in New Issue
Block a user