]> git.proxmox.com Git - ceph.git/blame - ceph/src/tools/monmaptool.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / tools / monmaptool.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14#include <string>
15
16#include "common/ceph_argparse.h"
17#include "common/errno.h"
18
19#include "global/global_init.h"
20#include "include/str_list.h"
21#include "mon/MonMap.h"
22
7c673cae
FG
23
24void usage()
25{
11fdf7f2
TL
26 cout << "usage: monmaptool [--print] [--create [--clobber] [--fsid uuid]]\n"
27 << " [--enable-all-features]\n"
7c673cae
FG
28 << " [--generate] [--set-initial-members]\n"
29 << " [--add name 1.2.3.4:567] [--rm name]\n"
30 << " [--feature-list [plain|parseable]]\n"
31 << " [--feature-set <value> [--optional|--persistent]]\n"
11fdf7f2
TL
32 << " [--feature-unset <value> [--optional|--persistent]]\n"
33 << " [--set-min-mon-release <release-major-number>]\n"
34 << " <mapfilename>"
7c673cae 35 << std::endl;
11fdf7f2
TL
36}
37
38void helpful_exit()
39{
40 cerr << "monmaptool -h for usage" << std::endl;
7c673cae
FG
41 exit(1);
42}
43
44struct feature_op_t {
45 enum type_t {
46 PERSISTENT,
47 OPTIONAL,
48 PLAIN,
49 PARSEABLE,
50 NONE
51 };
52
53 enum op_t {
54 OP_SET,
55 OP_UNSET,
56 OP_LIST
57 };
58
59 op_t op;
60 type_t type;
61 mon_feature_t feature;
62
63 feature_op_t() : op(OP_LIST), type(NONE) { }
64 // default to 'persistent' feature if not specified
65 feature_op_t(op_t o) : op(o), type(PERSISTENT) { }
66 feature_op_t(op_t o, type_t t) : op(o), type(t) { }
67 feature_op_t(op_t o, type_t t, mon_feature_t &f) :
68 op(o), type(t), feature(t) { }
69
70 void set_optional() {
71 type = OPTIONAL;
72 }
73 void set_persistent() {
74 type = PERSISTENT;
75 }
76 bool parse_value(string &s, ostream *errout = NULL) {
77
78 feature = ceph::features::mon::get_feature_by_name(s);
79 if (feature != ceph::features::mon::FEATURE_NONE) {
80 return true;
81 }
82
83 // try parsing as numerical value
84 uint64_t feature_val;
85 string interr;
86 feature_val = strict_strtoll(s.c_str(), 10, &interr);
87 if (!interr.empty()) {
88 if (errout) {
89 *errout << "unknown features name '" << s
90 << "' or unable to parse value: " << interr << std::endl;
91 }
92 return false;
93 }
94 feature = mon_feature_t(feature_val);
95 return true;
96 }
97};
98
99void features_list(feature_op_t &f, MonMap &m)
100{
101 if (f.type == feature_op_t::type_t::PLAIN) {
102
103 cout << "MONMAP FEATURES:" << std::endl;
104 cout << " persistent: ";
105 m.persistent_features.print_with_value(cout);
106 cout << std::endl;
107 cout << " optional: ";
108 m.optional_features.print_with_value(cout);
109 cout << std::endl;
110 cout << " required: ";
111 m.get_required_features().print_with_value(cout);
112 cout << std::endl;
113
114 cout << std::endl;
115 cout << "AVAILABLE FEATURES:" << std::endl;
116 cout << " supported: ";
117 ceph::features::mon::get_supported().print_with_value(cout);
118 cout << std::endl;
119 cout << " persistent: ";
120 ceph::features::mon::get_persistent().print_with_value(cout);
121 cout << std::endl;
122 } else if (f.type == feature_op_t::type_t::PARSEABLE) {
123
124 cout << "monmap:persistent:";
125 m.persistent_features.print_with_value(cout);
126 cout << std::endl;
127 cout << "monmap:optional:";
128 m.optional_features.print_with_value(cout);
129 cout << std::endl;
130 cout << "monmap:required:";
131 m.get_required_features().print_with_value(cout);
132 cout << std::endl;
133 cout << "available:supported:";
134 ceph::features::mon::get_supported().print_with_value(cout);
135 cout << std::endl;
136 cout << "available:persistent:";
137 ceph::features::mon::get_persistent().print_with_value(cout);
138 cout << std::endl;
139 }
140}
141
142bool handle_features(list<feature_op_t>& lst, MonMap &m)
143{
144 if (lst.empty())
145 return false;
146
147 bool modified = false;
148
149 for (auto &f : lst) {
150 if (f.op == feature_op_t::op_t::OP_LIST) {
151 features_list(f, m);
152 } else if (f.op == feature_op_t::op_t::OP_SET ||
153 f.op == feature_op_t::op_t::OP_UNSET) {
154
155 modified = true;
156
157 mon_feature_t &target =
158 ( f.type == feature_op_t::type_t::OPTIONAL ?
159 m.optional_features : m.persistent_features );
160
161 if (f.op == feature_op_t::op_t::OP_SET) {
162 target.set_feature(f.feature);
163 } else {
164 target.unset_feature(f.feature);
165 }
166 } else {
11fdf7f2 167 cerr << "unknown feature operation type '" << f.op << "'" << std::endl;
7c673cae
FG
168 }
169 }
170 return modified;
171}
172
173int main(int argc, const char **argv)
174{
175 vector<const char*> args;
176 argv_to_vec(argc, argv, args);
11fdf7f2
TL
177 if (args.empty()) {
178 cerr << argv[0] << ": -h or --help for usage" << std::endl;
179 exit(1);
180 }
181 if (ceph_argparse_need_usage(args)) {
182 usage();
183 exit(0);
184 }
7c673cae
FG
185
186 const char *me = argv[0];
187
188 std::string fn;
189 bool print = false;
190 bool create = false;
11fdf7f2 191 bool enable_all_features = false;
7c673cae
FG
192 bool clobber = false;
193 bool modified = false;
194 bool show_features = false;
195 bool generate = false;
196 bool filter = false;
11fdf7f2 197 int min_mon_release = -1;
7c673cae 198 map<string,entity_addr_t> add;
11fdf7f2 199 map<string,entity_addrvec_t> addv;
7c673cae
FG
200 list<string> rm;
201 list<feature_op_t> features;
202
203 auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT,
204 CODE_ENVIRONMENT_UTILITY,
205 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE);
206 common_init_finish(g_ceph_context);
207 std::string val;
208 for (std::vector<const char*>::iterator i = args.begin(); i != args.end(); ) {
209 if (ceph_argparse_double_dash(args, i)) {
210 break;
7c673cae
FG
211 } else if (ceph_argparse_flag(args, i, "-p", "--print", (char*)NULL)) {
212 print = true;
213 } else if (ceph_argparse_flag(args, i, "--create", (char*)NULL)) {
214 create = true;
11fdf7f2
TL
215 } else if (ceph_argparse_flag(args, i, "--enable-all-features", (char*)NULL)) {
216 enable_all_features = true;
7c673cae
FG
217 } else if (ceph_argparse_flag(args, i, "--clobber", (char*)NULL)) {
218 clobber = true;
219 } else if (ceph_argparse_flag(args, i, "--generate", (char*)NULL)) {
220 generate = true;
221 } else if (ceph_argparse_flag(args, i, "--set-initial-members", (char*)NULL)) {
222 filter = true;
11fdf7f2
TL
223 } else if (ceph_argparse_witharg(args, i, &val, "--set-min-mon-release",
224 (char*)NULL)) {
225 min_mon_release = atoi(val.c_str());
7c673cae
FG
226 } else if (ceph_argparse_flag(args, i, "--add", (char*)NULL)) {
227 string name = *i;
228 i = args.erase(i);
229 if (i == args.end())
11fdf7f2 230 helpful_exit();
7c673cae
FG
231 entity_addr_t addr;
232 if (!addr.parse(*i)) {
233 cerr << me << ": invalid ip:port '" << *i << "'" << std::endl;
234 return -1;
235 }
7c673cae
FG
236 add[name] = addr;
237 modified = true;
238 i = args.erase(i);
11fdf7f2
TL
239 } else if (ceph_argparse_flag(args, i, "--addv", (char*)NULL)) {
240 string name = *i;
241 i = args.erase(i);
242 if (i == args.end())
243 helpful_exit();
244 entity_addrvec_t addrs;
245 if (!addrs.parse(*i)) {
246 cerr << me << ": invalid ip:port '" << *i << "'" << std::endl;
247 return -1;
248 }
249 addv[name] = addrs;
250 modified = true;
251 i = args.erase(i);
7c673cae
FG
252 } else if (ceph_argparse_witharg(args, i, &val, "--rm", (char*)NULL)) {
253 rm.push_back(val);
254 modified = true;
255 } else if (ceph_argparse_flag(args, i, "--feature-list", (char*)NULL)) {
256 string format = *i;
257 if (format == "plain" || format == "parseable") {
258 i = args.erase(i);
259 } else {
260 format = "plain";
261 }
262
263 feature_op_t f(feature_op_t::op_t::OP_LIST,
264 feature_op_t::type_t::PLAIN);
265
266 if (format == "parseable") {
267 f.type = feature_op_t::type_t::PARSEABLE;
268 } else if (format != "plain") {
269 cerr << "invalid format type for list: '" << val << "'" << std::endl;
11fdf7f2 270 helpful_exit();
7c673cae
FG
271 }
272
273 features.push_back(f);
274 show_features = true;
275 } else if (ceph_argparse_witharg(args, i, &val,
276 "--feature-set", (char*)NULL)) {
277 // parse value
278 feature_op_t f(feature_op_t::op_t::OP_SET);
279 if (!f.parse_value(val, &cerr)) {
11fdf7f2 280 helpful_exit();
7c673cae
FG
281 }
282 features.push_back(f);
283
284 } else if (ceph_argparse_witharg(args, i, &val,
285 "--feature-unset", (char*)NULL)) {
286 // parse value
287 feature_op_t f(feature_op_t::op_t::OP_UNSET);
288 if (!f.parse_value(val, &cerr)) {
11fdf7f2 289 helpful_exit();
7c673cae
FG
290 }
291 features.push_back(f);
292 } else if (ceph_argparse_flag(args, i, "--optional", (char*)NULL)) {
293 if (features.empty()) {
11fdf7f2 294 helpful_exit();
7c673cae
FG
295 }
296 features.back().set_optional();
297 } else if (ceph_argparse_flag(args, i, "--persistent", (char*)NULL)) {
298 if (features.empty()) {
11fdf7f2 299 helpful_exit();
7c673cae
FG
300 }
301 features.back().set_persistent();
302 } else {
303 ++i;
304 }
305 }
306 if (args.empty()) {
307 cerr << me << ": must specify monmap filename" << std::endl;
11fdf7f2 308 helpful_exit();
7c673cae
FG
309 }
310 else if (args.size() > 1) {
311 cerr << me << ": too many arguments" << std::endl;
11fdf7f2 312 helpful_exit();
7c673cae
FG
313 }
314 fn = args[0];
315
316 MonMap monmap;
317
318 cout << me << ": monmap file " << fn << std::endl;
319
320 int r = 0;
321 if (!(create && clobber)) {
322 try {
323 r = monmap.read(fn.c_str());
324 } catch (...) {
325 cerr << me << ": unable to read monmap file" << std::endl;
326 return -1;
327 }
328 }
329
330 if (!create && r < 0) {
331 cerr << me << ": couldn't open " << fn << ": " << cpp_strerror(r) << std::endl;
332 return -1;
333 }
334 else if (create && !clobber && r == 0) {
335 cerr << me << ": " << fn << " exists, --clobber to overwrite" << std::endl;
336 return -1;
337 }
338
339 if (create) {
340 monmap.epoch = 0;
341 monmap.created = ceph_clock_now();
342 monmap.last_changed = monmap.created;
343 srand(getpid() + time(0));
11fdf7f2 344 if (g_conf().get_val<uuid_d>("fsid").is_zero()) {
7c673cae
FG
345 monmap.generate_fsid();
346 cout << me << ": generated fsid " << monmap.fsid << std::endl;
347 }
348 modified = true;
349 }
11fdf7f2
TL
350 if (enable_all_features) {
351 // populate persistent features, too
352 monmap.persistent_features = ceph::features::mon::get_persistent();
353 modified = true;
354 }
7c673cae
FG
355
356 if (generate) {
11fdf7f2 357 int r = monmap.build_initial(g_ceph_context, true, cerr);
7c673cae
FG
358 if (r < 0)
359 return r;
360 }
361
11fdf7f2
TL
362 if (min_mon_release >= 0) {
363 monmap.min_mon_release = min_mon_release;
364 cout << "setting min_mon_release = " << min_mon_release << std::endl;
365 modified = true;
366 }
367
7c673cae
FG
368 if (filter) {
369 // apply initial members
370 list<string> initial_members;
11fdf7f2 371 get_str_list(g_conf()->mon_initial_members, initial_members);
7c673cae
FG
372 if (!initial_members.empty()) {
373 cout << "initial_members " << initial_members << ", filtering seed monmap" << std::endl;
11fdf7f2 374 set<entity_addrvec_t> removed;
7c673cae 375 monmap.set_initial_members(g_ceph_context, initial_members,
11fdf7f2 376 string(), entity_addrvec_t(),
7c673cae
FG
377 &removed);
378 cout << "removed " << removed << std::endl;
379 }
380 modified = true;
381 }
382
11fdf7f2
TL
383 if (!g_conf().get_val<uuid_d>("fsid").is_zero()) {
384 monmap.fsid = g_conf().get_val<uuid_d>("fsid");
7c673cae
FG
385 cout << me << ": set fsid to " << monmap.fsid << std::endl;
386 modified = true;
387 }
388
11fdf7f2
TL
389 for (auto& p : add) {
390 entity_addr_t addr = p.second;
391 entity_addrvec_t addrs;
392 if (monmap.contains(p.first)) {
393 cerr << me << ": map already contains mon." << p.first << std::endl;
394 helpful_exit();
395 }
396 if (addr.get_port() == 0) {
397 if (monmap.persistent_features.contains_all(
398 ceph::features::mon::FEATURE_NAUTILUS)) {
399 addr.set_type(entity_addr_t::TYPE_MSGR2);
400 addr.set_port(CEPH_MON_PORT_IANA);
401 addrs.v.push_back(addr);
402 addr.set_type(entity_addr_t::TYPE_LEGACY);
403 addr.set_port(CEPH_MON_PORT_LEGACY);
404 addrs.v.push_back(addr);
405 } else {
406 addr.set_type(entity_addr_t::TYPE_LEGACY);
407 addr.set_port(CEPH_MON_PORT_LEGACY);
408 addrs.v.push_back(addr);
409 }
410 } else if (addr.get_port() == CEPH_MON_PORT_LEGACY) {
411 addr.set_type(entity_addr_t::TYPE_LEGACY);
412 addrs.v.push_back(addr);
413 } else {
414 if (monmap.persistent_features.contains_all(
415 ceph::features::mon::FEATURE_NAUTILUS)) {
416 addr.set_type(entity_addr_t::TYPE_MSGR2);
417 }
418 addrs.v.push_back(addr);
419 }
420 if (monmap.contains(addrs)) {
421 cerr << me << ": map already contains " << addrs << std::endl;
422 helpful_exit();
7c673cae 423 }
11fdf7f2
TL
424 monmap.add(p.first, addrs);
425 }
426 for (auto& p : addv) {
427 if (monmap.contains(p.first)) {
428 cerr << me << ": map already contains mon." << p.first << std::endl;
429 helpful_exit();
430 }
431 if (monmap.contains(p.second)) {
432 cerr << me << ": map already contains " << p.second << std::endl;
433 helpful_exit();
7c673cae 434 }
11fdf7f2 435 monmap.add(p.first, p.second);
7c673cae 436 }
11fdf7f2
TL
437 for (auto& p : rm) {
438 cout << me << ": removing " << p << std::endl;
439 if (!monmap.contains(p)) {
440 cerr << me << ": map does not contain " << p << std::endl;
441 helpful_exit();
7c673cae 442 }
11fdf7f2 443 monmap.remove(p);
7c673cae
FG
444 }
445
446 if (handle_features(features, monmap)) {
447 modified = true;
448 }
449
11fdf7f2
TL
450 if (!print && !modified && !show_features) {
451 cerr << "no action specified" << std::endl;
452 helpful_exit();
453 }
7c673cae
FG
454
455 if (print)
456 monmap.print(cout);
457
458 if (modified) {
459 // write it out
460 cout << me << ": writing epoch " << monmap.epoch
461 << " to " << fn
462 << " (" << monmap.size() << " monitors)"
463 << std::endl;
464 int r = monmap.write(fn.c_str());
465 if (r < 0) {
466 cerr << "monmaptool: error writing to '" << fn << "': " << cpp_strerror(r) << std::endl;
467 return 1;
468 }
469 }
470
471
472 return 0;
473}