mirror of
https://github.com/ceph/ceph
synced 2025-02-24 11:37:37 +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,
|
||||
const char *dest_image_name,
|
||||
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,
|
||||
const char *image_name);
|
||||
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,
|
||||
IoCtx& dest_io_ctx, const char *dest_image_name,
|
||||
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_with_progress(IoCtx& io_ctx, const char *image_name,
|
||||
ProgressContext &prog_ctx);
|
||||
|
@ -34,7 +34,9 @@
|
||||
#include "librbd/image/RemoveRequest.h"
|
||||
#include "librbd/image/Types.h"
|
||||
#include "librbd/internal.h"
|
||||
#include "librbd/migration/FormatInterface.h"
|
||||
#include "librbd/migration/NativeFormat.h"
|
||||
#include "librbd/migration/SourceSpecBuilder.h"
|
||||
#include "librbd/mirror/DisableRequest.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;
|
||||
return -ENOSYS;
|
||||
}
|
||||
features &= ~RBD_FEATURES_INTERNAL;
|
||||
features &= ~RBD_FEATURE_DIRTY_CACHE;
|
||||
features &= ~RBD_FEATURES_IMPLICIT_ENABLE;
|
||||
features |= RBD_FEATURE_MIGRATING;
|
||||
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(
|
||||
dest_image_name, util::generate_image_id(dest_io_ctx), nullptr,
|
||||
dest_io_ctx, false);
|
||||
src_image_ctx->image_lock.lock_shared();
|
||||
cls::rbd::MigrationSpec dst_migration_spec{
|
||||
cls::rbd::MIGRATION_HEADER_TYPE_DST, dest_io_ctx.get_id(),
|
||||
dest_io_ctx.get_namespace(), "", "", "", {}, 0,
|
||||
false, cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, flatten > 0,
|
||||
cls::rbd::MIGRATION_HEADER_TYPE_DST,
|
||||
src_image_ctx->md_ctx.get_id(), src_image_ctx->md_ctx.get_namespace(),
|
||||
src_image_ctx->name, src_image_ctx->id, "", {}, 0, false,
|
||||
cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, flatten > 0,
|
||||
cls::rbd::MIGRATION_STATE_PREPARING, ""};
|
||||
src_image_ctx->image_lock.unlock_shared();
|
||||
|
||||
Migration migration(src_image_ctx, dst_image_ctx, dst_migration_spec,
|
||||
opts, nullptr);
|
||||
r = migration.prepare();
|
||||
@ -512,6 +517,88 @@ int Migration<I>::prepare(librados::IoCtx& io_ctx,
|
||||
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>
|
||||
int Migration<I>::execute(librados::IoCtx& io_ctx,
|
||||
const std::string &image_name,
|
||||
@ -552,10 +639,15 @@ int Migration<I>::execute(librados::IoCtx& io_ctx,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ldout(cct, 5) << "migrating " << src_image_ctx->md_ctx.get_pool_name() << "/"
|
||||
<< src_image_ctx->name << " -> "
|
||||
<< dst_image_ctx->md_ctx.get_pool_name()
|
||||
<< "/" << dst_image_ctx->name << dendl;
|
||||
ldout(cct, 5) << "migrating ";
|
||||
if (!dst_migration_spec.source_spec.empty()) {
|
||||
*_dout << dst_migration_spec.source_spec;
|
||||
} 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;
|
||||
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;
|
||||
}
|
||||
|
||||
ldout(cct, 5) << "canceling incomplete migration "
|
||||
<< src_image_ctx->md_ctx.get_pool_name() << "/"
|
||||
<< src_image_ctx->name
|
||||
<< " -> " << dst_image_ctx->md_ctx.get_pool_name() << "/"
|
||||
<< dst_image_ctx->name << dendl;
|
||||
ldout(cct, 5) << "canceling incomplete migration ";
|
||||
if (!dst_migration_spec.source_spec.empty()) {
|
||||
*_dout << dst_migration_spec.source_spec;
|
||||
} 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;
|
||||
Migration migration(src_image_ctx, dst_image_ctx, dst_migration_spec,
|
||||
opts, &prog_ctx);
|
||||
r = migration.abort();
|
||||
|
||||
src_image_ctx->state->close();
|
||||
if (src_image_ctx != nullptr) {
|
||||
src_image_ctx->state->close();
|
||||
}
|
||||
|
||||
if (r < 0) {
|
||||
return r;
|
||||
@ -642,10 +740,15 @@ int Migration<I>::commit(librados::IoCtx& io_ctx,
|
||||
return r;
|
||||
}
|
||||
|
||||
ldout(cct, 5) << "migrating " << src_image_ctx->md_ctx.get_pool_name() << "/"
|
||||
<< src_image_ctx->name << " -> "
|
||||
<< dst_image_ctx->md_ctx.get_pool_name()
|
||||
<< "/" << dst_image_ctx->name << dendl;
|
||||
ldout(cct, 5) << "migrating ";
|
||||
if (!dst_migration_spec.source_spec.empty()) {
|
||||
*_dout << dst_migration_spec.source_spec;
|
||||
} 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;
|
||||
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;
|
||||
}
|
||||
|
||||
ldout(cct, 5) << "migrating " << src_image_ctx->md_ctx.get_pool_name() << "/"
|
||||
<< src_image_ctx->name << " -> "
|
||||
<< dst_image_ctx->md_ctx.get_pool_name()
|
||||
<< "/" << dst_image_ctx->name << dendl;
|
||||
ldout(cct, 5) << "migrating ";
|
||||
if (!dst_migration_spec.source_spec.empty()) {
|
||||
*_dout << dst_migration_spec.source_spec;
|
||||
} 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;
|
||||
Migration migration(src_image_ctx, dst_image_ctx, dst_migration_spec,
|
||||
@ -791,6 +899,25 @@ int Migration<I>::prepare() {
|
||||
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>
|
||||
int Migration<I>::execute() {
|
||||
ldout(m_cct, 10) << dendl;
|
||||
@ -847,21 +974,22 @@ int Migration<I>::abort() {
|
||||
ldout(m_cct, 10) << dendl;
|
||||
|
||||
int r;
|
||||
|
||||
m_src_image_ctx->owner_lock.lock_shared();
|
||||
if (m_src_image_ctx->exclusive_lock != nullptr &&
|
||||
!m_src_image_ctx->exclusive_lock->is_lock_owner()) {
|
||||
C_SaferCond ctx;
|
||||
m_src_image_ctx->exclusive_lock->acquire_lock(&ctx);
|
||||
m_src_image_ctx->owner_lock.unlock_shared();
|
||||
r = ctx.wait();
|
||||
if (r < 0) {
|
||||
lderr(m_cct) << "error acquiring exclusive lock: " << cpp_strerror(r)
|
||||
<< dendl;
|
||||
return r;
|
||||
if (m_src_image_ctx != nullptr) {
|
||||
m_src_image_ctx->owner_lock.lock_shared();
|
||||
if (m_src_image_ctx->exclusive_lock != nullptr &&
|
||||
!m_src_image_ctx->exclusive_lock->is_lock_owner()) {
|
||||
C_SaferCond ctx;
|
||||
m_src_image_ctx->exclusive_lock->acquire_lock(&ctx);
|
||||
m_src_image_ctx->owner_lock.unlock_shared();
|
||||
r = ctx.wait();
|
||||
if (r < 0) {
|
||||
lderr(m_cct) << "error acquiring exclusive lock: " << cpp_strerror(r)
|
||||
<< dendl;
|
||||
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;
|
||||
@ -902,19 +1030,21 @@ int Migration<I>::abort() {
|
||||
return r;
|
||||
}
|
||||
|
||||
// copy dst HEAD -> src HEAD
|
||||
SteppedProgressContext progress_ctx(m_prog_ctx, 2);
|
||||
revert_data(m_dst_image_ctx, m_src_image_ctx, &progress_ctx);
|
||||
progress_ctx.next_step();
|
||||
SteppedProgressContext progress_ctx(
|
||||
m_prog_ctx, (m_src_image_ctx != nullptr ? 2 : 1));
|
||||
if (m_src_image_ctx != nullptr) {
|
||||
// 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;
|
||||
r = relink_children(m_dst_image_ctx, m_src_image_ctx);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
ldout(m_cct, 10) << "relinking children" << dendl;
|
||||
r = relink_children(m_dst_image_ctx, m_src_image_ctx);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
ldout(m_cct, 10) << "removing dst image snapshots" << dendl;
|
||||
|
||||
std::vector<librbd::snap_info_t> snaps;
|
||||
r = Snapshot<I>::list(m_dst_image_ctx, snaps);
|
||||
if (r < 0) {
|
||||
@ -966,24 +1096,26 @@ int Migration<I>::abort() {
|
||||
}
|
||||
}
|
||||
|
||||
r = relink_src_image(m_src_image_ctx);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
if (m_src_image_ctx != nullptr) {
|
||||
r = relink_src_image(m_src_image_ctx);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = add_group(m_src_image_ctx, group_info);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
r = add_group(m_src_image_ctx, group_info);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = remove_migration(m_src_image_ctx);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
r = remove_migration(m_src_image_ctx);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = enable_mirroring(m_src_image_ctx, m_mirroring, m_mirror_image_mode);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
r = enable_mirroring(m_src_image_ctx, m_mirroring, m_mirror_image_mode);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
ldout(m_cct, 10) << "succeeded" << dendl;
|
||||
@ -1007,9 +1139,11 @@ int Migration<I>::commit() {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = remove_src_image(&m_src_image_ctx);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
if (m_src_image_ctx != nullptr) {
|
||||
r = remove_src_image(&m_src_image_ctx);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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>
|
||||
int Migration<I>::set_state(cls::rbd::MigrationState state,
|
||||
const std::string &description) {
|
||||
int r;
|
||||
if (m_src_image_ctx != nullptr) {
|
||||
r = cls_client::migration_set_state(&m_src_image_ctx->md_ctx,
|
||||
m_src_image_ctx->header_oid,
|
||||
state, description);
|
||||
r = set_state(m_src_image_ctx, "source", state, description);
|
||||
if (r < 0) {
|
||||
lderr(m_cct) << "failed to set source migration header: "
|
||||
<< cpp_strerror(r) << dendl;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
r = cls_client::migration_set_state(&m_dst_io_ctx, m_dst_header_oid, state,
|
||||
description);
|
||||
r = set_state(m_dst_image_ctx, "destination", state, description);
|
||||
if (r < 0) {
|
||||
lderr(m_cct) << "failed to set destination migration header: "
|
||||
<< cpp_strerror(r) << dendl;
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -1348,7 +1490,7 @@ int Migration<I>::create_dst_image(I** image_ctx) {
|
||||
m_src_image_ctx->op_work_queue, &on_create);
|
||||
req->send();
|
||||
} 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_io_ctx);
|
||||
if (r < 0) {
|
||||
@ -1410,25 +1552,23 @@ int Migration<I>::create_dst_image(I** image_ctx) {
|
||||
return r;
|
||||
}
|
||||
|
||||
C_SaferCond on_metadata_copy;
|
||||
auto metadata_copy_req = librbd::deep_copy::MetadataCopyRequest<I>::create(
|
||||
m_src_image_ctx, dst_image_ctx, &on_metadata_copy);
|
||||
metadata_copy_req->send();
|
||||
r = on_metadata_copy.wait();
|
||||
if (r < 0) {
|
||||
lderr(m_cct) << "failed to copy metadata: " << cpp_strerror(r) << dendl;
|
||||
return r;
|
||||
if (!m_src_image_ctx->header_oid.empty()) {
|
||||
C_SaferCond on_metadata_copy;
|
||||
auto metadata_copy_req = librbd::deep_copy::MetadataCopyRequest<I>::create(
|
||||
m_src_image_ctx, dst_image_ctx, &on_metadata_copy);
|
||||
metadata_copy_req->send();
|
||||
r = on_metadata_copy.wait();
|
||||
if (r < 0) {
|
||||
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 = {cls::rbd::MIGRATION_HEADER_TYPE_DST,
|
||||
m_src_image_ctx->md_ctx.get_id(),
|
||||
m_src_image_ctx->md_ctx.get_namespace(),
|
||||
m_src_image_ctx->name, m_src_image_ctx->id,
|
||||
"", snap_seqs, size, m_mirroring, m_mirror_image_mode,
|
||||
m_flatten, cls::rbd::MIGRATION_STATE_PREPARING, ""};
|
||||
m_src_image_ctx->image_lock.unlock_shared();
|
||||
|
||||
m_dst_migration_spec.snap_seqs = snap_seqs;
|
||||
m_dst_migration_spec.overlap = size;
|
||||
m_dst_migration_spec.mirroring = m_mirroring;
|
||||
m_dst_migration_spec.mirror_image_mode = m_mirror_image_mode;
|
||||
m_dst_migration_spec.flatten = m_flatten;
|
||||
r = cls_client::migration_set(&m_dst_io_ctx, m_dst_header_oid,
|
||||
m_dst_migration_spec);
|
||||
if (r < 0) {
|
||||
@ -1437,26 +1577,37 @@ int Migration<I>::create_dst_image(I** image_ctx) {
|
||||
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) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = set_state(cls::rbd::MIGRATION_STATE_PREPARED, "");
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
if (m_dst_migration_spec.source_spec.empty()) {
|
||||
r = dst_image_ctx->state->refresh();
|
||||
if (r < 0) {
|
||||
lderr(m_cct) << "failed to refresh destination image: " << cpp_strerror(r)
|
||||
<< dendl;
|
||||
return r;
|
||||
}
|
||||
|
||||
r = dst_image_ctx->state->refresh();
|
||||
if (r < 0) {
|
||||
lderr(m_cct) << "failed to refresh destination image: " << cpp_strerror(r)
|
||||
<< dendl;
|
||||
return r;
|
||||
}
|
||||
|
||||
r = relink_children(m_src_image_ctx, dst_image_ctx);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
r = relink_children(m_src_image_ctx, dst_image_ctx);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -23,6 +23,10 @@ public:
|
||||
static int prepare(librados::IoCtx& io_ctx, const std::string &image_name,
|
||||
librados::IoCtx& dest_io_ctx,
|
||||
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,
|
||||
ProgressContext &prog_ctx);
|
||||
static int abort(librados::IoCtx& io_ctx, const std::string &image_name,
|
||||
@ -56,11 +60,15 @@ private:
|
||||
ImageOptions& opts, ProgressContext *prog_ctx);
|
||||
|
||||
int prepare();
|
||||
int prepare_import();
|
||||
int execute();
|
||||
int abort();
|
||||
int commit();
|
||||
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 list_src_snaps(ImageCtxT* image_ctx,
|
||||
|
@ -923,6 +923,13 @@ namespace librbd {
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
librados::IoCtx io_ctx;
|
||||
|
@ -370,6 +370,10 @@ cdef extern from "rbd/librbd.h" nogil:
|
||||
rados_ioctx_t dest_io_ctx,
|
||||
const char *dest_image_name,
|
||||
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,
|
||||
const char *image_name,
|
||||
librbd_progress_fn_t cb,
|
||||
@ -1688,6 +1692,67 @@ class RBD(object):
|
||||
if ret < 0:
|
||||
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):
|
||||
"""
|
||||
Execute a prepared RBD image migration.
|
||||
|
@ -2619,6 +2619,36 @@ class TestMigration(object):
|
||||
RBD().migration_commit(ioctx, image_name)
|
||||
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):
|
||||
d = {'received_callback': False}
|
||||
def progress_cb(current, total):
|
||||
|
Loading…
Reference in New Issue
Block a user