Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / tools / rbd / action / Lock.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include "tools/rbd/ArgumentTypes.h"
5 #include "tools/rbd/Shell.h"
6 #include "tools/rbd/Utils.h"
7 #include "common/errno.h"
8 #include "common/Formatter.h"
9 #include "common/TextTable.h"
10 #include <iostream>
11 #include <boost/program_options.hpp>
12
13 namespace rbd {
14 namespace action {
15 namespace lock {
16
17 namespace at = argument_types;
18 namespace po = boost::program_options;
19
20 namespace {
21
22 void add_id_option(po::options_description *positional) {
23   positional->add_options()
24     ("lock-id", "unique lock id");
25 }
26
27 int get_id(const po::variables_map &vm, std::string *id) {
28   *id = utils::get_positional_argument(vm, 1);
29   if (id->empty()) {
30     std::cerr << "rbd: lock id was not specified" << std::endl;
31     return -EINVAL;
32   }
33   return 0;
34 }
35
36 } // anonymous namespace
37
38 static int do_lock_list(librbd::Image& image, Formatter *f)
39 {
40   std::list<librbd::locker_t> lockers;
41   bool exclusive;
42   std::string tag;
43   TextTable tbl;
44   int r;
45
46   r = image.list_lockers(&lockers, &exclusive, &tag);
47   if (r < 0)
48     return r;
49
50   if (f) {
51     f->open_object_section("locks");
52   } else {
53     tbl.define_column("Locker", TextTable::LEFT, TextTable::LEFT);
54     tbl.define_column("ID", TextTable::LEFT, TextTable::LEFT);
55     tbl.define_column("Address", TextTable::LEFT, TextTable::LEFT);
56   }
57
58   if (lockers.size()) {
59     bool one = (lockers.size() == 1);
60
61     if (!f) {
62       std::cout << "There " << (one ? "is " : "are ") << lockers.size()
63            << (exclusive ? " exclusive" : " shared")
64            << " lock" << (one ? "" : "s") << " on this image.\n";
65       if (!exclusive)
66         std::cout << "Lock tag: " << tag << "\n";
67     }
68
69     for (std::list<librbd::locker_t>::const_iterator it = lockers.begin();
70          it != lockers.end(); ++it) {
71       if (f) {
72         f->open_object_section(it->cookie.c_str());
73         f->dump_string("locker", it->client);
74         f->dump_string("address", it->address);
75         f->close_section();
76       } else {
77         tbl << it->client << it->cookie << it->address << TextTable::endrow;
78       }
79     }
80     if (!f)
81       std::cout << tbl;
82   }
83
84   if (f) {
85     f->close_section();
86     f->flush(std::cout);
87   }
88   return 0;
89 }
90
91 static int do_lock_add(librbd::Image& image, const char *cookie,
92                        const char *tag)
93 {
94   if (tag)
95     return image.lock_shared(cookie, tag);
96   else
97     return image.lock_exclusive(cookie);
98 }
99
100 static int do_lock_remove(librbd::Image& image, const char *client,
101                           const char *cookie)
102 {
103   return image.break_lock(client, cookie);
104 }
105
106 void get_list_arguments(po::options_description *positional,
107                         po::options_description *options) {
108   at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
109   at::add_format_options(options);
110 }
111
112 int execute_list(const po::variables_map &vm) {
113   size_t arg_index = 0;
114   std::string pool_name;
115   std::string image_name;
116   std::string snap_name;
117   int r = utils::get_pool_image_snapshot_names(
118     vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &image_name,
119     &snap_name, utils::SNAPSHOT_PRESENCE_NONE, utils::SPEC_VALIDATION_NONE);
120   if (r < 0) {
121     return r;
122   }
123
124   at::Format::Formatter formatter;
125   r = utils::get_formatter(vm, &formatter);
126   if (r < 0) {
127     return r;
128   }
129
130   librados::Rados rados;
131   librados::IoCtx io_ctx;
132   librbd::Image image;
133   r = utils::init_and_open_image(pool_name, image_name, "", "", true,
134                                  &rados, &io_ctx, &image);
135   if (r < 0) {
136     return r;
137   }
138
139   r = do_lock_list(image, formatter.get());
140   if (r < 0) {
141     std::cerr << "rbd: listing locks failed: " << cpp_strerror(r) << std::endl;
142     return r;
143   }
144   return 0;
145 }
146
147 void get_add_arguments(po::options_description *positional,
148                        po::options_description *options) {
149   at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
150   add_id_option(positional);
151   options->add_options()
152     ("shared", po::value<std::string>(), "shared lock tag");
153 }
154
155 int execute_add(const po::variables_map &vm) {
156   size_t arg_index = 0;
157   std::string pool_name;
158   std::string image_name;
159   std::string snap_name;
160   int r = utils::get_pool_image_snapshot_names(
161     vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &image_name,
162     &snap_name, utils::SNAPSHOT_PRESENCE_NONE, utils::SPEC_VALIDATION_NONE);
163   if (r < 0) {
164     return r;
165   }
166
167   std::string lock_cookie;
168   r = get_id(vm, &lock_cookie);
169   if (r < 0) {
170     return r;
171   }
172
173   std::string lock_tag;
174   if (vm.count("shared")) {
175     lock_tag = vm["shared"].as<std::string>();
176   }
177
178   librados::Rados rados;
179   librados::IoCtx io_ctx;
180   librbd::Image image;
181   r = utils::init_and_open_image(pool_name, image_name, "", "", false,
182                                  &rados, &io_ctx, &image);
183   if (r < 0) {
184     return r;
185   }
186
187   r = do_lock_add(image, lock_cookie.c_str(),
188                   lock_tag.empty() ? nullptr : lock_tag.c_str());
189   if (r < 0) {
190     if (r == -EBUSY || r == -EEXIST) {
191       if (!lock_tag.empty()) {
192         std::cerr << "rbd: lock is already held by someone else"
193                   << " with a different tag" << std::endl;
194       } else {
195         std::cerr << "rbd: lock is already held by someone else" << std::endl;
196       }
197     } else {
198       std::cerr << "rbd: taking lock failed: " << cpp_strerror(r) << std::endl;
199     }
200     return r;
201   }
202   return 0;
203 }
204
205 void get_remove_arguments(po::options_description *positional,
206                           po::options_description *options) {
207   at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
208   add_id_option(positional);
209   positional->add_options()
210     ("locker", "locker client");
211 }
212
213 int execute_remove(const po::variables_map &vm) {
214   size_t arg_index = 0;
215   std::string pool_name;
216   std::string image_name;
217   std::string snap_name;
218   int r = utils::get_pool_image_snapshot_names(
219     vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &image_name,
220     &snap_name, utils::SNAPSHOT_PRESENCE_NONE, utils::SPEC_VALIDATION_NONE);
221   if (r < 0) {
222     return r;
223   }
224
225   std::string lock_cookie;
226   r = get_id(vm, &lock_cookie);
227   if (r < 0) {
228     return r;
229   }
230
231   std::string lock_client = utils::get_positional_argument(vm, 2);
232   if (lock_client.empty()) {
233     std::cerr << "rbd: locker was not specified" << std::endl;
234     return -EINVAL;
235   }
236
237   librados::Rados rados;
238   librados::IoCtx io_ctx;
239   librbd::Image image;
240   r = utils::init_and_open_image(pool_name, image_name, "", "", false,
241                                  &rados, &io_ctx, &image);
242   if (r < 0) {
243     return r;
244   }
245
246   r = do_lock_remove(image, lock_client.c_str(), lock_cookie.c_str());
247   if (r < 0) {
248     std::cerr << "rbd: releasing lock failed: " << cpp_strerror(r) << std::endl;
249     return r;
250   }
251   return 0;
252 }
253
254 Shell::Action action_list(
255   {"lock", "list"}, {"lock", "ls"}, "Show locks held on an image.", "",
256   &get_list_arguments, &execute_list);
257 Shell::Action action_add(
258   {"lock", "add"}, {}, "Take a lock on an image.", "",
259   &get_add_arguments, &execute_add);
260 Shell::Action action_remove(
261   {"lock", "remove"}, {"lock", "rm"}, "Release a lock on an image.", "",
262   &get_remove_arguments, &execute_remove);
263
264 } // namespace lock
265 } // namespace action
266 } // namespace rbd