1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "tools/rbd/ArgumentTypes.h"
5 #include "tools/rbd/Shell.h"
6 #include "tools/rbd/Utils.h"
7 #include "include/Context.h"
8 #include "common/blkdev.h"
9 #include "common/debug.h"
10 #include "common/errno.h"
11 #include "common/Throttle.h"
12 #include "include/compat.h"
13 #include "include/encoding.h"
14 #include "common/debug.h"
15 #include "common/errno.h"
16 #include "common/safe_io.h"
18 #include <boost/program_options.hpp>
19 #include <boost/scoped_ptr.hpp>
20 #include "include/ceph_assert.h"
22 #define dout_context g_ceph_context
23 #define dout_subsys ceph_subsys_rbd
29 struct ImportDiffContext
{
33 utils::ProgressContext pc
;
34 OrderedThrottle throttle
;
37 ImportDiffContext(librbd::Image
*image
, int fd
, size_t size
, bool no_progress
)
38 : image(image
), fd(fd
), size(size
), pc("Importing image diff", no_progress
),
39 throttle((fd
== STDIN_FILENO
) ? 1 :
40 g_conf().get_val
<uint64_t>("rbd_concurrent_management_ops"),
45 void update_size(size_t new_size
)
47 if (fd
== STDIN_FILENO
) {
52 void update_progress(uint64_t off
)
55 pc
.update_progress(off
, size
);
60 void update_progress()
62 uint64_t off
= last_offset
;
63 if (fd
!= STDIN_FILENO
) {
64 off
= lseek(fd
, 0, SEEK_CUR
);
80 class C_ImportDiff
: public Context
{
82 C_ImportDiff(ImportDiffContext
*idiffctx
, bufferlist data
, uint64_t offset
,
83 uint64_t length
, bool discard
)
84 : m_idiffctx(idiffctx
), m_data(data
), m_offset(offset
), m_length(length
),
86 // use block offset (stdin) or import file position to report
88 if (m_idiffctx
->fd
== STDIN_FILENO
) {
89 m_prog_offset
= offset
;
91 m_prog_offset
= lseek(m_idiffctx
->fd
, 0, SEEK_CUR
);
97 if (m_idiffctx
->throttle
.pending_error()) {
98 return m_idiffctx
->throttle
.wait_for_ret();
101 C_OrderedThrottle
*ctx
= m_idiffctx
->throttle
.start_op(this);
102 librbd::RBD::AioCompletion
*aio_completion
=
103 new librbd::RBD::AioCompletion(ctx
, &utils::aio_context_callback
);
107 r
= m_idiffctx
->image
->aio_discard(m_offset
, m_length
, aio_completion
);
109 r
= m_idiffctx
->image
->aio_write2(m_offset
, m_length
, m_data
,
110 aio_completion
, LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
114 aio_completion
->release();
121 void finish(int r
) override
123 m_idiffctx
->update_progress(m_prog_offset
);
124 m_idiffctx
->throttle
.end_op(r
);
128 ImportDiffContext
*m_idiffctx
;
133 uint64_t m_prog_offset
;
136 static int do_image_snap_from(ImportDiffContext
*idiffctx
)
140 r
= utils::read_string(idiffctx
->fd
, 4096, &from
); // 4k limit to make sure we don't get a garbage string
142 std::cerr
<< "rbd: failed to decode start snap name" << std::endl
;
147 r
= idiffctx
->image
->snap_exists2(from
.c_str(), &exists
);
149 std::cerr
<< "rbd: failed to query start snap state" << std::endl
;
154 std::cerr
<< "start snapshot '" << from
155 << "' does not exist in the image, aborting" << std::endl
;
159 idiffctx
->update_progress();
163 static int do_image_snap_to(ImportDiffContext
*idiffctx
, std::string
*tosnap
)
167 r
= utils::read_string(idiffctx
->fd
, 4096, &to
); // 4k limit to make sure we don't get a garbage string
169 std::cerr
<< "rbd: failed to decode end snap name" << std::endl
;
174 r
= idiffctx
->image
->snap_exists2(to
.c_str(), &exists
);
176 std::cerr
<< "rbd: failed to query end snap state" << std::endl
;
181 std::cerr
<< "end snapshot '" << to
<< "' already exists, aborting"
187 idiffctx
->update_progress();
192 static int get_snap_protection_status(ImportDiffContext
*idiffctx
,
196 char buf
[sizeof(__u8
)];
197 r
= safe_read_exact(idiffctx
->fd
, buf
, sizeof(buf
));
199 std::cerr
<< "rbd: failed to decode snap protection status" << std::endl
;
203 *is_protected
= (buf
[0] != 0);
204 idiffctx
->update_progress();
209 static int do_image_resize(ImportDiffContext
*idiffctx
)
212 char buf
[sizeof(uint64_t)];
214 r
= safe_read_exact(idiffctx
->fd
, buf
, sizeof(buf
));
216 std::cerr
<< "rbd: failed to decode image size" << std::endl
;
221 bl
.append(buf
, sizeof(buf
));
222 auto p
= bl
.cbegin();
226 idiffctx
->image
->size(&cur_size
);
227 if (cur_size
!= end_size
) {
228 idiffctx
->image
->resize(end_size
);
231 idiffctx
->update_size(end_size
);
232 idiffctx
->update_progress();
236 static int do_image_io(ImportDiffContext
*idiffctx
, bool discard
, size_t sparse_size
)
240 r
= safe_read_exact(idiffctx
->fd
, buf
, sizeof(buf
));
242 std::cerr
<< "rbd: failed to decode IO length" << std::endl
;
247 bl
.append(buf
, sizeof(buf
));
248 auto p
= bl
.cbegin();
250 uint64_t image_offset
, buffer_length
;
251 decode(image_offset
, p
);
252 decode(buffer_length
, p
);
255 bufferptr bp
= buffer::create(buffer_length
);
256 r
= safe_read_exact(idiffctx
->fd
, bp
.c_str(), buffer_length
);
258 std::cerr
<< "rbd: failed to decode write data" << std::endl
;
262 size_t buffer_offset
= 0;
263 while (buffer_offset
< buffer_length
) {
264 size_t write_length
= 0;
266 utils::calc_sparse_extent(bp
, sparse_size
, buffer_offset
, buffer_length
,
267 &write_length
, &zeroed
);
268 ceph_assert(write_length
> 0);
272 bufferptr
write_ptr(bp
, buffer_offset
, write_length
);
273 write_bl
.push_back(write_ptr
);
274 ceph_assert(write_bl
.length() == write_length
);
277 C_ImportDiff
*ctx
= new C_ImportDiff(idiffctx
, write_bl
,
278 image_offset
+ buffer_offset
,
279 write_length
, zeroed
);
285 buffer_offset
+= write_length
;
289 C_ImportDiff
*ctx
= new C_ImportDiff(idiffctx
, data
, image_offset
,
290 buffer_length
, true);
296 static int validate_banner(int fd
, std::string banner
)
299 char buf
[banner
.size() + 1];
300 memset(buf
, 0, sizeof(buf
));
301 r
= safe_read_exact(fd
, buf
, banner
.size());
303 std::cerr
<< "rbd: failed to decode diff banner" << std::endl
;
307 buf
[banner
.size()] = '\0';
308 if (strcmp(buf
, banner
.c_str())) {
309 std::cerr
<< "rbd: invalid or unexpected diff banner" << std::endl
;
316 static int skip_tag(int fd
, uint64_t length
)
320 if (fd
== STDIN_FILENO
) {
321 // read the appending data out to skip this tag.
323 uint64_t len
= min
<uint64_t>(length
, sizeof(buf
));
325 r
= safe_read_exact(fd
, buf
, len
);
327 std::cerr
<< "rbd: failed to decode skipped tag data" << std::endl
;
331 len
= min
<uint64_t>(length
, sizeof(buf
));
334 // lseek to skip this tag
335 off64_t offs
= lseek64(fd
, length
, SEEK_CUR
);
344 static int read_tag(int fd
, __u8 end_tag
, int format
, __u8
*tag
, uint64_t *readlen
)
349 r
= safe_read_exact(fd
, &read_tag
, sizeof(read_tag
));
351 std::cerr
<< "rbd: failed to decode tag" << std::endl
;
356 if (read_tag
!= end_tag
&& format
== 2) {
357 char buf
[sizeof(uint64_t)];
358 r
= safe_read_exact(fd
, buf
, sizeof(buf
));
360 std::cerr
<< "rbd: failed to decode tag length" << std::endl
;
365 bl
.append(buf
, sizeof(buf
));
366 auto p
= bl
.cbegin();
373 int do_import_diff_fd(librados::Rados
&rados
, librbd::Image
&image
, int fd
,
374 bool no_progress
, int format
, size_t sparse_size
)
379 bool from_stdin
= (fd
== STDIN_FILENO
);
381 struct stat stat_buf
;
382 r
= ::fstat(fd
, &stat_buf
);
384 std::cerr
<< "rbd: failed to stat specified diff file" << std::endl
;
387 size
= (uint64_t)stat_buf
.st_size
;
390 r
= validate_banner(fd
, (format
== 1 ? utils::RBD_DIFF_BANNER
:
391 utils::RBD_DIFF_BANNER_V2
));
396 std::string skip_partial_discard
;
397 r
= rados
.conf_get("rbd_skip_partial_discard", skip_partial_discard
);
398 if (r
< 0 || skip_partial_discard
!= "false") {
399 dout(1) << "disabling sparse import" << dendl
;
404 // begin image import
406 bool is_protected
= false;
407 ImportDiffContext
idiffctx(&image
, fd
, size
, no_progress
);
412 r
= read_tag(fd
, RBD_DIFF_END
, format
, &tag
, &length
);
413 if (r
< 0 || tag
== RBD_DIFF_END
) {
417 if (tag
== RBD_DIFF_FROM_SNAP
) {
418 r
= do_image_snap_from(&idiffctx
);
419 } else if (tag
== RBD_DIFF_TO_SNAP
) {
420 r
= do_image_snap_to(&idiffctx
, &tosnap
);
421 } else if (tag
== RBD_SNAP_PROTECTION_STATUS
) {
422 r
= get_snap_protection_status(&idiffctx
, &is_protected
);
423 } else if (tag
== RBD_DIFF_IMAGE_SIZE
) {
424 r
= do_image_resize(&idiffctx
);
425 } else if (tag
== RBD_DIFF_WRITE
|| tag
== RBD_DIFF_ZERO
) {
426 r
= do_image_io(&idiffctx
, (tag
== RBD_DIFF_ZERO
), sparse_size
);
428 std::cerr
<< "unrecognized tag byte " << (int)tag
<< " in stream; skipping"
430 r
= skip_tag(fd
, length
);
434 int temp_r
= idiffctx
.throttle
.wait_for_ret();
435 r
= (r
< 0) ? r
: temp_r
; // preserve original error
436 if (r
== 0 && tosnap
.length()) {
437 r
= idiffctx
.image
->snap_create(tosnap
.c_str());
438 if (r
== 0 && is_protected
) {
439 r
= idiffctx
.image
->snap_protect(tosnap
.c_str());
447 int do_import_diff(librados::Rados
&rados
, librbd::Image
&image
,
448 const char *path
, bool no_progress
, size_t sparse_size
)
453 if (strcmp(path
, "-") == 0) {
456 fd
= open(path
, O_RDONLY
);
459 std::cerr
<< "rbd: error opening " << path
<< std::endl
;
463 r
= do_import_diff_fd(rados
, image
, fd
, no_progress
, 1, sparse_size
);
470 namespace at
= argument_types
;
471 namespace po
= boost::program_options
;
473 void get_arguments_diff(po::options_description
*positional
,
474 po::options_description
*options
) {
475 at::add_path_options(positional
, options
,
476 "import file (or '-' for stdin)");
477 at::add_image_spec_options(positional
, options
, at::ARGUMENT_MODIFIER_NONE
);
478 at::add_sparse_size_option(options
);
479 at::add_no_progress_option(options
);
482 int execute_diff(const po::variables_map
&vm
,
483 const std::vector
<std::string
> &ceph_global_init_args
) {
485 size_t arg_index
= 0;
486 int r
= utils::get_path(vm
, &arg_index
, &path
);
491 std::string pool_name
;
492 std::string namespace_name
;
493 std::string image_name
;
494 std::string snap_name
;
495 r
= utils::get_pool_image_snapshot_names(
496 vm
, at::ARGUMENT_MODIFIER_NONE
, &arg_index
, &pool_name
, &namespace_name
,
497 &image_name
, &snap_name
, true, utils::SNAPSHOT_PRESENCE_NONE
,
498 utils::SPEC_VALIDATION_NONE
);
503 size_t sparse_size
= utils::RBD_DEFAULT_SPARSE_SIZE
;
504 if (vm
.count(at::IMAGE_SPARSE_SIZE
)) {
505 sparse_size
= vm
[at::IMAGE_SPARSE_SIZE
].as
<size_t>();
508 librados::Rados rados
;
509 librados::IoCtx io_ctx
;
511 r
= utils::init_and_open_image(pool_name
, namespace_name
, image_name
, "", "",
512 false, &rados
, &io_ctx
, &image
);
517 r
= do_import_diff(rados
, image
, path
.c_str(),
518 vm
[at::NO_PROGRESS
].as
<bool>(), sparse_size
);
523 cerr
<< "rbd: import-diff failed: " << cpp_strerror(r
) << std::endl
;
529 Shell::Action
action_diff(
530 {"import-diff"}, {}, "Import an incremental diff.", "", &get_arguments_diff
,
533 class C_Import
: public Context
{
535 C_Import(SimpleThrottle
&simple_throttle
, librbd::Image
&image
,
536 bufferlist
&bl
, uint64_t offset
)
537 : m_throttle(simple_throttle
), m_image(image
),
539 new librbd::RBD::AioCompletion(this, &utils::aio_context_callback
)),
540 m_bufferlist(bl
), m_offset(offset
)
546 m_throttle
.start_op();
548 int op_flags
= LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
|
549 LIBRADOS_OP_FLAG_FADVISE_NOCACHE
;
550 int r
= m_image
.aio_write2(m_offset
, m_bufferlist
.length(), m_bufferlist
,
551 m_aio_completion
, op_flags
);
553 std::cerr
<< "rbd: error requesting write to destination image"
555 m_aio_completion
->release();
556 m_throttle
.end_op(r
);
560 void finish(int r
) override
563 std::cerr
<< "rbd: error writing to destination image at offset "
564 << m_offset
<< ": " << cpp_strerror(r
) << std::endl
;
566 m_throttle
.end_op(r
);
570 SimpleThrottle
&m_throttle
;
571 librbd::Image
&m_image
;
572 librbd::RBD::AioCompletion
*m_aio_completion
;
573 bufferlist m_bufferlist
;
577 static int decode_and_set_image_option(int fd
, uint64_t imageopt
, librbd::ImageOptions
& opts
)
580 char buf
[sizeof(uint64_t)];
582 r
= safe_read_exact(fd
, buf
, sizeof(buf
));
584 std::cerr
<< "rbd: failed to decode image option" << std::endl
;
589 bl
.append(buf
, sizeof(buf
));
590 auto it
= bl
.cbegin();
595 if (opts
.get(imageopt
, &val
) != 0) {
596 opts
.set(imageopt
, val
);
602 static int do_import_metadata(int import_format
, librbd::Image
& image
,
603 const std::map
<std::string
, std::string
> &imagemetas
)
608 if (import_format
== 1) {
612 for (std::map
<std::string
, std::string
>::const_iterator it
= imagemetas
.begin();
613 it
!= imagemetas
.end(); ++it
) {
614 r
= image
.metadata_set(it
->first
, it
->second
);
622 static int decode_imagemeta(int fd
, uint64_t length
, std::map
<std::string
, std::string
>* imagemetas
)
628 r
= utils::read_string(fd
, length
, &key
);
630 std::cerr
<< "rbd: failed to decode metadata key" << std::endl
;
634 r
= utils::read_string(fd
, length
, &value
);
636 std::cerr
<< "rbd: failed to decode metadata value" << std::endl
;
640 (*imagemetas
)[key
] = value
;
644 static int do_import_header(int fd
, int import_format
, librbd::ImageOptions
& opts
,
645 std::map
<std::string
, std::string
>* imagemetas
)
647 // There is no header in v1 image.
648 if (import_format
== 1) {
653 r
= validate_banner(fd
, utils::RBD_IMAGE_BANNER_V2
);
658 // As V1 format for image is already deprecated, import image in V2 by default.
659 uint64_t image_format
= 2;
660 if (opts
.get(RBD_IMAGE_OPTION_FORMAT
, &image_format
) != 0) {
661 opts
.set(RBD_IMAGE_OPTION_FORMAT
, image_format
);
667 r
= read_tag(fd
, RBD_EXPORT_IMAGE_END
, image_format
, &tag
, &length
);
668 if (r
< 0 || tag
== RBD_EXPORT_IMAGE_END
) {
672 if (tag
== RBD_EXPORT_IMAGE_ORDER
) {
673 r
= decode_and_set_image_option(fd
, RBD_IMAGE_OPTION_ORDER
, opts
);
674 } else if (tag
== RBD_EXPORT_IMAGE_FEATURES
) {
675 r
= decode_and_set_image_option(fd
, RBD_IMAGE_OPTION_FEATURES
, opts
);
676 } else if (tag
== RBD_EXPORT_IMAGE_STRIPE_UNIT
) {
677 r
= decode_and_set_image_option(fd
, RBD_IMAGE_OPTION_STRIPE_UNIT
, opts
);
678 } else if (tag
== RBD_EXPORT_IMAGE_STRIPE_COUNT
) {
679 r
= decode_and_set_image_option(fd
, RBD_IMAGE_OPTION_STRIPE_COUNT
, opts
);
680 } else if (tag
== RBD_EXPORT_IMAGE_META
) {
681 r
= decode_imagemeta(fd
, length
, imagemetas
);
683 std::cerr
<< "rbd: invalid tag in image properties zone: " << tag
<< "Skip it."
685 r
= skip_tag(fd
, length
);
692 static int do_import_v2(librados::Rados
&rados
, int fd
, librbd::Image
&image
,
693 uint64_t size
, size_t imgblklen
,
694 utils::ProgressContext
&pc
, size_t sparse_size
)
697 r
= validate_banner(fd
, utils::RBD_IMAGE_DIFFS_BANNER_V2
);
702 char buf
[sizeof(uint64_t)];
703 r
= safe_read_exact(fd
, buf
, sizeof(buf
));
705 std::cerr
<< "rbd: failed to decode diff count" << std::endl
;
709 bl
.append(buf
, sizeof(buf
));
710 auto p
= bl
.cbegin();
713 for (size_t i
= 0; i
< diff_num
; i
++) {
714 r
= do_import_diff_fd(rados
, image
, fd
, true, 2, sparse_size
);
717 std::cerr
<< "rbd: import-diff failed: " << cpp_strerror(r
) << std::endl
;
720 pc
.update_progress(i
+ 1, diff_num
);
726 static int do_import_v1(int fd
, librbd::Image
&image
, uint64_t size
,
727 size_t imgblklen
, utils::ProgressContext
&pc
,
731 size_t reqlen
= imgblklen
; // amount requested from read
732 ssize_t readlen
; // amount received from one read
733 size_t blklen
= 0; // amount accumulated from reads to fill blk
734 char *p
= new char[imgblklen
];
735 uint64_t image_pos
= 0;
736 bool from_stdin
= (fd
== STDIN_FILENO
);
737 boost::scoped_ptr
<SimpleThrottle
> throttle
;
740 throttle
.reset(new SimpleThrottle(1, false));
742 throttle
.reset(new SimpleThrottle(
743 g_conf().get_val
<uint64_t>("rbd_concurrent_management_ops"), false));
746 reqlen
= min
<uint64_t>(reqlen
, size
);
747 // loop body handles 0 return, as we may have a block to flush
748 while ((readlen
= ::read(fd
, p
+ blklen
, reqlen
)) >= 0) {
749 if (throttle
->pending_error()) {
754 // if read was short, try again to fill the block before writing
755 if (readlen
&& ((size_t)readlen
< reqlen
)) {
760 pc
.update_progress(image_pos
, size
);
762 bufferptr
blkptr(p
, blklen
);
763 // resize output image by binary expansion as we go for stdin
764 if (from_stdin
&& (image_pos
+ (size_t)blklen
) > size
) {
766 r
= image
.resize(size
);
768 std::cerr
<< "rbd: can't resize image during import" << std::endl
;
773 // write as much as we got; perhaps less than imgblklen
774 // but skip writing zeros to create sparse images
775 size_t buffer_offset
= 0;
776 while (buffer_offset
< blklen
) {
777 size_t write_length
= 0;
779 utils::calc_sparse_extent(blkptr
, sparse_size
, buffer_offset
, blklen
,
780 &write_length
, &zeroed
);
784 bufferptr
write_ptr(blkptr
, buffer_offset
, write_length
);
785 write_bl
.push_back(write_ptr
);
786 ceph_assert(write_bl
.length() == write_length
);
788 C_Import
*ctx
= new C_Import(*throttle
, image
, write_bl
,
789 image_pos
+ buffer_offset
);
793 buffer_offset
+= write_length
;
796 // done with whole block, whether written or not
798 if (!from_stdin
&& image_pos
>= size
)
800 // if read had returned 0, we're at EOF and should quit
806 r
= throttle
->wait_for_ret();
811 if (fd
== STDIN_FILENO
) {
812 r
= image
.resize(image_pos
);
814 std::cerr
<< "rbd: final image resize failed" << std::endl
;
823 static int do_import(librados::Rados
&rados
, librbd::RBD
&rbd
,
824 librados::IoCtx
& io_ctx
, const char *imgname
,
825 const char *path
, librbd::ImageOptions
& opts
,
826 bool no_progress
, int import_format
, size_t sparse_size
)
829 struct stat stat_buf
;
830 utils::ProgressContext
pc("Importing image", no_progress
);
831 std::map
<std::string
, std::string
> imagemetas
;
833 ceph_assert(imgname
);
836 if (opts
.get(RBD_IMAGE_OPTION_ORDER
, &order
) != 0) {
837 order
= g_conf().get_val
<uint64_t>("rbd_default_order");
840 // try to fill whole imgblklen blocks for sparsification
841 size_t imgblklen
= 1 << order
;
845 bool from_stdin
= !strcmp(path
, "-");
848 size
= 1ULL << order
;
850 if ((fd
= open(path
, O_RDONLY
)) < 0) {
852 std::cerr
<< "rbd: error opening " << path
<< std::endl
;
856 if ((fstat(fd
, &stat_buf
)) < 0) {
858 std::cerr
<< "rbd: stat error " << path
<< std::endl
;
861 if (S_ISDIR(stat_buf
.st_mode
)) {
863 std::cerr
<< "rbd: cannot import a directory" << std::endl
;
866 if (stat_buf
.st_size
)
867 size
= (uint64_t)stat_buf
.st_size
;
870 int64_t bdev_size
= 0;
872 r
= blkdev
.get_size(&bdev_size
);
874 std::cerr
<< "rbd: unable to get size of file/block device"
878 ceph_assert(bdev_size
>= 0);
879 size
= (uint64_t) bdev_size
;
881 #ifdef HAVE_POSIX_FADVISE
882 posix_fadvise(fd
, 0, 0, POSIX_FADV_SEQUENTIAL
);
886 r
= do_import_header(fd
, import_format
, opts
, &imagemetas
);
888 std::cerr
<< "rbd: import header failed." << std::endl
;
892 r
= rbd
.create4(io_ctx
, imgname
, size
, opts
);
894 std::cerr
<< "rbd: image creation failed" << std::endl
;
898 r
= rbd
.open(io_ctx
, image
, imgname
);
900 std::cerr
<< "rbd: failed to open image" << std::endl
;
904 r
= do_import_metadata(import_format
, image
, imagemetas
);
906 std::cerr
<< "rbd: failed to import image-meta" << std::endl
;
910 if (import_format
== 1) {
911 r
= do_import_v1(fd
, image
, size
, imgblklen
, pc
, sparse_size
);
913 r
= do_import_v2(rados
, fd
, image
, size
, imgblklen
, pc
, sparse_size
);
916 std::cerr
<< "rbd: failed to import image" << std::endl
;
924 rbd
.remove(io_ctx
, imgname
);
936 void get_arguments(po::options_description
*positional
,
937 po::options_description
*options
) {
938 at::add_path_options(positional
, options
,
939 "import file (or '-' for stdin)");
940 at::add_image_spec_options(positional
, options
, at::ARGUMENT_MODIFIER_DEST
);
941 at::add_create_image_options(options
, true);
942 at::add_sparse_size_option(options
);
943 at::add_no_progress_option(options
);
944 at::add_export_format_option(options
);
946 // TODO legacy rbd allowed import to accept both 'image'/'dest' and
947 // 'pool'/'dest-pool'
948 at::add_pool_option(options
, at::ARGUMENT_MODIFIER_NONE
, " (deprecated)");
949 at::add_image_option(options
, at::ARGUMENT_MODIFIER_NONE
, " (deprecated)");
952 int execute(const po::variables_map
&vm
,
953 const std::vector
<std::string
> &ceph_global_init_args
) {
955 size_t arg_index
= 0;
956 int r
= utils::get_path(vm
, &arg_index
, &path
);
961 // odd check to support legacy / deprecated behavior of import
962 std::string deprecated_pool_name
;
963 if (vm
.count(at::POOL_NAME
)) {
964 deprecated_pool_name
= vm
[at::POOL_NAME
].as
<std::string
>();
965 std::cerr
<< "rbd: --pool is deprecated for import, use --dest-pool"
969 std::string deprecated_image_name
;
970 if (vm
.count(at::IMAGE_NAME
)) {
971 deprecated_image_name
= vm
[at::IMAGE_NAME
].as
<std::string
>();
972 std::cerr
<< "rbd: --image is deprecated for import, use --dest"
975 deprecated_image_name
= path
.substr(path
.find_last_of("/") + 1);
978 std::string deprecated_snap_name
;
979 r
= utils::extract_spec(deprecated_image_name
, &deprecated_pool_name
,
980 nullptr, &deprecated_image_name
,
981 &deprecated_snap_name
, utils::SPEC_VALIDATION_FULL
);
986 size_t sparse_size
= utils::RBD_DEFAULT_SPARSE_SIZE
;
987 if (vm
.count(at::IMAGE_SPARSE_SIZE
)) {
988 sparse_size
= vm
[at::IMAGE_SPARSE_SIZE
].as
<size_t>();
991 std::string pool_name
= deprecated_pool_name
;
992 std::string namespace_name
;
993 std::string image_name
;
994 std::string snap_name
= deprecated_snap_name
;
995 r
= utils::get_pool_image_snapshot_names(
996 vm
, at::ARGUMENT_MODIFIER_DEST
, &arg_index
, &pool_name
, &namespace_name
,
997 &image_name
, &snap_name
, false, utils::SNAPSHOT_PRESENCE_NONE
,
998 utils::SPEC_VALIDATION_FULL
);
1003 if (image_name
.empty()) {
1004 image_name
= deprecated_image_name
;
1007 librbd::ImageOptions opts
;
1008 r
= utils::get_image_options(vm
, true, &opts
);
1013 librados::Rados rados
;
1014 librados::IoCtx io_ctx
;
1015 r
= utils::init(pool_name
, namespace_name
, &rados
, &io_ctx
);
1021 if (vm
.count("export-format"))
1022 format
= vm
["export-format"].as
<uint64_t>();
1025 r
= do_import(rados
, rbd
, io_ctx
, image_name
.c_str(), path
.c_str(),
1026 opts
, vm
[at::NO_PROGRESS
].as
<bool>(), format
, sparse_size
);
1028 std::cerr
<< "rbd: import failed: " << cpp_strerror(r
) << std::endl
;
1035 Shell::Action
action(
1036 {"import"}, {}, "Import image from file.", at::get_long_features_help(),
1037 &get_arguments
, &execute
);
1039 } // namespace import
1040 } // namespace action