// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "acconfig.h" #include "tools/rbd/ArgumentTypes.h" #include "tools/rbd/Shell.h" #include #include "include/ceph_assert.h" namespace rbd { namespace action { namespace at = argument_types; namespace po = boost::program_options; #define DECLARE_DEVICE_OPERATIONS(ns) \ namespace ns { \ int execute_list(const po::variables_map &vm, \ const std::vector &ceph_global_args); \ int execute_map(const po::variables_map &vm, \ const std::vector &ceph_global_args); \ int execute_unmap(const po::variables_map &vm, \ const std::vector &ceph_global_args); \ int execute_attach(const po::variables_map &vm, \ const std::vector &ceph_global_args); \ int execute_detach(const po::variables_map &vm, \ const std::vector &ceph_global_args); \ } DECLARE_DEVICE_OPERATIONS(ggate); DECLARE_DEVICE_OPERATIONS(kernel); DECLARE_DEVICE_OPERATIONS(nbd); DECLARE_DEVICE_OPERATIONS(wnbd); namespace device { namespace { struct DeviceOperations { int (*execute_list)(const po::variables_map &vm, const std::vector &ceph_global_args); int (*execute_map)(const po::variables_map &vm, const std::vector &ceph_global_args); int (*execute_unmap)(const po::variables_map &vm, const std::vector &ceph_global_args); int (*execute_attach)(const po::variables_map &vm, const std::vector &ceph_global_args); int (*execute_detach)(const po::variables_map &vm, const std::vector &ceph_global_args); }; const DeviceOperations ggate_operations = { ggate::execute_list, ggate::execute_map, ggate::execute_unmap, ggate::execute_attach, ggate::execute_detach, }; const DeviceOperations krbd_operations = { kernel::execute_list, kernel::execute_map, kernel::execute_unmap, kernel::execute_attach, kernel::execute_detach, }; const DeviceOperations nbd_operations = { nbd::execute_list, nbd::execute_map, nbd::execute_unmap, nbd::execute_attach, nbd::execute_detach, }; const DeviceOperations wnbd_operations = { wnbd::execute_list, wnbd::execute_map, wnbd::execute_unmap, wnbd::execute_attach, wnbd::execute_detach, }; enum device_type_t { DEVICE_TYPE_GGATE, DEVICE_TYPE_KRBD, DEVICE_TYPE_NBD, DEVICE_TYPE_WNBD, }; struct DeviceType {}; void validate(boost::any& v, const std::vector& values, DeviceType *target_type, int) { po::validators::check_first_occurrence(v); const std::string &s = po::validators::get_single_string(values); #ifdef _WIN32 if (s == "wnbd") { v = boost::any(DEVICE_TYPE_WNBD); #else if (s == "nbd") { v = boost::any(DEVICE_TYPE_NBD); } else if (s == "ggate") { v = boost::any(DEVICE_TYPE_GGATE); } else if (s == "krbd") { v = boost::any(DEVICE_TYPE_KRBD); #endif /* _WIN32 */ } else { throw po::validation_error(po::validation_error::invalid_option_value); } } void add_device_type_option(po::options_description *options) { options->add_options() ("device-type,t", po::value(), #ifdef _WIN32 "device type [wnbd]"); #else "device type [ggate, krbd (default), nbd]"); #endif } void add_device_specific_options(po::options_description *options) { options->add_options() ("options,o", po::value>(), "device specific options"); } device_type_t get_device_type(const po::variables_map &vm) { if (vm.count("device-type")) { return vm["device-type"].as(); } #ifndef _WIN32 return DEVICE_TYPE_KRBD; #else return DEVICE_TYPE_WNBD; #endif } const DeviceOperations *get_device_operations(const po::variables_map &vm) { switch (get_device_type(vm)) { case DEVICE_TYPE_GGATE: return &ggate_operations; case DEVICE_TYPE_KRBD: return &krbd_operations; case DEVICE_TYPE_NBD: return &nbd_operations; case DEVICE_TYPE_WNBD: return &wnbd_operations; default: ceph_abort(); return nullptr; } } } // anonymous namespace void get_list_arguments(po::options_description *positional, po::options_description *options) { add_device_type_option(options); at::add_format_options(options); } int execute_list(const po::variables_map &vm, const std::vector &ceph_global_init_args) { return (*get_device_operations(vm)->execute_list)(vm, ceph_global_init_args); } void get_map_arguments(po::options_description *positional, po::options_description *options) { add_device_type_option(options); at::add_image_or_snap_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE); options->add_options() ("show-cookie", po::bool_switch(), "show device cookie") ("cookie", po::value(), "specify device cookie") ("read-only", po::bool_switch(), "map read-only") ("exclusive", po::bool_switch(), "disable automatic exclusive lock transitions") ("quiesce", po::bool_switch(), "use quiesce hooks") ("quiesce-hook", po::value(), "quiesce hook path"); at::add_snap_id_option(options); add_device_specific_options(options); } int execute_map(const po::variables_map &vm, const std::vector &ceph_global_init_args) { return (*get_device_operations(vm)->execute_map)(vm, ceph_global_init_args); } void get_unmap_arguments(po::options_description *positional, po::options_description *options) { add_device_type_option(options); positional->add_options() ("image-or-snap-or-device-spec", "image, snapshot, or device specification\n" "[/[/]][@] or "); at::add_pool_option(options, at::ARGUMENT_MODIFIER_NONE); at::add_namespace_option(options, at::ARGUMENT_MODIFIER_NONE); at::add_image_option(options, at::ARGUMENT_MODIFIER_NONE); at::add_snap_option(options, at::ARGUMENT_MODIFIER_NONE); at::add_snap_id_option(options); add_device_specific_options(options); } int execute_unmap(const po::variables_map &vm, const std::vector &ceph_global_init_args) { return (*get_device_operations(vm)->execute_unmap)(vm, ceph_global_init_args); } void get_attach_arguments(po::options_description *positional, po::options_description *options) { add_device_type_option(options); at::add_image_or_snap_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE); options->add_options() ("device", po::value()->required(), "specify device path") ("show-cookie", po::bool_switch(), "show device cookie") ("cookie", po::value(), "specify device cookie") ("read-only", po::bool_switch(), "attach read-only") ("force", po::bool_switch(), "force attach") ("exclusive", po::bool_switch(), "disable automatic exclusive lock transitions") ("quiesce", po::bool_switch(), "use quiesce hooks") ("quiesce-hook", po::value(), "quiesce hook path"); at::add_snap_id_option(options); add_device_specific_options(options); } int execute_attach(const po::variables_map &vm, const std::vector &ceph_global_init_args) { return (*get_device_operations(vm)->execute_attach)(vm, ceph_global_init_args); } void get_detach_arguments(po::options_description *positional, po::options_description *options) { add_device_type_option(options); positional->add_options() ("image-or-snap-or-device-spec", "image, snapshot, or device specification\n" "[/[/]][@] or "); at::add_pool_option(options, at::ARGUMENT_MODIFIER_NONE); at::add_namespace_option(options, at::ARGUMENT_MODIFIER_NONE); at::add_image_option(options, at::ARGUMENT_MODIFIER_NONE); at::add_snap_option(options, at::ARGUMENT_MODIFIER_NONE); at::add_snap_id_option(options); add_device_specific_options(options); } int execute_detach(const po::variables_map &vm, const std::vector &ceph_global_init_args) { return (*get_device_operations(vm)->execute_detach)(vm, ceph_global_init_args); } Shell::SwitchArguments switched_arguments({"exclusive", "force", "quiesce", "read-only", "show-cookie"}); Shell::Action action_list( {"device", "list"}, {"showmapped"}, "List mapped rbd images.", "", &get_list_arguments, &execute_list); // yet another alias for list command Shell::Action action_ls( {"device", "ls"}, {}, "List mapped rbd images.", "", &get_list_arguments, &execute_list, false); Shell::Action action_map( {"device", "map"}, {"map"}, "Map an image to a block device.", "", &get_map_arguments, &execute_map); Shell::Action action_unmap( {"device", "unmap"}, {"unmap"}, "Unmap a rbd device.", "", &get_unmap_arguments, &execute_unmap); Shell::Action action_attach( {"device", "attach"}, {}, "Attach image to device.", "", &get_attach_arguments, &execute_attach); Shell::Action action_detach( {"device", "detach"}, {}, "Detach image from device.", "", &get_detach_arguments, &execute_detach); } // namespace device } // namespace action } // namespace rbd