]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd: new helper API method to retrieving the migration source spec
authorJason Dillaman <dillaman@redhat.com>
Fri, 16 Oct 2020 01:07:07 +0000 (21:07 -0400)
committerJason Dillaman <dillaman@redhat.com>
Sat, 24 Oct 2020 17:51:07 +0000 (13:51 -0400)
When using advanced, non-legacy migration sources like a remote Ceph
cluster or a flat file, this API will return the JSON-encoded description
of the migration source.

Signed-off-by: Jason Dillaman <dillaman@redhat.com>
src/include/rbd/librbd.h
src/include/rbd/librbd.hpp
src/librbd/api/Migration.cc
src/librbd/api/Migration.h
src/librbd/librbd.cc
src/pybind/rbd/rbd.pyx
src/test/librbd/test_librbd.cc
src/test/pybind/test_rbd.py

index 810b03693365885972094c955fe0d8d66dfc53e3..f5626fb0b8adc4919b63a60561fbe50d9551e001 100644 (file)
@@ -726,6 +726,10 @@ CEPH_RBD_API int rbd_get_parent(rbd_image_t image,
                                 rbd_linked_image_spec_t *parent_image,
                                 rbd_snap_spec_t *parent_snap);
 
+CEPH_RBD_API int rbd_get_migration_source_spec(rbd_image_t image,
+                                               char* source_spec,
+                                               size_t* max_len);
+
 CEPH_RBD_API int rbd_get_flags(rbd_image_t image, uint64_t *flags);
 CEPH_RBD_API int rbd_get_group(rbd_image_t image, rbd_group_info_t *group_info,
                                size_t group_info_size);
index ec96f72b8fab83b2de07ac0b359b357d410bc838..151bd6a916e4decc0d433cce2dea8dadc6a462cd 100644 (file)
@@ -528,6 +528,8 @@ public:
       CEPH_RBD_DEPRECATED;
   int get_parent(linked_image_spec_t *parent_image, snap_spec_t *parent_snap);
 
+  int get_migration_source_spec(std::string* source_spec);
+
   int old_format(uint8_t *old);
   int size(uint64_t *size);
   int get_group(group_info_t *group_info, size_t group_info_size);
index cec63ce54f09f5cebe70de76e8d7e410f2ca1bfe..ee0291ee2fc2c7b552bef6d0399da568fd2c8fe4 100644 (file)
@@ -34,6 +34,7 @@
 #include "librbd/image/RemoveRequest.h"
 #include "librbd/image/Types.h"
 #include "librbd/internal.h"
+#include "librbd/migration/NativeFormat.h"
 #include "librbd/mirror/DisableRequest.h"
 #include "librbd/mirror/EnableRequest.h"
 
@@ -661,6 +662,29 @@ int Migration<I>::status(librados::IoCtx& io_ctx,
   return 0;
 }
 
