Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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 }