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 write_zeroes
)
84 : m_idiffctx(idiffctx
), m_data(data
), m_offset(offset
), m_length(length
),
85 m_write_zeroes(write_zeroes
) {
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
);
106 if (m_write_zeroes
) {
107 r
= m_idiffctx
->image
->aio_write_zeroes(m_offset
, m_length
,
109 LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
111 r
= m_idiffctx
->image
->aio_write2(m_offset
, m_length
, m_data
,
113 LIBRADOS_OP_FLAG_FADVISE_NOCACHE
);
117 aio_completion
->release();
124 void finish(int r
) override
126 m_idiffctx
->update_progress(m_prog_offset
);
127 m_idiffctx
->throttle
.end_op(r
);
131 ImportDiffContext
*m_idiffctx
;
136 uint64_t m_prog_offset
;
139 static int do_image_snap_from(ImportDiffContext
*idiffctx
)
143 r
= utils::read_string(idiffctx
->fd
, 4096, &from
); // 4k limit to make sure we don't get a garbage string
145 std::cerr
<< "rbd: failed to decode start snap name" << std::endl
;
150 r
= idiffctx
->image
->snap_exists2(from
.c_str(), &exists
);
152 std::cerr
<< "rbd: failed to query start snap state" << std::endl
;
157 std::cerr
<< "start snapshot '" << from
158 << "' does not exist in the image, aborting" << std::endl
;
162 idiffctx
->update_progress();
166 static int do_image_snap_to(ImportDiffContext
*idiffctx
, std::string
*tosnap
)
170 r
= utils::read_string(idiffctx
->fd
, 4096, &to
); // 4k limit to make sure we don't get a garbage string
172 std::cerr
<< "rbd: failed to decode end snap name" << std::endl
;
177 r
= idiffctx
->image
->snap_exists2(to
.c_str(), &exists
);
179 std::cerr
<< "rbd: failed to query end snap state" << std::endl
;
184 std::cerr
<< "end snapshot '" << to
<< "' already exists, aborting"
190 idiffctx
->update_progress();
195 static int get_snap_protection_status(ImportDiffContext
*idiffctx
,
199 char buf
[sizeof(__u8
)];
200 r
= safe_read_exact(idiffctx
->fd
, buf
, sizeof(buf
));
202 std::cerr
<< "rbd: failed to decode snap protection status" << std::endl
;
206 *is_protected
= (buf
[0] != 0);
207 idiffctx
->update_progress();
212 static int do_image_resize(ImportDiffContext
*idiffctx
)
215 char buf
[sizeof(uint64_t)];
217 r
= safe_read_exact(idiffctx
->fd
, buf
, sizeof(buf
));
219 std::cerr
<< "rbd: failed to decode image size" << std::endl
;
224 bl
.append(buf
, sizeof(buf
));
225 auto p
= bl
.cbegin();
229 idiffctx
->image
->size(&cur_size
);
230 if (cur_size
!= end_size
) {
231 idiffctx
->image
->resize(end_size
);
234 idiffctx
->update_size(end_size
);
235 idiffctx
->update_progress();
239 static int do_image_io(ImportDiffContext
*idiffctx
, bool write_zeroes
,
244 r
= safe_read_exact(idiffctx
->fd
, buf
, sizeof(buf
));
246 std::cerr
<< "rbd: failed to decode IO length" << std::endl
;
251 bl
.append(buf
, sizeof(buf
));
252 auto p
= bl
.cbegin();
254 uint64_t image_offset
, buffer_length
;
255 decode(image_offset
, p
);
256 decode(buffer_length
, p
);
259 bufferptr bp
= buffer::create(buffer_length
);
260 r
= safe_read_exact(idiffctx
->fd
, bp
.c_str(), buffer_length
);
262 std::cerr
<< "rbd: failed to decode write data" << std::endl
;
266 size_t buffer_offset
= 0;
267 while (buffer_offset
< buffer_length
) {
268 size_t write_length
= 0;
270 utils::calc_sparse_extent(bp
, sparse_size
, buffer_offset
, buffer_length
,
271 &write_length
, &zeroed
);
272 ceph_assert(write_length
> 0);
276 bufferptr
write_ptr(bp
, buffer_offset
, write_length
);
277 write_bl
.push_back(write_ptr
);
278 ceph_assert(write_bl
.length() == write_length
);
281 C_ImportDiff
*ctx
= new C_ImportDiff(idiffctx
, write_bl
,
282 image_offset
+ buffer_offset
,
283 write_length
, zeroed
);
289 buffer_offset
+= write_length
;
293 C_ImportDiff
*ctx
= new C_ImportDiff(idiffctx
, data
, image_offset
,
294 buffer_length
, true);
300 static int validate_banner(int fd
, std::string banner
)
303 char buf
[banner
.size() + 1];
304 memset(buf
, 0, sizeof(buf
));
305 r
= safe_read_exact(fd
, buf
, banner
.size());
307 std::cerr
<< "rbd: failed to decode diff banner" << std::endl
;
311 buf
[banner
.size()] = '\0';
312 if (strcmp(buf
, banner
.c_str())) {
313 std::cerr
<< "rbd: invalid or unexpected diff banner" << std::endl
;
320 static int skip_tag(int fd
, uint64_t length
)
324 if (fd
== STDIN_FILENO
) {
325 // read the appending data out to skip this tag.
327 uint64_t len
= min
<uint64_t>(length
, sizeof(buf
));
329 r
= safe_read_exact(fd
, buf
, len
);
331 std::cerr
<< "rbd: failed to decode skipped tag data" << std::endl
;
335 len
= min
<uint64_t>(length
, sizeof(buf
));
338 // lseek to skip this tag
339 off64_t offs
= lseek64(fd
, length
, SEEK_CUR
);
348 static int read_tag(int fd
, __u8 end_tag
, int format
, __u8
*tag
, uint64_t *readlen
)
353 r
= safe_read_exact(fd
, &read_tag
, sizeof(read_tag
));
355 std::cerr
<< "rbd: failed to decode tag" << std::endl
;
360 if (read_tag
!= end_tag
&& format
== 2) {
361 char buf
[sizeof(uint64_t)];
362 r
= safe_read_exact(fd
, buf
, sizeof(buf
));
364 std::cerr
<< "rbd: failed to decode tag length" << std::endl
;
369 bl
.append(buf
, sizeof(buf
));
370 auto p
= bl
.cbegin();
377 int do_import_diff_fd(librados::Rados
&rados
, librbd::Image
&image
, int fd
,
378 bool no_progress
, int format
, size_t sparse_size
)
383 bool from_stdin
= (fd
== STDIN_FILENO
);
385 struct stat stat_buf
;
386 r
= ::fstat(fd
, &stat_buf
);
388 std::cerr
<< "rbd: failed to stat specified diff file" << std::endl
;
391 size
= (uint64_t)stat_buf
.st_size
;
394 r
= validate_banner(fd
, (format
== 1 ? utils::RBD_DIFF_BANNER
:
395 utils::RBD_DIFF_BANNER_V2
));
400 // begin image import
402 bool is_protected
= false;
403 ImportDiffContext
idiffctx(&image
, fd
, size
, no_progress
);
408 r
= read_tag(fd
, RBD_DIFF_END
, format
, &tag
, &length
);
409 if (r
< 0 || tag
== RBD_DIFF_END
) {
413 if (tag
== RBD_DIFF_FROM_SNAP
) {
414 r
= do_image_snap_from(&idiffctx
);
415 } else if (tag
== RBD_DIFF_TO_SNAP
) {
416 r
= do_image_snap_to(&idiffctx
, &tosnap
);
417 } else if (tag
== RBD_SNAP_PROTECTION_STATUS
) {
418 r
= get_snap_protection_status(&idiffctx
, &is_protected
);
419 } else if (tag
== RBD_DIFF_IMAGE_SIZE
) {
420 r
= do_image_resize(&idiffctx
);
421 } else if (tag
== RBD_DIFF_WRITE
|| tag
== RBD_DIFF_ZERO
) {
422 r
= do_image_io(&idiffctx
, (tag
== RBD_DIFF_ZERO
), sparse_size
);
424 std::cerr
<< "unrecognized tag byte " << (int)tag
<< " in stream; skipping"
426 r
= skip_tag(fd
, length
);
430 int temp_r
= idiffctx
.throttle
.wait_for_ret();
431 r
= (r
< 0) ? r
: temp_r
; // preserve original error
432 if (r
== 0 && tosnap
.length()) {
433 r
= idiffctx
.image
->snap_create(tosnap
.c_str());
434 if (r
== 0 && is_protected
) {
435 r
= idiffctx
.image
->snap_protect(tosnap
.c_str());
443 int do_import_diff(librados::Rados
&rados
, librbd::Image
&image
,
444 const char *path
, bool no_progress
, size_t sparse_size
)
449 if (strcmp(path
, "-") == 0) {
452 fd
= open(path
, O_RDONLY
|O_BINARY
);
455 std::cerr
<< "rbd: error opening " << path
<< std::endl
;
459 r
= do_import_diff_fd(rados
, image
, fd
, no_progress
, 1, sparse_size
);
466 namespace at
= argument_types
;
467 namespace po
= boost::program_options
;
469 void get_arguments_diff(po::options_description
*positional
,
470 po::options_description
*options
) {
471 at::add_path_options(positional
, options
,
472 "import file (or '-' for stdin)");
473 at::add_image_spec_options(positional
, options
, at::ARGUMENT_MODIFIER_NONE
);
474 at::add_sparse_size_option(options
);
475 at::add_no_progress_option(options
);
478 int execute_diff(const po::variables_map
&vm
,
479 const std::vector
<std::string
> &ceph_global_init_args
) {
481 size_t arg_index
= 0;
482 int r
= utils::get_path(vm
, &arg_index
, &path
);
487 std::string pool_name
;
488 std::string namespace_name
;
489 std::string image_name
;
490 std::string snap_name
;
491 r
= utils::get_pool_image_snapshot_names(
492 vm
, at::ARGUMENT_MODIFIER_NONE
, &arg_index
, &pool_name
, &namespace_name
,
493 &image_name
, &snap_name
, true, utils::SNAPSHOT_PRESENCE_NONE
,
494 utils::SPEC_VALIDATION_NONE
);
499 size_t sparse_size
= utils::RBD_DEFAULT_SPARSE_SIZE
;
500 if (vm
.count(at::IMAGE_SPARSE_SIZE
)) {
501 sparse_size
= vm
[at::IMAGE_SPARSE_SIZE
].as
<size_t>();
504 librados::Rados rados
;
505 librados::IoCtx io_ctx
;
507 r
= utils::init_and_open_image(pool_name
, namespace_name
, image_name
, "", "",
508 false, &rados
, &io_ctx
, &image
);
513 r
= do_import_diff(rados
, image
, path
.c_str(),
514 vm
[at::NO_PROGRESS
].as
<bool>(), sparse_size
);
519 cerr
<< "rbd: import-diff failed: " << cpp_strerror(r
) << std::endl
;
525 Shell::Action
action_diff(
526 {"import-diff"}, {}, "Import an incremental diff.", "", &get_arguments_diff
,
529 class C_Import
: public Context
{
531 C_Import(SimpleThrottle
&simple_throttle
, librbd::Image
&image
,
532 bufferlist
&bl
, uint64_t offset
)
533 : m_throttle(simple_throttle
), m_image(image
),
535 new librbd::RBD::AioCompletion(this, &utils::aio_context_callback
)),
536 m_bufferlist(bl
), m_offset(offset
)
542 m_throttle
.start_op();
544 int op_flags
= LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
|
545 LIBRADOS_OP_FLAG_FADVISE_NOCACHE
;
546 int r
= m_image
.aio_write2(m_offset
, m_bufferlist
.length(), m_bufferlist
,
547 m_aio_completion
, op_flags
);
549 std::cerr
<< "rbd: error requesting write to destination image"
551 m_aio_completion
->release();
552 m_throttle
.end_op(r
);
556 void finish(int r
) override
559 std::cerr
<< "rbd: error writing to destination image at offset "
560 << m_offset
<< ": " << cpp_strerror(r
) << std::endl
;
562 m_throttle
.end_op(r
);
566 SimpleThrottle
&m_throttle
;
567 librbd::Image
&m_image
;
568 librbd::RBD::AioCompletion
*m_aio_completion
;
569 bufferlist m_bufferlist
;
573 static int decode_and_set_image_option(int fd
, uint64_t imageopt
, librbd::ImageOptions
& opts
)
576 char buf
[sizeof(uint64_t)];
578 r
= safe_read_exact(fd
, buf
, sizeof(buf
));
580 std::cerr
<< "rbd: failed to decode image option" << std::endl
;
585 bl
.append(buf
, sizeof(buf
));
586 auto it
= bl
.cbegin();
591 if (opts
.get(imageopt
, &val
) != 0) {
592 opts
.set(imageopt
, val
);
598 static int do_import_metadata(int import_format
, librbd::Image
& image
,
599 const std::map
<std::string
, std::string
> &imagemetas
)
604 if (import_format
== 1) {
608 for (std::map
<std::string
, std::string
>::const_iterator it
= imagemetas
.begin();
609 it
!= imagemetas
.end(); ++it
) {
610 r
= image
.metadata_set(it
->first
, it
->second
);
618 static int decode_imagemeta(int fd
, uint64_t length
, std::map
<std::string
, std::string
>* imagemetas
)
624 r
= utils::read_string(fd
, length
, &key
);
626 std::cerr
<< "rbd: failed to decode metadata key" << std::endl
;
630 r
= utils::read_string(fd
, length
, &value
);
632 std::cerr
<< "rbd: failed to decode metadata value" << std::endl
;
636 (*imagemetas
)[key
] = value
;
640 static int do_import_header(int fd
, int import_format
, librbd::ImageOptions
& opts
,
641 std::map
<std::string
, std::string
>* imagemetas
)
643 // There is no header in v1 image.
644 if (import_format
== 1) {
649 r
= validate_banner(fd
, utils::RBD_IMAGE_BANNER_V2
);
654 // As V1 format for image is already deprecated, import image in V2 by default.
655 uint64_t image_format
= 2;
656 if (opts
.get(RBD_IMAGE_OPTION_FORMAT
, &image_format
) != 0) {
657 opts
.set(RBD_IMAGE_OPTION_FORMAT
, image_format
);
663 r
= read_tag(fd
, RBD_EXPORT_IMAGE_END
, image_format
, &tag
, &length
);
664 if (r
< 0 || tag
== RBD_EXPORT_IMAGE_END
) {
668 if (tag
== RBD_EXPORT_IMAGE_ORDER
) {
669 r
= decode_and_set_image_option(fd
, RBD_IMAGE_OPTION_ORDER
, opts
);
670 } else if (tag
== RBD_EXPORT_IMAGE_FEATURES
) {
671 r
= decode_and_set_image_option(fd
, RBD_IMAGE_OPTION_FEATURES
, opts
);
672 } else if (tag
== RBD_EXPORT_IMAGE_STRIPE_UNIT
) {
673 r
= decode_and_set_image_option(fd
, RBD_IMAGE_OPTION_STRIPE_UNIT
, opts
);
674 } else if (tag
== RBD_EXPORT_IMAGE_STRIPE_COUNT
) {
675 r
= decode_and_set_image_option(fd
, RBD_IMAGE_OPTION_STRIPE_COUNT
, opts
);
676 } else if (tag
== RBD_EXPORT_IMAGE_META
) {
677 r
= decode_imagemeta(fd
, length
, imagemetas
);
679 std::cerr
<< "rbd: invalid tag in image properties zone: " << tag
<< "Skip it."
681 r
= skip_tag(fd
, length
);
688 static int do_import_v2(librados::Rados
&rados
, int fd
, librbd::Image
&image
,
689 uint64_t size
, size_t imgblklen
,
690 utils::ProgressContext
&pc
, size_t sparse_size
)
693 r
= validate_banner(fd
, utils::RBD_IMAGE_DIFFS_BANNER_V2
);
698 char buf
[sizeof(uint64_t)];
699 r
= safe_read_exact(fd
, buf
, sizeof(buf
));
701 std::cerr
<< "rbd: failed to decode diff count" << std::endl
;
705 bl
.append(buf
, sizeof(buf
));
706 auto p
= bl
.cbegin();
709 for (size_t i
= 0; i
< diff_num
; i
++) {
710 r
= do_import_diff_fd(rados
, image
, fd
, true, 2, sparse_size
);
713 std::cerr
<< "rbd: import-diff failed: " << cpp_strerror(r
) << std::endl
;
716 pc
.update_progress(i
+ 1, diff_num
);
722 static int do_import_v1(int fd
, librbd::Image
&image
, uint64_t size
,
723 size_t imgblklen
, utils::ProgressContext
&pc
,
727 size_t reqlen
= imgblklen
; // amount requested from read
728 ssize_t readlen
; // amount received from one read
729 size_t blklen
= 0; // amount accumulated from reads to fill blk
730 char *p
= new char[imgblklen
];
731 uint64_t image_pos
= 0;
732 bool from_stdin
= (fd
== STDIN_FILENO
);
733 boost::scoped_ptr
<SimpleThrottle
> throttle
;
736 throttle
.reset(new SimpleThrottle(1, false));
738 throttle
.reset(new SimpleThrottle(
739 g_conf().get_val
<uint64_t>("rbd_concurrent_management_ops"), false));
742 reqlen
= min
<uint64_t>(reqlen
, size
);
743 // loop body handles 0 return, as we may have a block to flush
744 while ((readlen
= ::read(fd
, p
+ blklen
, reqlen
)) >= 0) {
745 if (throttle
->pending_error()) {
750 // if read was short, try again to fill the block before writing
751 if (readlen
&& ((size_t)readlen
< reqlen
)) {
756 pc
.update_progress(image_pos
, size
);
758 bufferptr
blkptr(p
, blklen
);
759 // resize output image by binary expansion as we go for stdin
760 if (from_stdin
&& (image_pos
+ (size_t)blklen
) > size
) {
762 r
= image
.resize(size
);
764 std::cerr
<< "rbd: can't resize image during import" << std::endl
;
769 // write as much as we got; perhaps less than imgblklen
770 // but skip writing zeros to create sparse images
771 size_t buffer_offset
= 0;
772 while (buffer_offset
< blklen
) {
773 size_t write_length
= 0;
775 utils::calc_sparse_extent(blkptr
, sparse_size
, buffer_offset
, blklen
,
776 &write_length
, &zeroed
);
780 bufferptr
write_ptr(blkptr
, buffer_offset
, write_length
);
781 write_bl
.push_back(write_ptr
);
782 ceph_assert(write_bl
.length() == write_length
);
784 C_Import
*ctx
= new C_Import(*throttle
, image
, write_bl
,
785 image_pos
+ buffer_offset
);
789 buffer_offset
+= write_length
;
792 // done with whole block, whether written or not
794 if (!from_stdin
&& image_pos
>= size
)
796 // if read had returned 0, we're at EOF and should quit
802 r
= throttle
->wait_for_ret();
807 if (fd
== STDIN_FILENO
) {
808 r
= image
.resize(image_pos
);
810 std::cerr
<< "rbd: final image resize failed" << std::endl
;
819 static int do_import(librados::Rados
&rados
, librbd::RBD
&rbd
,
820 librados::IoCtx
& io_ctx
, const char *imgname
,
821 const char *path
, librbd::ImageOptions
& opts
,
822 bool no_progress
, int import_format
, size_t sparse_size
)
825 struct stat stat_buf
;
826 utils::ProgressContext
pc("Importing image", no_progress
);
827 std::map
<std::string
, std::string
> imagemetas
;
829 ceph_assert(imgname
);
832 if (opts
.get(RBD_IMAGE_OPTION_ORDER
, &order
) != 0) {
833 order
= g_conf().get_val
<uint64_t>("rbd_default_order");
836 // try to fill whole imgblklen blocks for sparsification
837 size_t imgblklen
= 1 << order
;
841 bool from_stdin
= !strcmp(path
, "-");
844 size
= 1ULL << order
;
846 if ((fd
= open(path
, O_RDONLY
|O_BINARY
)) < 0) {
848 std::cerr
<< "rbd: error opening " << path
<< std::endl
;
852 if ((fstat(fd
, &stat_buf
)) < 0) {
854 std::cerr
<< "rbd: stat error " << path
<< std::endl
;
857 if (S_ISDIR(stat_buf
.st_mode
)) {
859 std::cerr
<< "rbd: cannot import a directory" << std::endl
;
862 if (stat_buf
.st_size
)
863 size
= (uint64_t)stat_buf
.st_size
;
866 int64_t bdev_size
= 0;
868 r
= blkdev
.get_size(&bdev_size
);
870 std::cerr
<< "rbd: unable to get size of file/block device"
874 ceph_assert(bdev_size
>= 0);
875 size
= (uint64_t) bdev_size
;
877 #ifdef HAVE_POSIX_FADVISE
878 posix_fadvise(fd
, 0, 0, POSIX_FADV_SEQUENTIAL
);
882 r
= do_import_header(fd
, import_format
, opts
, &imagemetas
);
884 std::cerr
<< "rbd: import header failed." << std::endl
;
888 r
= rbd
.create4(io_ctx
, imgname
, size
, opts
);
890 std::cerr
<< "rbd: image creation failed" << std::endl
;
894 r
= rbd
.open(io_ctx
, image
, imgname
);
896 std::cerr
<< "rbd: failed to open image" << std::endl
;
900 r
= do_import_metadata(import_format
, image
, imagemetas
);
902 std::cerr
<< "rbd: failed to import image-meta" << std::endl
;
906 if (import_format
== 1) {
907 r
= do_import_v1(fd
, image
, size
, imgblklen
, pc
, sparse_size
);
909 r
= do_import_v2(rados
, fd
, image
, size
, imgblklen
, pc
, sparse_size
);
912 std::cerr
<< "rbd: failed to import image" << std::endl
;
920 rbd
.remove(io_ctx
, imgname
);
932 void get_arguments(po::options_description
*positional
,
933 po::options_description
*options
) {
934 at::add_path_options(positional
, options
,
935 "import file (or '-' for stdin)");
936 at::add_image_spec_options(positional
, options
, at::ARGUMENT_MODIFIER_DEST
);
937 at::add_create_image_options(options
, true);
938 at::add_sparse_size_option(options
);
939 at::add_no_progress_option(options
);
940 at::add_export_format_option(options
);
942 // TODO legacy rbd allowed import to accept both 'image'/'dest' and
943 // 'pool'/'dest-pool'
944 at::add_pool_option(options
, at::ARGUMENT_MODIFIER_NONE
, " deprecated[:dest-pool]");
945 at::add_image_option(options
, at::ARGUMENT_MODIFIER_NONE
, " deprecated[:dest]");
948 int execute(const po::variables_map
&vm
,
949 const std::vector
<std::string
> &ceph_global_init_args
) {
951 size_t arg_index
= 0;
952 int r
= utils::get_path(vm
, &arg_index
, &path
);
957 // odd check to support legacy / deprecated behavior of import
958 std::string deprecated_pool_name
;
959 if (vm
.count(at::POOL_NAME
)) {
960 deprecated_pool_name
= vm
[at::POOL_NAME
].as
<std::string
>();
963 std::string deprecated_image_name
;
964 if (vm
.count(at::IMAGE_NAME
)) {
965 deprecated_image_name
= vm
[at::IMAGE_NAME
].as
<std::string
>();
967 deprecated_image_name
= path
.substr(path
.find_last_of("/\\") + 1);
970 std::string deprecated_snap_name
;
971 r
= utils::extract_spec(deprecated_image_name
, &deprecated_pool_name
,
972 nullptr, &deprecated_image_name
,
973 &deprecated_snap_name
, utils::SPEC_VALIDATION_FULL
);
978 size_t sparse_size
= utils::RBD_DEFAULT_SPARSE_SIZE
;
979 if (vm
.count(at::IMAGE_SPARSE_SIZE
)) {
980 sparse_size
= vm
[at::IMAGE_SPARSE_SIZE
].as
<size_t>();
983 std::string pool_name
= deprecated_pool_name
;
984 std::string namespace_name
;
985 std::string image_name
;
986 std::string snap_name
= deprecated_snap_name
;
987 r
= utils::get_pool_image_snapshot_names(
988 vm
, at::ARGUMENT_MODIFIER_DEST
, &arg_index
, &pool_name
, &namespace_name
,
989 &image_name
, &snap_name
, false, utils::SNAPSHOT_PRESENCE_NONE
,
990 utils::SPEC_VALIDATION_FULL
);
995 if (image_name
.empty()) {
996 image_name
= deprecated_image_name
;
999 librbd::ImageOptions opts
;
1000 r
= utils::get_image_options(vm
, true, &opts
);
1005 librados::Rados rados
;
1006 librados::IoCtx io_ctx
;
1007 r
= utils::init(pool_name
, namespace_name
, &rados
, &io_ctx
);
1013 if (vm
.count("export-format"))
1014 format
= vm
["export-format"].as
<uint64_t>();
1017 r
= do_import(rados
, rbd
, io_ctx
, image_name
.c_str(), path
.c_str(),
1018 opts
, vm
[at::NO_PROGRESS
].as
<bool>(), format
, sparse_size
);
1020 std::cerr
<< "rbd: import failed: " << cpp_strerror(r
) << std::endl
;
1027 Shell::Action
action(
1028 {"import"}, {}, "Import image from file.", at::get_long_features_help(),
1029 &get_arguments
, &execute
);
1031 } // namespace import
1032 } // namespace action