+template <typename I>
+int Migration<I>::get_source_spec(I* image_ctx, std::string* source_spec) {
+  auto cct = image_ctx->cct;
+  ldout(cct, 10) << dendl;
+
+  if (image_ctx->migration_info.empty()) {
+    return -ENOENT;
+  }
+
+  if (!image_ctx->migration_info.source_spec.empty()) {
+    *source_spec = image_ctx->migration_info.source_spec;
+  } else {
+    // legacy migration source
+    *source_spec = migration::NativeFormat<I>::build_source_spec(
+      image_ctx->migration_info.pool_id,
+      image_ctx->migration_info.pool_namespace,
+      image_ctx->migration_info.image_name,
+      image_ctx->migration_info.image_id);
+  }
+
+  return 0;
+}
+
 template <typename I>
 Migration<I>::Migration(I *src_image_ctx, librados::IoCtx& dst_io_ctx,
                         const std::string &dstname,
index 8d24e310d81365d7ed141bfd4bdf9b997907f458..1b070ee60205bf854b6057189e41b26cb51b1362 100644 (file)
@@ -32,6 +32,8 @@ public:
   static int status(librados::IoCtx& io_ctx, const std::string &image_name,
                     image_migration_status_t *status);
 
+  static int get_source_spec(ImageCtxT* image_ctx, std::string* source_spec);
+
 private:
   CephContext* m_cct;
   ImageCtxT *m_src_image_ctx;
index 1af6381f258f80928649505ad4e56ecb3f87f4ac..50897529e2baec5eb1ce8c20257e9f9c1bd87ab1 100644 (file)
@@ -1827,6 +1827,12 @@ namespace librbd {
     return r;
   }
 
+  int Image::get_migration_source_spec(std::string* source_spec)
+  {
+    auto ictx = reinterpret_cast<ImageCtx*>(ctx);
+    return librbd::api::Migration<>::get_source_spec(ictx, source_spec);
+  }
+
   int Image::get_flags(uint64_t *flags)
   {
     ImageCtx *ictx = (ImageCtx *)ctx;
@@ -5129,6 +5135,31 @@ extern "C" int rbd_get_parent(rbd_image_t image,
   return r;
 }
 
+extern "C" int rbd_get_migration_source_spec(rbd_image_t image,
+                                             char* source_spec,
+                                             size_t* max_len)
+{
+  auto ictx = reinterpret_cast<librbd::ImageCtx*>(image);
+
+  std::string cpp_source_spec;
+  int r = librbd::api::Migration<>::get_source_spec(ictx, &cpp_source_spec);
+  if (r < 0) {
+    return r;
+  }
+
+  size_t expected_size = cpp_source_spec.size();
+  if (expected_size >= *max_len) {
+    *max_len = expected_size + 1;
+    return -ERANGE;
+  }
+
+  strncpy(source_spec, cpp_source_spec.c_str(), expected_size);
+  source_spec[expected_size] = '\0';
+  *max_len = expected_size + 1;
+
+  return 0;
+}
+
 extern "C" int rbd_get_flags(rbd_image_t image, uint64_t *flags)
 {
   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
index 8b7d5403c11a583c2472743ebd8ebefa87b16191..4eb6bdbbde92599b7ae5bac0a7ad52711ee7c24a 100644 (file)
@@ -15,6 +15,7 @@ method.
 # Copyright 2015 Hector Martin <marcan@marcan.st>
 
 import cython
+import json
 import sys
 
 from cpython cimport PyObject, ref, exc
@@ -497,6 +498,8 @@ cdef extern from "rbd/librbd.h" nogil:
     int rbd_get_parent(rbd_image_t image,
                        rbd_linked_image_spec_t *parent_image,
                        rbd_snap_spec_t *parent_snap)
+    int rbd_get_migration_source_spec(rbd_image_t image,
+                                      char* source_spec, size_t* max_len)
     int rbd_get_flags(rbd_image_t image, uint64_t *flags)
     int rbd_get_group(rbd_image_t image, rbd_group_info_t *group_info,
                       size_t group_info_size)
@@ -3672,6 +3675,30 @@ cdef class Image(object):
         rbd_snap_spec_cleanup(&snap_spec)
         return result
 
+    @requires_not_closed
+    def migration_source_spec(self):
+        """
+        Get migration source spec (if any)
+
+        :returns: dict
+        :raises: :class:`ImageNotFound` if the image is not migration destination
+        """
+        cdef:
+            size_t size = 512
+            char *spec = NULL
+        try:
+            while True:
+                spec = <char *>realloc_chk(spec, size)
+                with nogil:
+                    ret = rbd_get_migration_source_spec(self.image, spec, &size)
+                if ret >= 0:
+                    break
+                elif ret != -errno.ERANGE:
+                    raise make_ex(ret, 'error retrieving migration source')
+            return json.loads(decode_cstr(spec))
+        finally:
+            free(spec)
+
     @requires_not_closed
     def old_format(self):
         """
index 5c3e27fd67b4d3a17d5ad18e9d2c9f5dff319e6d..93164f616733914149125d7adc5df839e1ce1791 100644 (file)
@@ -20,6 +20,7 @@
 #include "include/event_type.h"
 #include "include/err.h"
 #include "common/ceph_mutex.h"
+#include "json_spirit/json_spirit.h"
 
 #include "gtest/gtest.h"
 
@@ -7370,6 +7371,16 @@ TEST_F(TestLibRBD, Migration) {
   ASSERT_EQ(status.state, RBD_IMAGE_MIGRATION_STATE_PREPARED);
   rbd_migration_status_cleanup(&status);
 
+  rbd_image_t image;
+  ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
+  char source_spec[2048];
+  size_t source_spec_length = sizeof(source_spec);
+  ASSERT_EQ(0, rbd_get_migration_source_spec(image, source_spec,
+                                             &source_spec_length));
+  json_spirit::mValue json_source_spec;
+  json_spirit::read(source_spec, json_source_spec);
+  EXPECT_EQ(0, rbd_close(image));
+
   ASSERT_EQ(-EBUSY, rbd_remove(ioctx, name.c_str()));
   ASSERT_EQ(-EBUSY, rbd_trash_move(ioctx, name.c_str(), 0));
 
@@ -7392,7 +7403,6 @@ TEST_F(TestLibRBD, Migration) {
 
   ASSERT_EQ(0, rbd_migration_abort(ioctx, name.c_str()));
 
-  rbd_image_t image;
   ASSERT_EQ(0, rbd_open(ioctx, name.c_str(), &image, NULL));
   EXPECT_EQ(0, rbd_close(image));
 }
@@ -7433,6 +7443,22 @@ TEST_F(TestLibRBD, MigrationPP) {
   ASSERT_NE(status.dest_image_id, "");
   ASSERT_EQ(status.state, RBD_IMAGE_MIGRATION_STATE_PREPARED);
 
+  librbd::Image image;
+  ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
+  std::string source_spec;
+  ASSERT_EQ(0, image.get_migration_source_spec(&source_spec));
+  json_spirit::mValue json_source_spec;
+  json_spirit::read(source_spec, json_source_spec);
+  json_spirit::mObject json_source_spec_obj = json_source_spec.get_obj();
+  ASSERT_EQ(ioctx.get_id(), json_source_spec_obj["pool_id"].get_int64());
+  ASSERT_EQ("", json_source_spec_obj["pool_namespace"].get_str());
+  if (old_format) {
+    ASSERT_EQ(1, json_source_spec_obj.count("image_name"));
+  } else {
+    ASSERT_EQ(1, json_source_spec_obj.count("image_id"));
+  }
+  ASSERT_EQ(0, image.close());
+
   ASSERT_EQ(-EBUSY, rbd.remove(ioctx, name.c_str()));
   ASSERT_EQ(-EBUSY, rbd.trash_move(ioctx, name.c_str(), 0));
 
@@ -7454,7 +7480,6 @@ TEST_F(TestLibRBD, MigrationPP) {
 
   ASSERT_EQ(0, rbd.migration_abort(ioctx, name.c_str()));
 
-  librbd::Image image;
   ASSERT_EQ(0, rbd.open(ioctx, image, name.c_str(), NULL));
 }
 
index 0fd6cfaa36d9f89ae3c82904aca3b070e843d761..d2810be24aba1230a92617165eca629422bb41a7 100644 (file)
@@ -2521,6 +2521,10 @@ class TestMigration(object):
         eq(image_name, status['dest_image_name'])
         eq(RBD_IMAGE_MIGRATION_STATE_PREPARED, status['state'])
 
+        with Image(ioctx, image_name) as image:
+            source_spec = image.migration_source_spec()
+            eq("native", source_spec["type"])
+
         RBD().migration_execute(ioctx, image_name)
         RBD().migration_commit(ioctx, image_name)
         remove_image()