]>
Commit | Line | Data |
---|---|---|
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 | ||
15 | #ifndef CEPH_MONMAP_H | |
16 | #define CEPH_MONMAP_H | |
17 | ||
11fdf7f2 TL |
18 | #ifdef WITH_SEASTAR |
19 | #include <seastar/core/future.hh> | |
20 | #endif | |
7c673cae | 21 | |
11fdf7f2 TL |
22 | #include "common/config_fwd.h" |
23 | ||
24 | #include "include/err.h" | |
7c673cae | 25 | #include "include/types.h" |
11fdf7f2 | 26 | |
7c673cae | 27 | #include "mon/mon_types.h" |
11fdf7f2 TL |
28 | #include "msg/Message.h" |
29 | ||
30 | ||
31 | #ifdef WITH_SEASTAR | |
32 | namespace ceph::common { | |
33 | class ConfigProxy; | |
34 | } | |
35 | #endif | |
7c673cae FG |
36 | |
37 | namespace ceph { | |
38 | class Formatter; | |
39 | } | |
40 | ||
41 | struct mon_info_t { | |
42 | /** | |
43 | * monitor name | |
44 | * | |
45 | * i.e., 'foo' in 'mon.foo' | |
46 | */ | |
47 | string name; | |
48 | /** | |
11fdf7f2 | 49 | * monitor's public address(es) |
7c673cae | 50 | * |
11fdf7f2 TL |
51 | * public facing address(es), used to communicate with all clients |
52 | * and with other monitors. | |
7c673cae | 53 | */ |
11fdf7f2 | 54 | entity_addrvec_t public_addrs; |
224ce89b WB |
55 | /** |
56 | * the priority of the mon, the lower value the more preferred | |
57 | */ | |
58 | uint16_t priority{0}; | |
7c673cae | 59 | |
11fdf7f2 | 60 | // <REMOVE ME> |
224ce89b | 61 | mon_info_t(const string& n, const entity_addr_t& p_addr, uint16_t p) |
11fdf7f2 TL |
62 | : name(n), public_addrs(p_addr), priority(p) |
63 | {} | |
64 | // </REMOVE ME> | |
65 | ||
66 | mon_info_t(const string& n, const entity_addrvec_t& p_addrs, uint16_t p) | |
67 | : name(n), public_addrs(p_addrs), priority(p) | |
224ce89b | 68 | {} |
11fdf7f2 TL |
69 | mon_info_t(const string &n, const entity_addrvec_t& p_addrs) |
70 | : name(n), public_addrs(p_addrs) | |
7c673cae FG |
71 | { } |
72 | ||
73 | mon_info_t() { } | |
74 | ||
75 | ||
76 | void encode(bufferlist& bl, uint64_t features) const; | |
11fdf7f2 | 77 | void decode(bufferlist::const_iterator& p); |
7c673cae FG |
78 | void print(ostream& out) const; |
79 | }; | |
80 | WRITE_CLASS_ENCODER_FEATURES(mon_info_t) | |
81 | ||
82 | inline ostream& operator<<(ostream& out, const mon_info_t& mon) { | |
83 | mon.print(out); | |
84 | return out; | |
85 | } | |
86 | ||
87 | class MonMap { | |
88 | public: | |
89 | epoch_t epoch; // what epoch/version of the monmap | |
90 | uuid_d fsid; | |
91 | utime_t last_changed; | |
92 | utime_t created; | |
93 | ||
94 | map<string, mon_info_t> mon_info; | |
95 | map<entity_addr_t, string> addr_mons; | |
96 | ||
97 | vector<string> ranks; | |
98 | ||
99 | /** | |
100 | * Persistent Features are all those features that once set on a | |
101 | * monmap cannot, and should not, be removed. These will define the | |
102 | * non-negotiable features that a given monitor must support to | |
103 | * properly operate in a given quorum. | |
104 | * | |
105 | * Should be reserved for features that we really want to make sure | |
106 | * are sticky, and are important enough to tolerate not being able | |
107 | * to downgrade a monitor. | |
108 | */ | |
109 | mon_feature_t persistent_features; | |
110 | /** | |
111 | * Optional Features are all those features that can be enabled or | |
112 | * disabled following a given criteria -- e.g., user-mandated via the | |
113 | * cli --, and act much like indicators of what the cluster currently | |
114 | * supports. | |
115 | * | |
116 | * They are by no means "optional" in the sense that monitors can | |
117 | * ignore them. Just that they are not persistent. | |
118 | */ | |
119 | mon_feature_t optional_features; | |
120 | ||
121 | /** | |
122 | * Returns the set of features required by this monmap. | |
123 | * | |
124 | * The features required by this monmap is the union of all the | |
125 | * currently set persistent features and the currently set optional | |
126 | * features. | |
127 | * | |
128 | * @returns the set of features required by this monmap | |
129 | */ | |
130 | mon_feature_t get_required_features() const { | |
131 | return (persistent_features | optional_features); | |
132 | } | |
133 | ||
11fdf7f2 TL |
134 | // upgrade gate |
135 | uint8_t min_mon_release = 0; | |
136 | ||
137 | void _add_ambiguous_addr(const string& name, | |
138 | entity_addr_t addr, | |
139 | int priority, | |
140 | bool for_mkfs=false); | |
141 | ||
7c673cae | 142 | public: |
11fdf7f2 TL |
143 | void calc_legacy_ranks(); |
144 | void calc_addr_mons() { | |
145 | // populate addr_mons | |
146 | addr_mons.clear(); | |
147 | for (auto& p : mon_info) { | |
148 | for (auto& a : p.second.public_addrs.v) { | |
149 | addr_mons[a] = p.first; | |
150 | } | |
151 | } | |
152 | } | |
7c673cae FG |
153 | |
154 | MonMap() | |
155 | : epoch(0) { | |
7c673cae FG |
156 | } |
157 | ||
158 | uuid_d& get_fsid() { return fsid; } | |
159 | ||
160 | unsigned size() const { | |
161 | return mon_info.size(); | |
162 | } | |
163 | ||
11fdf7f2 TL |
164 | unsigned min_quorum_size(unsigned total_mons=0) const { |
165 | if (total_mons == 0) { | |
166 | total_mons = size(); | |
167 | } | |
168 | return total_mons / 2 + 1; | |
169 | } | |
170 | ||
7c673cae FG |
171 | epoch_t get_epoch() const { return epoch; } |
172 | void set_epoch(epoch_t e) { epoch = e; } | |
173 | ||
174 | /** | |
175 | * Obtain list of public facing addresses | |
176 | * | |
177 | * @param ls list to populate with the monitors' addresses | |
178 | */ | |
179 | void list_addrs(list<entity_addr_t>& ls) const { | |
11fdf7f2 TL |
180 | for (auto& i : mon_info) { |
181 | for (auto& j : i.second.public_addrs.v) { | |
182 | ls.push_back(j); | |
183 | } | |
7c673cae FG |
184 | } |
185 | } | |
186 | ||
224ce89b WB |
187 | /** |
188 | * Add new monitor to the monmap | |
189 | * | |
190 | * @param m monitor info of the new monitor | |
191 | */ | |
11fdf7f2 TL |
192 | void add(const mon_info_t& m) { |
193 | ceph_assert(mon_info.count(m.name) == 0); | |
194 | for (auto& a : m.public_addrs.v) { | |
195 | ceph_assert(addr_mons.count(a) == 0); | |
196 | } | |
197 | mon_info[m.name] = m; | |
198 | if (get_required_features().contains_all( | |
199 | ceph::features::mon::FEATURE_NAUTILUS)) { | |
200 | ranks.push_back(m.name); | |
201 | ceph_assert(ranks.size() == mon_info.size()); | |
202 | } else { | |
203 | calc_legacy_ranks(); | |
204 | } | |
205 | calc_addr_mons(); | |
224ce89b WB |
206 | } |
207 | ||
7c673cae FG |
208 | /** |
209 | * Add new monitor to the monmap | |
210 | * | |
211 | * @param name Monitor name (i.e., 'foo' in 'mon.foo') | |
212 | * @param addr Monitor's public address | |
213 | */ | |
11fdf7f2 TL |
214 | void add(const string &name, const entity_addrvec_t &addrv, |
215 | int priority=0) { | |
216 | add(mon_info_t(name, addrv, priority)); | |
7c673cae | 217 | } |
224ce89b | 218 | |
7c673cae FG |
219 | /** |
220 | * Remove monitor from the monmap | |
221 | * | |
222 | * @param name Monitor name (i.e., 'foo' in 'mon.foo') | |
223 | */ | |
224 | void remove(const string &name) { | |
11fdf7f2 | 225 | ceph_assert(mon_info.count(name)); |
7c673cae | 226 | mon_info.erase(name); |
11fdf7f2 TL |
227 | ceph_assert(mon_info.count(name) == 0); |
228 | if (get_required_features().contains_all( | |
229 | ceph::features::mon::FEATURE_NAUTILUS)) { | |
230 | ranks.erase(std::find(ranks.begin(), ranks.end(), name)); | |
231 | ceph_assert(ranks.size() == mon_info.size()); | |
232 | } else { | |
233 | calc_legacy_ranks(); | |
234 | } | |
235 | calc_addr_mons(); | |
7c673cae FG |
236 | } |
237 | ||
238 | /** | |
239 | * Rename monitor from @p oldname to @p newname | |
240 | * | |
241 | * @param oldname monitor's current name (i.e., 'foo' in 'mon.foo') | |
242 | * @param newname monitor's new name (i.e., 'bar' in 'mon.bar') | |
243 | */ | |
244 | void rename(string oldname, string newname) { | |
11fdf7f2 TL |
245 | ceph_assert(contains(oldname)); |
246 | ceph_assert(!contains(newname)); | |
7c673cae FG |
247 | mon_info[newname] = mon_info[oldname]; |
248 | mon_info.erase(oldname); | |
249 | mon_info[newname].name = newname; | |
11fdf7f2 TL |
250 | if (get_required_features().contains_all( |
251 | ceph::features::mon::FEATURE_NAUTILUS)) { | |
252 | *std::find(ranks.begin(), ranks.end(), oldname) = newname; | |
253 | ceph_assert(ranks.size() == mon_info.size()); | |
254 | } else { | |
255 | calc_legacy_ranks(); | |
256 | } | |
257 | calc_addr_mons(); | |
258 | } | |
259 | ||
260 | int set_rank(const string& name, int rank) { | |
261 | int oldrank = get_rank(name); | |
262 | if (oldrank < 0) { | |
263 | return -ENOENT; | |
264 | } | |
265 | if (rank < 0 || rank >= (int)ranks.size()) { | |
266 | return -EINVAL; | |
267 | } | |
268 | if (oldrank != rank) { | |
269 | ranks.erase(ranks.begin() + oldrank); | |
270 | ranks.insert(ranks.begin() + rank, name); | |
271 | } | |
272 | return 0; | |
7c673cae FG |
273 | } |
274 | ||
275 | bool contains(const string& name) const { | |
276 | return mon_info.count(name); | |
277 | } | |
278 | ||
279 | /** | |
280 | * Check if monmap contains a monitor with address @p a | |
281 | * | |
282 | * @note checks for all addresses a monitor may have, public or otherwise. | |
283 | * | |
284 | * @param a monitor address | |
285 | * @returns true if monmap contains a monitor with address @p; | |
286 | * false otherwise. | |
287 | */ | |
11fdf7f2 TL |
288 | bool contains(const entity_addr_t &a, string *name=nullptr) const { |
289 | for (auto& i : mon_info) { | |
290 | for (auto& j : i.second.public_addrs.v) { | |
291 | if (j == a) { | |
292 | if (name) { | |
293 | *name = i.first; | |
294 | } | |
295 | return true; | |
296 | } | |
297 | } | |
298 | } | |
299 | return false; | |
300 | } | |
301 | bool contains(const entity_addrvec_t &av, string *name=nullptr) const { | |
302 | for (auto& i : mon_info) { | |
303 | for (auto& j : i.second.public_addrs.v) { | |
304 | for (auto& k : av.v) { | |
305 | if (j == k) { | |
306 | if (name) { | |
307 | *name = i.first; | |
308 | } | |
309 | return true; | |
310 | } | |
311 | } | |
312 | } | |
7c673cae FG |
313 | } |
314 | return false; | |
315 | } | |
316 | ||
317 | string get_name(unsigned n) const { | |
11fdf7f2 | 318 | ceph_assert(n < ranks.size()); |
7c673cae FG |
319 | return ranks[n]; |
320 | } | |
321 | string get_name(const entity_addr_t& a) const { | |
322 | map<entity_addr_t,string>::const_iterator p = addr_mons.find(a); | |
323 | if (p == addr_mons.end()) | |
324 | return string(); | |
325 | else | |
326 | return p->second; | |
327 | } | |
11fdf7f2 TL |
328 | string get_name(const entity_addrvec_t& av) const { |
329 | for (auto& i : av.v) { | |
330 | map<entity_addr_t,string>::const_iterator p = addr_mons.find(i); | |
331 | if (p != addr_mons.end()) | |
332 | return p->second; | |
333 | } | |
334 | return string(); | |
335 | } | |
7c673cae | 336 | |
11fdf7f2 TL |
337 | int get_rank(const string& n) const { |
338 | if (auto found = std::find(ranks.begin(), ranks.end(), n); | |
339 | found != ranks.end()) { | |
340 | return std::distance(ranks.begin(), found); | |
341 | } else { | |
342 | return -1; | |
343 | } | |
7c673cae | 344 | } |
11fdf7f2 | 345 | int get_rank(const entity_addr_t& a) const { |
7c673cae | 346 | string n = get_name(a); |
11fdf7f2 TL |
347 | if (!n.empty()) { |
348 | return get_rank(n); | |
349 | } | |
350 | return -1; | |
351 | } | |
352 | int get_rank(const entity_addrvec_t& av) const { | |
353 | string n = get_name(av); | |
354 | if (!n.empty()) { | |
355 | return get_rank(n); | |
356 | } | |
7c673cae FG |
357 | return -1; |
358 | } | |
359 | bool get_addr_name(const entity_addr_t& a, string& name) { | |
360 | if (addr_mons.count(a) == 0) | |
361 | return false; | |
362 | name = addr_mons[a]; | |
363 | return true; | |
364 | } | |
365 | ||
11fdf7f2 TL |
366 | const entity_addrvec_t& get_addrs(const string& n) const { |
367 | ceph_assert(mon_info.count(n)); | |
7c673cae | 368 | map<string,mon_info_t>::const_iterator p = mon_info.find(n); |
11fdf7f2 | 369 | return p->second.public_addrs; |
7c673cae | 370 | } |
11fdf7f2 TL |
371 | const entity_addrvec_t& get_addrs(unsigned m) const { |
372 | ceph_assert(m < ranks.size()); | |
373 | return get_addrs(ranks[m]); | |
7c673cae | 374 | } |
11fdf7f2 TL |
375 | void set_addrvec(const string& n, const entity_addrvec_t& a) { |
376 | ceph_assert(mon_info.count(n)); | |
377 | mon_info[n].public_addrs = a; | |
378 | calc_addr_mons(); | |
7c673cae FG |
379 | } |
380 | ||
381 | void encode(bufferlist& blist, uint64_t con_features) const; | |
382 | void decode(bufferlist& blist) { | |
11fdf7f2 | 383 | auto p = std::cbegin(blist); |
7c673cae FG |
384 | decode(p); |
385 | } | |
11fdf7f2 | 386 | void decode(bufferlist::const_iterator& p); |
7c673cae FG |
387 | |
388 | void generate_fsid() { | |
389 | fsid.generate_random(); | |
390 | } | |
391 | ||
392 | // read from/write to a file | |
393 | int write(const char *fn); | |
394 | int read(const char *fn); | |
395 | ||
396 | /** | |
397 | * build an initial bootstrap monmap from conf | |
398 | * | |
399 | * Build an initial bootstrap monmap from the config. This will | |
400 | * try, in this order: | |
401 | * | |
402 | * 1 monmap -- an explicitly provided monmap | |
403 | * 2 mon_host -- list of monitors | |
404 | * 3 config [mon.*] sections, and 'mon addr' fields in those sections | |
405 | * | |
406 | * @param cct context (and associated config) | |
407 | * @param errout ostream to send error messages too | |
408 | */ | |
11fdf7f2 TL |
409 | #ifdef WITH_SEASTAR |
410 | seastar::future<> build_initial(const ceph::common::ConfigProxy& conf, bool for_mkfs); | |
411 | #else | |
412 | int build_initial(CephContext *cct, bool for_mkfs, ostream& errout); | |
413 | #endif | |
7c673cae FG |
414 | /** |
415 | * filter monmap given a set of initial members. | |
416 | * | |
417 | * Remove mons that aren't in the initial_members list. Add missing | |
418 | * mons and give them dummy IPs (blank IPv4, with a non-zero | |
419 | * nonce). If the name matches my_name, then my_addr will be used in | |
420 | * place of a dummy addr. | |
421 | * | |
422 | * @param initial_members list of initial member names | |
423 | * @param my_name name of self, can be blank | |
424 | * @param my_addr my addr | |
425 | * @param removed optional pointer to set to insert removed mon addrs to | |
426 | */ | |
427 | void set_initial_members(CephContext *cct, | |
428 | list<std::string>& initial_members, | |
11fdf7f2 TL |
429 | string my_name, |
430 | const entity_addrvec_t& my_addrs, | |
431 | set<entity_addrvec_t> *removed); | |
7c673cae FG |
432 | |
433 | void print(ostream& out) const; | |
434 | void print_summary(ostream& out) const; | |
435 | void dump(ceph::Formatter *f) const; | |
436 | ||
437 | static void generate_test_instances(list<MonMap*>& o); | |
11fdf7f2 TL |
438 | protected: |
439 | /** | |
440 | * build a monmap from a list of ips | |
441 | * | |
442 | * Give mons dummy names. | |
443 | * | |
444 | * @param hosts list of ips, space or comma separated | |
445 | * @param prefix prefix to prepend to generated mon names | |
446 | * @return 0 for success, -errno on error | |
447 | */ | |
448 | int init_with_ips(const std::string& ips, | |
449 | bool for_mkfs, | |
450 | const std::string &prefix); | |
451 | /** | |
452 | * build a monmap from a list of hostnames | |
453 | * | |
454 | * Give mons dummy names. | |
455 | * | |
456 | * @param hosts list of ips, space or comma separated | |
457 | * @param prefix prefix to prepend to generated mon names | |
458 | * @return 0 for success, -errno on error | |
459 | */ | |
460 | int init_with_hosts(const std::string& hostlist, | |
461 | bool for_mkfs, | |
462 | const std::string& prefix); | |
463 | int init_with_config_file(const ConfigProxy& conf, std::ostream& errout); | |
464 | #if WITH_SEASTAR | |
465 | seastar::future<> read_monmap(const std::string& monmap); | |
466 | /// try to build monmap with different settings, like | |
467 | /// mon_host, mon* sections, and mon_dns_srv_name | |
468 | seastar::future<> build_monmap(const ceph::common::ConfigProxy& conf, bool for_mkfs); | |
469 | /// initialize monmap by resolving given service name | |
470 | seastar::future<> init_with_dns_srv(bool for_mkfs, const std::string& name); | |
471 | #else | |
472 | /// read from encoded monmap file | |
473 | int init_with_monmap(const std::string& monmap, std::ostream& errout); | |
474 | int init_with_dns_srv(CephContext* cct, std::string srv_name, bool for_mkfs, | |
475 | std::ostream& errout); | |
476 | #endif | |
7c673cae FG |
477 | }; |
478 | WRITE_CLASS_ENCODER_FEATURES(MonMap) | |
479 | ||
480 | inline ostream& operator<<(ostream &out, const MonMap &m) { | |
481 | m.print_summary(out); | |
482 | return out; | |
483 | } | |
484 | ||
485 | #endif |