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