]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rbd:export/import image-meta when we export/import an image 17134/head
authorPCzhangPC <pengcheng.zhang@easystack.cn>
Fri, 29 Sep 2017 05:30:01 +0000 (13:30 +0800)
committerPCzhangPC <pengcheng.zhang@easystack.cn>
Fri, 29 Sep 2017 05:30:01 +0000 (13:30 +0800)
when we do exporting/importing an image, we should export or import the image-meta of this image at the same time

Signed-off-by: PCzhangPC <pengcheng.zhang@easystack.cn>
doc/dev/rbd-export.rst
qa/workunits/rbd/import_export.sh
src/tools/rbd/Utils.h
src/tools/rbd/action/Export.cc
src/tools/rbd/action/Import.cc

index 0d34d611b64f416979e045d2c074179140104e8b..d009b79953ab4584e438fd63e672a6b363d9be0d 100644 (file)
@@ -65,6 +65,14 @@ Image Stripe count
 - le64: length of appending data (8)
 - le64: image striping count
 
+ImageMeta Key and Value
+-----------------------
+
+- u8: 'M'
+- le64: length of appending data (length of key + length of value + 4 * 2)
+- string: image-meta key
+- string: image-meta value
+
 Final Record
 ~~~~~~~~~~~~
 
index 639f569d0bbed7a64b5f165ec2921570dec604ad..aff0ad82c7063d1c20bc3c2755d7883e86b4a224 100755 (executable)
@@ -79,10 +79,14 @@ if rbd help export | grep -q export-format; then
     dd if=/bin/dd of=${TMPDIR}/img bs=1k count=10 seek=100
     rbd import $RBD_CREATE_ARGS ${TMPDIR}/img testimg
     rbd snap create testimg@snap
+    rbd image-meta set testimg key1 value1
+    IMAGEMETA_BEFORE=`rbd image-meta list testimg`
     rbd export --export-format 2 testimg ${TMPDIR}/img_v2
     rbd import --export-format 2 ${TMPDIR}/img_v2 testimg_import
     rbd info testimg_import
     rbd info testimg_import@snap
+    IMAGEMETA_AFTER=`rbd image-meta list testimg_import`
+    [ "$IMAGEMETA_BEFORE" = "$IMAGEMETA_AFTER" ]
 
     # compare the contents between testimg and testimg_import
     rbd export testimg_import ${TMPDIR}/img_import
index d60a7b3e2cb67e2589cc14d611b72b30cdd58efb..fe7538315cc48d9c1e74304d2cece7c39a91ed9c 100644 (file)
@@ -50,6 +50,7 @@ static const std::string RBD_DIFF_BANNER_V2 ("rbd diff v2\n");
 #define RBD_EXPORT_IMAGE_FEATURES      'T'
 #define RBD_EXPORT_IMAGE_STRIPE_UNIT   'U'
 #define RBD_EXPORT_IMAGE_STRIPE_COUNT  'C'
+#define RBD_EXPORT_IMAGE_META          'M'
 #define RBD_EXPORT_IMAGE_END           'E'
 
 enum SnapshotPresence {
index bfda6980598a6190c8ec07caf88fde771b26c0ce..0fa0eb07ac16f048208d176213a961a01484c081 100644 (file)
@@ -371,6 +371,8 @@ private:
   int m_fd;
 };
 
