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/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
<int64_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 bufferlist::iterator p
= bl
.begin();
223 ::decode(end_size
, p
);
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 bufferlist::iterator p
= bl
.begin();
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 assert(write_length
> 0);
272 bufferptr
write_ptr(bp
, buffer_offset
, write_length
);
273 write_bl
.push_back(write_ptr
);
274 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 bufferlist::iterator p
= bl
.begin();
367 ::decode(*readlen
, p
);
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
) {
484 int r
= utils::get_path(vm
, utils::get_positional_argument(vm
, 0), &path
);
489 size_t arg_index
= 1;
490 std::string pool_name
;
491 std::string image_name
;
492 std::string snap_name
;
493 r
= utils::get_pool_image_snapshot_names(
494 vm
, at::ARGUMENT_MODIFIER_NONE
, &arg_index
, &pool_name
, &image_name
,
495 &snap_name
, utils::SNAPSHOT_PRESENCE_NONE
, utils::SPEC_VALIDATION_NONE
);
500 size_t sparse_size
= utils::RBD_DEFAULT_SPARSE_SIZE
;
501 if (vm
.count(at::IMAGE_SPARSE_SIZE
)) {
502 sparse_size
= vm
[at::IMAGE_SPARSE_SIZE
].as
<size_t>();
505 librados::Rados rados
;
506 librados::IoCtx io_ctx
;
508 r
= utils::init_and_open_image(pool_name
, image_name
, "", "", false,
509 &rados
, &io_ctx
, &image
);
514 r
= do_import_diff(rados
, image
, path
.c_str(),
515 vm
[at::NO_PROGRESS
].as
<bool>(), sparse_size
);
520 cerr
<< "rbd: import-diff failed: " << cpp_strerror(r
) << std::endl
;
526 Shell::Action
action_diff(
527 {"import-diff"}, {}, "Import an incremental diff.", "", &get_arguments_diff
,
530 class C_Import
: public Context
{
532 C_Import(SimpleThrottle
&simple_throttle
, librbd::Image
&image
,
533 bufferlist
&bl
, uint64_t offset
)
534 : m_throttle(simple_throttle
), m_image(image
),
536 new librbd::RBD::AioCompletion(this, &utils::aio_context_callback
)),
537 m_bufferlist(bl
), m_offset(offset
)
543 m_throttle
.start_op();
545 int op_flags
= LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
|
546 LIBRADOS_OP_FLAG_FADVISE_NOCACHE
;
547 int r
= m_image
.aio_write2(m_offset
, m_bufferlist
.length(), m_bufferlist
,
548 m_aio_completion
, op_flags
);
550 std::cerr
<< "rbd: error requesting write to destination image"
552 m_aio_completion
->release();
553 m_throttle
.end_op(r
);
557 void finish(int r
) override
560 std::cerr
<< "rbd: error writing to destination image at offset "
561 << m_offset
<< ": " << cpp_strerror(r
) << std::endl
;
563 m_throttle
.end_op(r
);
567 SimpleThrottle
&m_throttle
;
568 librbd::Image
&m_image
;
569 librbd::RBD::AioCompletion
*m_aio_completion
;
570 bufferlist m_bufferlist
;
574 static int decode_and_set_image_option(int fd
, uint64_t imageopt
, librbd::ImageOptions
& opts
)
577 char buf
[sizeof(uint64_t)];
579 r
= safe_read_exact(fd
, buf
, sizeof(buf
));
581 std::cerr
<< "rbd: failed to decode image option" << std::endl
;
586 bl
.append(buf
, sizeof(buf
));
587 bufferlist::iterator it
;
593 if (opts
.get(imageopt
, &val
) != 0) {
594 opts
.set(imageopt
, val
);
600 static int do_import_metadata(int import_format
, librbd::Image
& image
,
601 const std::map
<std::string
, std::string
> &imagemetas
)
606 if (import_format
== 1) {
610 for (std::map
<std::string
, std::string
>::const_iterator it
= imagemetas
.begin();
611 it
!= imagemetas
.end(); ++it
) {
612 r
= image
.metadata_set(it
->first
, it
->second
);
620 static int decode_imagemeta(int fd
, uint64_t length
, std::map
<std::string
, std::string
>* imagemetas
)
626 r
= utils::read_string(fd
, length
, &key
);
628 std::cerr
<< "rbd: failed to decode metadata key" << std::endl
;
632 r
= utils::read_string(fd
, length
, &value
);
634 std::cerr
<< "rbd: failed to decode metadata value" << std::endl
;
638 (*imagemetas
)[key
] = value
;
642 static int do_import_header(int fd
, int import_format
, uint64_t &size
, librbd::ImageOptions
& opts
,
643 std::map
<std::string
, std::string
>* imagemetas
)
645 // There is no header in v1 image.
646 if (import_format
== 1) {
650 if (fd
== STDIN_FILENO
|| size
< utils::RBD_IMAGE_BANNER_V2
.size()) {
655 r
= validate_banner(fd
, utils::RBD_IMAGE_BANNER_V2
);
660 // As V1 format for image is already deprecated, import image in V2 by default.
661 uint64_t image_format
= 2;
662 if (opts
.get(RBD_IMAGE_OPTION_FORMAT
, &image_format
) != 0) {
663 opts
.set(RBD_IMAGE_OPTION_FORMAT
, image_format
);
669 r
= read_tag(fd
, RBD_EXPORT_IMAGE_END
, image_format
, &tag
, &length
);
670 if (r
< 0 || tag
== RBD_EXPORT_IMAGE_END
) {
674 if (tag
== RBD_EXPORT_IMAGE_ORDER
) {
675 r
= decode_and_set_image_option(fd
, RBD_IMAGE_OPTION_ORDER
, opts
);
676 } else if (tag
== RBD_EXPORT_IMAGE_FEATURES
) {
677 r
= decode_and_set_image_option(fd
, RBD_IMAGE_OPTION_FEATURES
, opts
);
678 } else if (tag
== RBD_EXPORT_IMAGE_STRIPE_UNIT
) {
679 r
= decode_and_set_image_option(fd
, RBD_IMAGE_OPTION_STRIPE_UNIT
, opts
);
680 } else if (tag
== RBD_EXPORT_IMAGE_STRIPE_COUNT
) {
681 r
= decode_and_set_image_option(fd
, RBD_IMAGE_OPTION_STRIPE_COUNT
, opts
);
682 } else if (tag
== RBD_EXPORT_IMAGE_META
) {
683 r
= decode_imagemeta(fd
, length
, imagemetas
);
685 std::cerr
<< "rbd: invalid tag in image properties zone: " << tag
<< "Skip it."
687 r
= skip_tag(fd
, length
);
694 static int do_import_v2(librados::Rados
&rados
, int fd
, librbd::Image
&image
,
695 uint64_t size
, size_t imgblklen
,
696 utils::ProgressContext
&pc
, size_t sparse_size
)
699 r
= validate_banner(fd
, utils::RBD_IMAGE_DIFFS_BANNER_V2
);
704 char buf
[sizeof(uint64_t)];
705 r
= safe_read_exact(fd
, buf
, sizeof(buf
));
707 std::cerr
<< "rbd: failed to decode diff count" << std::endl
;
711 bl
.append(buf
, sizeof(buf
));
712 bufferlist::iterator p
= bl
.begin();
714 ::decode(diff_num
, p
);
716 for (size_t i
= 0; i
< diff_num
; i
++) {
717 r
= do_import_diff_fd(rados
, image
, fd
, true, 2, sparse_size
);
720 std::cerr
<< "rbd: import-diff failed: " << cpp_strerror(r
) << std::endl
;
723 pc
.update_progress(i
+ 1, diff_num
);
729 static int do_import_v1(int fd
, librbd::Image
&image
, uint64_t size
,
730 size_t imgblklen
, utils::ProgressContext
&pc
,
734 size_t reqlen
= imgblklen
; // amount requested from read
735 ssize_t readlen
; // amount received from one read
736 size_t blklen
= 0; // amount accumulated from reads to fill blk
737 char *p
= new char[imgblklen
];
738 uint64_t image_pos
= 0;
739 bool from_stdin
= (fd
== STDIN_FILENO
);
740 boost::scoped_ptr
<SimpleThrottle
> throttle
;
743 throttle
.reset(new SimpleThrottle(1, false));
745 throttle
.reset(new SimpleThrottle(
746 g_conf
->get_val
<int64_t>("rbd_concurrent_management_ops"), false));
749 reqlen
= min
<uint64_t>(reqlen
, size
);
750 // loop body handles 0 return, as we may have a block to flush
751 while ((readlen
= ::read(fd
, p
+ blklen
, reqlen
)) >= 0) {
752 if (throttle
->pending_error()) {
757 // if read was short, try again to fill the block before writing
758 if (readlen
&& ((size_t)readlen
< reqlen
)) {
763 pc
.update_progress(image_pos
, size
);
765 bufferptr
blkptr(p
, blklen
);
766 // resize output image by binary expansion as we go for stdin
767 if (from_stdin
&& (image_pos
+ (size_t)blklen
) > size
) {
769 r
= image
.resize(size
);
771 std::cerr
<< "rbd: can't resize image during import" << std::endl
;
776 // write as much as we got; perhaps less than imgblklen
777 // but skip writing zeros to create sparse images
778 size_t buffer_offset
= 0;
779 while (buffer_offset
< blklen
) {
780 size_t write_length
= 0;
782 utils::calc_sparse_extent(blkptr
, sparse_size
, buffer_offset
, blklen
,
783 &write_length
, &zeroed
);
787 bufferptr
write_ptr(blkptr
, buffer_offset
, write_length
);
788 write_bl
.push_back(write_ptr
);
789 assert(write_bl
.length() == write_length
);
791 C_Import
*ctx
= new C_Import(*throttle
, image
, write_bl
,
792 image_pos
+ buffer_offset
);
796 buffer_offset
+= write_length
;
799 // done with whole block, whether written or not
801 if (!from_stdin
&& image_pos
>= size
)
803 // if read had returned 0, we're at EOF and should quit
809 r
= throttle
->wait_for_ret();
814 if (fd
== STDIN_FILENO
) {
815 r
= image
.resize(image_pos
);
817 std::cerr
<< "rbd: final image resize failed" << std::endl
;
826 static int do_import(librados::Rados
&rados
, librbd::RBD
&rbd
,
827 librados::IoCtx
& io_ctx
, const char *imgname
,
828 const char *path
, librbd::ImageOptions
& opts
,
829 bool no_progress
, int import_format
, size_t sparse_size
)
832 struct stat stat_buf
;
833 utils::ProgressContext
pc("Importing image", no_progress
);
834 std::map
<std::string
, std::string
> imagemetas
;
839 if (opts
.get(RBD_IMAGE_OPTION_ORDER
, &order
) != 0) {
840 order
= g_conf
->get_val
<int64_t>("rbd_default_order");
843 // try to fill whole imgblklen blocks for sparsification
844 size_t imgblklen
= 1 << order
;
848 bool from_stdin
= !strcmp(path
, "-");
851 size
= 1ULL << order
;
853 if ((fd
= open(path
, O_RDONLY
)) < 0) {
855 std::cerr
<< "rbd: error opening " << path
<< std::endl
;
859 if ((fstat(fd
, &stat_buf
)) < 0) {
861 std::cerr
<< "rbd: stat error " << path
<< std::endl
;
864 if (S_ISDIR(stat_buf
.st_mode
)) {
866 std::cerr
<< "rbd: cannot import a directory" << std::endl
;
869 if (stat_buf
.st_size
)
870 size
= (uint64_t)stat_buf
.st_size
;
873 int64_t bdev_size
= 0;
874 r
= get_block_device_size(fd
, &bdev_size
);
876 std::cerr
<< "rbd: unable to get size of file/block device"
880 assert(bdev_size
>= 0);
881 size
= (uint64_t) bdev_size
;
883 #ifdef HAVE_POSIX_FADVISE
884 posix_fadvise(fd
, 0, 0, POSIX_FADV_SEQUENTIAL
);
888 r
= do_import_header(fd
, import_format
, size
, opts
, &imagemetas
);
890 std::cerr
<< "rbd: import header failed." << std::endl
;
894 r
= rbd
.create4(io_ctx
, imgname
, size
, opts
);
896 std::cerr
<< "rbd: image creation failed" << std::endl
;
900 r
= rbd
.open(io_ctx
, image
, imgname
);
902 std::cerr
<< "rbd: failed to open image" << std::endl
;
906 r
= do_import_metadata(import_format
, image
, imagemetas
);
908 std::cerr
<< "rbd: failed to import image-meta" << std::endl
;
912 if (import_format
== 1) {
913 r
= do_import_v1(fd
, image
, size
, imgblklen
, pc
, sparse_size
);
915 r
= do_import_v2(rados
, fd
, image
, size
, imgblklen
, pc
, sparse_size
);
918 std::cerr
<< "rbd: failed to import image" << std::endl
;
926 rbd
.remove(io_ctx
, imgname
);
938 void get_arguments(po::options_description
*positional
,
939 po::options_description
*options
) {
940 at::add_path_options(positional
, options
,
941 "import file (or '-' for stdin)");
942 at::add_image_spec_options(positional
, options
, at::ARGUMENT_MODIFIER_DEST
);
943 at::add_create_image_options(options
, true);
944 at::add_sparse_size_option(options
);
945 at::add_no_progress_option(options
);
946 at::add_export_format_option(options
);
948 // TODO legacy rbd allowed import to accept both 'image'/'dest' and
949 // 'pool'/'dest-pool'
950 at::add_pool_option(options
, at::ARGUMENT_MODIFIER_NONE
, " (deprecated)");
951 at::add_image_option(options
, at::ARGUMENT_MODIFIER_NONE
, " (deprecated)");
954 int execute(const po::variables_map
&vm
) {
956 int r
= utils::get_path(vm
, utils::get_positional_argument(vm
, 0), &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 &deprecated_image_name
, &deprecated_snap_name
,
981 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 size_t arg_index
= 1;
992 std::string pool_name
= deprecated_pool_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
, &image_name
,
997 &snap_name
, utils::SNAPSHOT_PRESENCE_NONE
, 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
, &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