]> git.proxmox.com Git - ceph.git/blob - ceph/src/tools/monmaptool.cc
update sources to v12.2.4
[ceph.git] / ceph / src / tools / monmaptool.cc
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
23 using namespace std;
24
25 void usage()
26 {
27 cout << " usage: [--print] [--create [--clobber][--fsid uuid]]\n"
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"
32 << " [--feature-unset <value> [--optional|--persistent]] "
33 << "<mapfilename>"
34 << std::endl;
35 exit(1);
36 }
37
38 struct feature_op_t {
39 enum type_t {
40 PERSISTENT,
41 OPTIONAL,
42 PLAIN,
43 PARSEABLE,
44 NONE
45 };
46
47 enum op_t {
48 OP_SET,
49 OP_UNSET,
50 OP_LIST
51 };
52
53 op_t op;
54 type_t type;
55 mon_feature_t feature;
56
57 feature_op_t() : op(OP_LIST), type(NONE) { }
58 // default to 'persistent' feature if not specified
59 feature_op_t(op_t o) : op(o), type(PERSISTENT) { }
60 feature_op_t(op_t o, type_t t) : op(o), type(t) { }
61 feature_op_t(op_t o, type_t t, mon_feature_t &f) :
62 op(o), type(t), feature(t) { }
63
64 void set_optional() {
65 type = OPTIONAL;
66 }
67 void set_persistent() {
68 type = PERSISTENT;
69 }
70 bool parse_value(string &s, ostream *errout = NULL) {
71
72 feature = ceph::features::mon::get_feature_by_name(s);
73 if (feature != ceph::features::mon::FEATURE_NONE) {
74 return true;
75 }
76
77 // try parsing as numerical value
78 uint64_t feature_val;
79 string interr;
80 feature_val = strict_strtoll(s.c_str(), 10, &interr);
81 if (!interr.empty()) {
82 if (errout) {
83 *errout << "unknown features name '" << s
84 << "' or unable to parse value: " << interr << std::endl;
85 }
86 return false;
87 }
88 feature = mon_feature_t(feature_val);
89 return true;
90 }
91 };
92
93 void features_list(feature_op_t &f, MonMap &m)
94 {
95 if (f.type == feature_op_t::type_t::PLAIN) {
96
97 cout << "MONMAP FEATURES:" << std::endl;
98 cout << " persistent: ";
99 m.persistent_features.print_with_value(cout);
100 cout << std::endl;
101 cout << " optional: ";
102 m.optional_features.print_with_value(cout);
103 cout << std::endl;
104 cout << " required: ";
105 m.get_required_features().print_with_value(cout);
106 cout << std::endl;
107
108 cout << std::endl;
109 cout << "AVAILABLE FEATURES:" << std::endl;
110 cout << " supported: ";
111 ceph::features::mon::get_supported().print_with_value(cout);
112 cout << std::endl;
113 cout << " persistent: ";
114 ceph::features::mon::get_persistent().print_with_value(cout);
115 cout << std::endl;
116 } else if (f.type == feature_op_t::type_t::PARSEABLE) {
117
118 cout << "monmap:persistent:";
119 m.persistent_features.print_with_value(cout);
120 cout << std::endl;
121 cout << "monmap:optional:";
122 m.optional_features.print_with_value(cout);
123 cout << std::endl;
124 cout << "monmap:required:";
125 m.get_required_features().print_with_value(cout);
126 cout << std::endl;
127 cout << "available:supported:";
128 ceph::features::mon::get_supported().print_with_value(cout);
129 cout << std::endl;
130 cout << "available:persistent:";
131 ceph::features::mon::get_persistent().print_with_value(cout);
132 cout << std::endl;
133 }
134 }
135
136 bool handle_features(list<feature_op_t>& lst, MonMap &m)
137 {
138 if (lst.empty())
139 return false;
140
141 bool modified = false;
142
143 for (auto &f : lst) {
144 if (f.op == feature_op_t::op_t::OP_LIST) {
145 features_list(f, m);
146 } else if (f.op == feature_op_t::op_t::OP_SET ||
147 f.op == feature_op_t::op_t::OP_UNSET) {
148
149 modified = true;
150
151 mon_feature_t &target =
152 ( f.type == feature_op_t::type_t::OPTIONAL ?
153 m.optional_features : m.persistent_features );
154
155 if (f.op == feature_op_t::op_t::OP_SET) {
156 target.set_feature(f.feature);
157 } else {
158 target.unset_feature(f.feature);
159 }
160 } else {
161 cerr << "unknow feature operation type '" << f.op << "'" << std::endl;
162 }
163 }
164 return modified;
165 }
166
167 int main(int argc, const char **argv)
168 {
169 vector<const char*> args;
170 argv_to_vec(argc, argv, args);
171
172 const char *me = argv[0];
173
174 std::string fn;
175 bool print = false;
176 bool create = false;
177 bool clobber = false;
178 bool modified = false;
179 bool show_features = false;
180 bool generate = false;
181 bool filter = false;
182 map<string,entity_addr_t> add;
183 list<string> rm;
184 list<feature_op_t> features;
185
186 auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT,
187 CODE_ENVIRONMENT_UTILITY,
188 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE);
189 common_init_finish(g_ceph_context);
190 std::string val;
191 for (std::vector<const char*>::iterator i = args.begin(); i != args.end(); ) {
192 if (ceph_argparse_double_dash(args, i)) {
193 break;
194 } else if (ceph_argparse_flag(args, i, "-h", "--help", (char*)NULL)) {
195 usage();
196 } else if (ceph_argparse_flag(args, i, "-p", "--print", (char*)NULL)) {
197 print = true;
198 } else if (ceph_argparse_flag(args, i, "--create", (char*)NULL)) {
199 create = true;
200 } else if (ceph_argparse_flag(args, i, "--clobber", (char*)NULL)) {
201 clobber = true;
202 } else if (ceph_argparse_flag(args, i, "--generate", (char*)NULL)) {
203 generate = true;
204 } else if (ceph_argparse_flag(args, i, "--set-initial-members", (char*)NULL)) {
205 filter = true;
206 } else if (ceph_argparse_flag(args, i, "--add", (char*)NULL)) {
207 string name = *i;
208 i = args.erase(i);
209 if (i == args.end())
210 usage();
211 entity_addr_t addr;
212 if (!addr.parse(*i)) {
213 cerr << me << ": invalid ip:port '" << *i << "'" << std::endl;
214 return -1;
215 }
216 if (addr.get_port() == 0)
217 addr.set_port(CEPH_MON_PORT);
218 add[name] = addr;
219 modified = true;
220 i = args.erase(i);
221 } else if (ceph_argparse_witharg(args, i, &val, "--rm", (char*)NULL)) {
222 rm.push_back(val);
223 modified = true;
224 } else if (ceph_argparse_flag(args, i, "--feature-list", (char*)NULL)) {
225 string format = *i;
226 if (format == "plain" || format == "parseable") {
227 i = args.erase(i);
228 } else {
229 format = "plain";
230 }
231
232 feature_op_t f(feature_op_t::op_t::OP_LIST,
233 feature_op_t::type_t::PLAIN);
234
235 if (format == "parseable") {
236 f.type = feature_op_t::type_t::PARSEABLE;
237 } else if (format != "plain") {
238 cerr << "invalid format type for list: '" << val << "'" << std::endl;
239 usage();
240 }
241
242 features.push_back(f);
243 show_features = true;
244 } else if (ceph_argparse_witharg(args, i, &val,
245 "--feature-set", (char*)NULL)) {
246 // parse value
247 feature_op_t f(feature_op_t::op_t::OP_SET);
248 if (!f.parse_value(val, &cerr)) {
249 usage();
250 }
251 features.push_back(f);
252
253 } else if (ceph_argparse_witharg(args, i, &val,
254 "--feature-unset", (char*)NULL)) {
255 // parse value
256 feature_op_t f(feature_op_t::op_t::OP_UNSET);
257 if (!f.parse_value(val, &cerr)) {
258 usage();
259 }
260 features.push_back(f);
261 } else if (ceph_argparse_flag(args, i, "--optional", (char*)NULL)) {
262 if (features.empty()) {
263 usage();
264 }
265 features.back().set_optional();
266 } else if (ceph_argparse_flag(args, i, "--persistent", (char*)NULL)) {
267 if (features.empty()) {
268 usage();
269 }
270 features.back().set_persistent();
271 } else {
272 ++i;
273 }
274 }
275 if (args.empty()) {
276 cerr << me << ": must specify monmap filename" << std::endl;
277 usage();
278 }
279 else if (args.size() > 1) {
280 cerr << me << ": too many arguments" << std::endl;
281 usage();
282 }
283 fn = args[0];
284
285 MonMap monmap;
286
287 cout << me << ": monmap file " << fn << std::endl;
288
289 int r = 0;
290 if (!(create && clobber)) {
291 try {
292 r = monmap.read(fn.c_str());
293 } catch (...) {
294 cerr << me << ": unable to read monmap file" << std::endl;
295 return -1;
296 }
297 }
298
299 if (!create && r < 0) {
300 cerr << me << ": couldn't open " << fn << ": " << cpp_strerror(r) << std::endl;
301 return -1;
302 }
303 else if (create && !clobber && r == 0) {
304 cerr << me << ": " << fn << " exists, --clobber to overwrite" << std::endl;
305 return -1;
306 }
307
308 if (create) {
309 monmap.epoch = 0;
310 monmap.created = ceph_clock_now();
311 monmap.last_changed = monmap.created;
312 srand(getpid() + time(0));
313 if (g_conf->get_val<uuid_d>("fsid").is_zero()) {
314 monmap.generate_fsid();
315 cout << me << ": generated fsid " << monmap.fsid << std::endl;
316 }
317 modified = true;
318 }
319
320 if (generate) {
321 int r = monmap.build_initial(g_ceph_context, cerr);
322 if (r < 0)
323 return r;
324 }
325
326 if (filter) {
327 // apply initial members
328 list<string> initial_members;
329 get_str_list(g_conf->mon_initial_members, initial_members);
330 if (!initial_members.empty()) {
331 cout << "initial_members " << initial_members << ", filtering seed monmap" << std::endl;
332 set<entity_addr_t> removed;
333 monmap.set_initial_members(g_ceph_context, initial_members,
334 string(), entity_addr_t(),
335 &removed);
336 cout << "removed " << removed << std::endl;
337 }
338 modified = true;
339 }
340
341 if (!g_conf->get_val<uuid_d>("fsid").is_zero()) {
342 monmap.fsid = g_conf->get_val<uuid_d>("fsid");
343 cout << me << ": set fsid to " << monmap.fsid << std::endl;
344 modified = true;
345 }
346
347 for (map<string,entity_addr_t>::iterator p = add.begin(); p != add.end(); ++p) {
348 if (monmap.contains(p->first)) {
349 cerr << me << ": map already contains mon." << p->first << std::endl;
350 usage();
351 }
352 if (monmap.contains(p->second)) {
353 cerr << me << ": map already contains " << p->second << std::endl;
354 usage();
355 }
356 monmap.add(p->first, p->second);
357 }
358 for (list<string>::iterator p = rm.begin(); p != rm.end(); ++p) {
359 cout << me << ": removing " << *p << std::endl;
360 if (!monmap.contains(*p)) {
361 cerr << me << ": map does not contain " << *p << std::endl;
362 usage();
363 }
364 monmap.remove(*p);
365 }
366
367 if (handle_features(features, monmap)) {
368 modified = true;
369 }
370
371 if (!print && !modified && !show_features)
372 usage();
373
374 if (print)
375 monmap.print(cout);
376
377 if (modified) {
378 // write it out
379 cout << me << ": writing epoch " << monmap.epoch
380 << " to " << fn
381 << " (" << monmap.size() << " monitors)"
382 << std::endl;
383 int r = monmap.write(fn.c_str());
384 if (r < 0) {
385 cerr << "monmaptool: error writing to '" << fn << "': " << cpp_strerror(r) << std::endl;
386 return 1;
387 }
388 }
389
390
391 return 0;
392 }