+const uint32_t MAX_KEYS = 64;
+
 static int do_export_v2(librbd::Image& image, librbd::image_info_t &info, int fd,
                        uint64_t period, int max_concurrent_ops, utils::ProgressContext &pc)
 {
@@ -414,6 +416,45 @@ static int do_export_v2(librbd::Image& image, librbd::image_info_t &info, int fd
   ::encode(length, bl);
   ::encode(stripe_count, bl);
 
+  //retrieve metadata of image
+  std::map<std::string, string> imagemetas;
+  std::string last_key;
+  bool more_results = true;
+  while (more_results) {
+    std::map<std::string, bufferlist> pairs;
+    r = image.metadata_list(last_key, MAX_KEYS, &pairs);
+    if (r < 0) {
+      std::cerr << "failed to retrieve metadata of image : " << cpp_strerror(r)
+                << std::endl;
+      return r;
+    }
+
+    if (!pairs.empty()) {
+      last_key = pairs.rbegin()->first;
+
+      for (auto kv : pairs) {
+        std::string key = kv.first;
+        std::string val(kv.second.c_str(), kv.second.length());
+        imagemetas[key] = val;
+      }
+    }
+    more_results = (pairs.size() == MAX_KEYS);
+  }
+
+  //encode imageMeta key and value
+  for (std::map<std::string, string>::iterator it = imagemetas.begin();
+       it != imagemetas.end(); ++it) {
+    string key = it->first;
+    string value = it->second;
+
+    tag = RBD_EXPORT_IMAGE_META;
+    length = key.length() + value.length() + 4 * 2;
+    ::encode(tag, bl);
+    ::encode(length, bl);
+    ::encode(key, bl);
+    ::encode(value, bl);
+  }
+
   // encode end tag
   tag = RBD_EXPORT_IMAGE_END;
   ::encode(tag, bl);
index 3c717855270574547b92b5b300aa2b0d37590cac..988d2d1cfe09e723dd20bb4ae0479303c1aa6505 100644 (file)
@@ -555,7 +555,46 @@ static int decode_and_set_image_option(int fd, uint64_t imageopt, librbd::ImageO
   return 0;
 }
 
-static int do_import_header(int fd, int import_format, uint64_t &size, librbd::ImageOptions& opts)
+static int do_import_metadata(int import_format, librbd::Image& image,
+                              const std::map<std::string, std::string> &imagemetas)
+{
+  int r = 0;
+
+  //v1 format
+  if (import_format == 1) {
+    return r;
+  }
+
+  for (std::map<std::string, std::string>::const_iterator it = imagemetas.begin();
+       it != imagemetas.end(); ++it) {
+    r = image.metadata_set(it->first, it->second);
+    if (r < 0)
+      return r;
+  }
+
+  return r;
+}
+
+static int decode_imagemeta(int fd, uint64_t length, std::map<std::string, std::string>* imagemetas)
+{
+  int r;
+  string key;
+  string value;
+
+  r = utils::read_string(fd, length, &key);
+  if (r < 0)
+    return r;
+
+  r = utils::read_string(fd, length, &value);
+  if (r < 0)
+    return r;
+
+  (*imagemetas)[key] = value;
+  return 0;
+}
+
+static int do_import_header(int fd, int import_format, uint64_t &size, librbd::ImageOptions& opts,
+                            std::map<std::string, std::string>* imagemetas)
 {
   // There is no header in v1 image.
   if (import_format == 1) {
@@ -594,6 +633,8 @@ static int do_import_header(int fd, int import_format, uint64_t &size, librbd::I
       r = decode_and_set_image_option(fd, RBD_IMAGE_OPTION_STRIPE_UNIT, opts);
     } else if (tag == RBD_EXPORT_IMAGE_STRIPE_COUNT) {
       r = decode_and_set_image_option(fd, RBD_IMAGE_OPTION_STRIPE_COUNT, opts);
+    } else if (tag == RBD_EXPORT_IMAGE_META) {
+      r = decode_imagemeta(fd, length, imagemetas);
     } else {
       std::cerr << "rbd: invalid tag in image properties zone: " << tag << "Skip it."
                 << std::endl;
@@ -743,6 +784,7 @@ static int do_import(librados::Rados &rados, librbd::RBD &rbd,
   int fd, r;
   struct stat stat_buf;
   utils::ProgressContext pc("Importing image", no_progress);
+  std::map<std::string, std::string> imagemetas;
 
   assert(imgname);
 
@@ -796,7 +838,7 @@ static int do_import(librados::Rados &rados, librbd::RBD &rbd,
 #endif
   }
 
-  r = do_import_header(fd, import_format, size, opts);
+  r = do_import_header(fd, import_format, size, opts, &imagemetas);
   if (r < 0) {
     std::cerr << "rbd: import header failed." << std::endl;
     goto done;
@@ -814,6 +856,12 @@ static int do_import(librados::Rados &rados, librbd::RBD &rbd,
     goto err;
   }
 
+  r = do_import_metadata(import_format, image, imagemetas);
+  if (r < 0) {
+    std::cerr << "rbd: failed to import image-meta" << std::endl;
+    goto err;
+  }
+
   if (import_format == 1) {
     r = do_import_v1(fd, image, size, imgblklen, pc, sparse_size);
   } else {