From fe9a4740ee1321093503a4a00dbef2ff51c5fa96 Mon Sep 17 00:00:00 2001 From: Leonid Chernin Date: Mon, 2 Feb 2026 08:01:14 +0200 Subject: [PATCH] first Signed-off-by: Leonid Chernin --- src/librbd/api/Migration.cc | 128 ++++++++++++++++-- .../migration/OpenSourceImageRequest.cc | 38 +++++- src/mon/MonCommands.h | 22 +++ 3 files changed, 174 insertions(+), 14 deletions(-) diff --git a/src/librbd/api/Migration.cc b/src/librbd/api/Migration.cc index 34cd0f13369..d28f723e88b 100644 --- a/src/librbd/api/Migration.cc +++ b/src/librbd/api/Migration.cc @@ -39,7 +39,7 @@ #include "librbd/migration/NativeFormat.h" #include "librbd/mirror/DisableRequest.h" #include "librbd/mirror/EnableRequest.h" - +//#include #include #include // for std::shared_lock @@ -515,6 +515,107 @@ int Migration::prepare(librados::IoCtx& io_ctx, return r; } +constexpr const char* SPEC_SECRET_KEY = "secret_key"; + +static int get_config_key(librados::Rados& rados, const std::string& key, + std::string* value) { + std::string cmd = + "{" + "\"prefix\": \"config-key get\", " + "\"key\": \"" + key + "\"" + "}"; + + bufferlist out_bl; + + int r = rados.mon_command(std::move(cmd), {}, &out_bl, nullptr); + if (r == -EINVAL) { + return -EOPNOTSUPP; + } else if (r < 0 && r != -ENOENT) { + return r; + } + + *value = out_bl.to_str(); + return 0; +} + +static 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 out_bl; + + int r = rados.mon_command(std::move(cmd), {}, &out_bl, nullptr); + if (r == -EINVAL) { + return -EOPNOTSUPP; + } else if (r < 0) { + return r; + } + + return 0; +} + +static int try_get_fsid_secret_key(json_spirit::mObject source_spec_object, + librados::IoCtx& dest_io_ctx) { + std::string secret_key; + auto cct = reinterpret_cast(dest_io_ctx.cct()); + auto it = source_spec_object.find("secret_key"); + if (it != source_spec_object.end()) { + try { + secret_key = it->second.get_str(); + ldout(cct, 5) << "found secret_key in source spec " << secret_key << dendl; + } catch (std::runtime_error&) { + lderr(cct) << "secret_key must be a string" << dendl; + return -EINVAL; + } + + std::string fsid; + auto it_fsid = source_spec_object.find("source_cluster_fsid"); + if (it_fsid != source_spec_object.end()) { + fsid = it_fsid->second.get_str(); + ldout(cct, 5) << "found fsid in source spec " << fsid << dendl; + } else { + lderr(cct) << "source_cluster_fsid missing in spec" << dendl; + return -EINVAL; + } + source_spec_object.erase("secret_key"); // need to remove the key from the spec + std::string sanitized_source_spec = + json_spirit::write(source_spec_object); + ldout(cct, 5) << "sanitized source spec: " + << sanitized_source_spec << dendl; + librados::Rados rados(dest_io_ctx); + int r = set_config_key(rados, "migration/fsid/" + fsid, secret_key); + if (r < 0) { + lderr(reinterpret_cast(rados.cct())) + << "failed to store secret key in monitor: " + << cpp_strerror(r) << dendl; + return r; + } + ldout(cct, 5) << "key set " << fsid << dendl; + std::string value; + r = get_config_key(rados, "migration/fsid/" + fsid, &value); + if (r < 0) { + lderr(reinterpret_cast(rados.cct())) + << "failed to fetch secret key from the monitor: " + << cpp_strerror(r) << dendl; + return r; + } + ldout(cct, 5) << " get value by key " << fsid <<" got "<< value << dendl; + } + return 0; +} + + template int Migration::prepare_import( const std::string& source_spec, librados::IoCtx& dest_io_ctx, @@ -529,6 +630,20 @@ int Migration::prepare_import( << dest_io_ctx.get_pool_name() << "/" << dest_image_name << ", opts=" << opts << dendl; + // use json-spirit to clean-up json formatting + json_spirit::mObject source_spec_object; + json_spirit::mValue json_root; + if(json_spirit::read(source_spec, json_root)) { + try { + source_spec_object = json_root.get_obj(); + } catch (std::runtime_error&) { + lderr(cct) << "failed to clean source spec" << dendl; + return -EINVAL; + } + } + + try_get_fsid_secret_key(source_spec_object, dest_io_ctx); + I* src_image_ctx; librados::Rados* src_rados; C_SaferCond open_ctx; @@ -561,17 +676,6 @@ int Migration::prepare_import( ldout(cct, 20) << "updated opts=" << opts << dendl; - // use json-spirit to clean-up json formatting - json_spirit::mObject source_spec_object; - json_spirit::mValue json_root; - if(json_spirit::read(source_spec, json_root)) { - try { - source_spec_object = json_root.get_obj(); - } catch (std::runtime_error&) { - lderr(cct) << "failed to clean source spec" << dendl; - return -EINVAL; - } - } auto dst_image_ctx = I::create( dest_image_name, util::generate_image_id(dest_io_ctx), nullptr, diff --git a/src/librbd/migration/OpenSourceImageRequest.cc b/src/librbd/migration/OpenSourceImageRequest.cc index 3288a813e9f..161a61a3b9c 100644 --- a/src/librbd/migration/OpenSourceImageRequest.cc +++ b/src/librbd/migration/OpenSourceImageRequest.cc @@ -22,6 +22,27 @@ namespace librbd { namespace migration { + static int get_config_key(librados::Rados& rados, const std::string& key, + std::string* value) { + std::string cmd = + "{" + "\"prefix\": \"config-key get\", " + "\"key\": \"" + key + "\"" + "}"; + + bufferlist out_bl; + + int r = rados.mon_command(std::move(cmd), {}, &out_bl, nullptr); + if (r == -EINVAL) { + return -EOPNOTSUPP; + } else if (r < 0 && r != -ENOENT) { + return r; + } + + *value = out_bl.to_str(); + return 0; +} + template OpenSourceImageRequest::OpenSourceImageRequest( librados::IoCtx& dst_io_ctx, I* dst_image_ctx, uint64_t src_snap_id, @@ -74,7 +95,12 @@ template void OpenSourceImageRequest::open_native( const json_spirit::mObject& source_spec_object, bool import_only) { ldout(m_cct, 10) << dendl; - + std::string fsid; + auto it_fsid = source_spec_object.find("source_cluster_fsid"); + if (it_fsid != source_spec_object.end()) { + fsid = it_fsid->second.get_str(); + ldout(m_cct, 5) << "open_native: found fsid in source spec " << fsid << dendl; + } int r = NativeFormat::create_image_ctx(m_dst_io_ctx, source_spec_object, import_only, m_src_snap_id, m_src_image_ctx, m_src_rados); @@ -84,7 +110,15 @@ void OpenSourceImageRequest::open_native( finish(r); return; } - + std::string value; + r = get_config_key(**m_src_rados, "migration/fsid/" + fsid, &value); + if (r < 0) { + lderr(reinterpret_cast((*m_src_rados)->cct())) + << "failed to fetch secret key from the monitor: " + << cpp_strerror(r) << dendl; + return ; + } + ldout(m_cct, 5) << " get value by key " << fsid <<" got "<< value << dendl; auto src_image_ctx = *m_src_image_ctx; src_image_ctx->child = m_dst_image_ctx; diff --git a/src/mon/MonCommands.h b/src/mon/MonCommands.h index ca9907c51e6..81ffb7010c4 100644 --- a/src/mon/MonCommands.h +++ b/src/mon/MonCommands.h @@ -1459,6 +1459,28 @@ COMMAND("nvme-gw listeners" " show all nvmeof gateways listeners within (pool, group)", "mon", "r") +COMMAND("import-migration put-metadata" + " name=pool,type=CephString" + " name=image,type=CephString" + " name=migration_id,type=CephString" + " name=key_ref,type=CephString", + "Store migration metadata in monitor DB", + "mon", "rw") + +COMMAND("import-migration get-metadata" + " name=pool,type=CephString" + " name=image,type=CephString" + " name=migration_id,type=CephString", + "Retrieve migration metadata from monitor DB", + "mon", "r") + +COMMAND("import-migration erase-metadata" + " name=pool,type=CephString" + " name=image,type=CephString" + " name=migration_id,type=CephString", + "Erase migration metadata from monitor DB", + "mon", "rw") + // these are tell commands that were implemented as CLI commands in // the broken pre-octopus way that we want to allow to work when a // monitor has upgraded to octopus+ but the monmap min_mon_release is -- 2.47.3