// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
+#include "include/compat.h"
#include "common/errno.h"
+#include "common/safe_io.h"
#include "tools/rbd/ArgumentTypes.h"
#include "tools/rbd/Shell.h"
#include "tools/rbd/Utils.h"
+#include <sys/types.h>
+#include <fcntl.h>
#include <iostream>
#include <boost/program_options.hpp>
namespace at = argument_types;
namespace po = boost::program_options;
-static int do_prepare(librados::IoCtx& io_ctx, const std::string &image_name,
- librados::IoCtx& dest_io_ctx,
- const std::string &dest_image_name,
- librbd::ImageOptions& opts) {
- int r = librbd::RBD().migration_prepare(io_ctx, image_name.c_str(),
- dest_io_ctx, dest_image_name.c_str(),
- opts);
- if (r < 0) {
- std::cerr << "rbd: preparing migration failed: " << cpp_strerror(r)
- << std::endl;
- return r;
- }
- return 0;
-}
-
static int do_execute(librados::IoCtx& io_ctx, const std::string &image_name,
bool no_progress) {
utils::ProgressContext pc("Image migration", no_progress);
void get_prepare_arguments(po::options_description *positional,
po::options_description *options) {
+ options->add_options()
+ ("import-only", po::bool_switch(), "only import data from source")
+ ("source-spec-path", po::value<std::string>(),
+ "source-spec file (or '-' for stdin)")
+ ("source-spec", po::value<std::string>(),
+ "source-spec");
at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_SOURCE);
at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_DEST);
at::add_create_image_options(options, true);
return r;
}
+ std::string dst_pool_name;
+ std::string dst_namespace_name;
+ std::string dst_image_name;
+ r = utils::get_pool_image_snapshot_names(
+ vm, at::ARGUMENT_MODIFIER_DEST, &arg_index, &dst_pool_name,
+ &dst_namespace_name, &dst_image_name, nullptr, false,
+ utils::SNAPSHOT_PRESENCE_NONE, utils::SPEC_VALIDATION_FULL);
+ if (r < 0) {
+ return r;
+ }
+
+ bool import_only = vm["import-only"].as<bool>();
+ std::string source_spec;
+ if (vm.count("source-spec") && vm.count("source-spec-path")) {
+ std::cerr << "rbd: cannot specify both source-image-spec and "
+ << "source-spec/source-spec-file" << std::endl;
+ return -EINVAL;
+ } else if (vm.count("source-spec-path")) {
+ std::string source_spec_path = vm["source-spec-path"].as<std::string>();
+
+ int fd = STDIN_FILENO;
+ if (source_spec_path != "-") {
+ fd = open(source_spec_path.c_str(), O_RDONLY);
+ if (fd < 0) {
+ r = -errno;
+ std::cerr << "rbd: error opening " << source_spec_path << std::endl;
+ return r;
+ }
+ }
+
+ source_spec.resize(4096);
+ r = safe_read(fd, source_spec.data(), source_spec.size() - 1);
+ if (fd != STDIN_FILENO) {
+ VOID_TEMP_FAILURE_RETRY(close(fd));
+ }
+
+ if (r >= 0) {
+ source_spec.resize(r);
+ } else {
+ std::cerr << "rbd: error reading source-spec file: " << cpp_strerror(r)
+ << std::endl;
+ return r;
+ }
+ } else if (vm.count("source-spec")) {
+ source_spec = vm["source-spec"].as<std::string>();
+ }
+
librados::Rados rados;
librados::IoCtx io_ctx;
r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
if (r < 0) {
return r;
}
- io_ctx.set_pool_full_try();
- std::string dest_pool_name;
- std::string dest_namespace_name;
- std::string dest_image_name;
- r = utils::get_pool_image_snapshot_names(
- vm, at::ARGUMENT_MODIFIER_DEST, &arg_index, &dest_pool_name,
- &dest_namespace_name, &dest_image_name, nullptr, false,
- utils::SNAPSHOT_PRESENCE_NONE, utils::SPEC_VALIDATION_FULL);
- if (r < 0) {
- return r;
+ librados::IoCtx dst_io_ctx;
+ if (source_spec.empty()) {
+ utils::normalize_pool_name(&dst_pool_name);
+ r = utils::init_io_ctx(rados, dst_pool_name, dst_namespace_name,
+ &dst_io_ctx);
+ if (r < 0) {
+ return r;
+ }
+ }
+
+ if (import_only && source_spec.empty()) {
+ std::stringstream ss;
+ ss << R"({)"
+ << R"("type":"native",)"
+ << R"("pool_id":)" << io_ctx.get_id() << R"(,)"
+ << R"("pool_namespace":")" << io_ctx.get_namespace() << R"(",)"
+ << R"("image_name":")" << image_name << R"(")"
+ << R"(})";
+ source_spec = ss.str();
+
+ if (dst_image_name.empty()) {
+ std::cerr << "rbd: destination image name must be provided" << std::endl;
+ return -EINVAL;
+ }
+ io_ctx = dst_io_ctx;
+ image_name = dst_image_name;
+ } else if (!import_only && !source_spec.empty()) {
+ std::cerr << "rbd: --import-only must be used in combination with "
+ << "source-spec/source-spec-path" << std::endl;
+ return -EINVAL;
}
librbd::ImageOptions opts;
return r;
}
- librados::IoCtx dest_io_ctx;
- utils::normalize_pool_name(&dest_pool_name);
- r = utils::init_io_ctx(rados, dest_pool_name, dest_namespace_name,
- &dest_io_ctx);
- if (r < 0) {
- return r;
- }
+ if (source_spec.empty()) {
+ if (dst_image_name.empty()) {
+ dst_image_name = image_name;
+ }
- r = do_prepare(io_ctx, image_name, dest_pool_name.empty() ? io_ctx :
- dest_io_ctx, dest_image_name, opts);
- if (r < 0) {
- return r;
+ int r = librbd::RBD().migration_prepare(io_ctx, image_name.c_str(),
+ dst_io_ctx, dst_image_name.c_str(),
+ opts);
+ if (r < 0) {
+ std::cerr << "rbd: preparing migration failed: " << cpp_strerror(r)
+ << std::endl;
+ return r;
+ }
+ } else {
+ ceph_assert(import_only);
+ r = librbd::RBD().migration_prepare_import(source_spec.c_str(), io_ctx,
+ image_name.c_str(), opts);
+ if (r < 0) {
+ std::cerr << "rbd: preparing import migration failed: " << cpp_strerror(r)
+ << std::endl;
+ return r;
+ }
}
return 0;