1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
13 #include <seastar/core/fstream.hh>
14 #include <seastar/core/reactor.hh>
15 #include <seastar/net/dns.hh>
16 #include "crimson/common/config_proxy.h"
19 #include "common/Formatter.h"
21 #include "include/ceph_features.h"
22 #include "include/addr_parsing.h"
23 #include "common/ceph_argparse.h"
24 #include "common/dns_resolve.h"
25 #include "common/errno.h"
26 #include "common/dout.h"
27 #include "common/Clock.h"
28 #include "mon/health_check.h"
33 using std::ostringstream
;
38 using ceph::DNSResolver
;
39 using ceph::Formatter
;
43 seastar::logger
& logger()
45 return crimson::get_logger(ceph_subsys_monc
);
50 void mon_info_t::encode(ceph::buffer::list
& bl
, uint64_t features
) const
54 if (!crush_loc
.empty()) {
55 // we added crush_loc in version 5, but need to let old clients decode it
56 // so just leave the min_v at version 1. Monitors are protected
57 // from misunderstandings about location because setting it is blocked
61 if (!HAVE_FEATURE(features
, SERVER_NAUTILUS
)) {
64 ENCODE_START(v
, min_v
, bl
);
67 ceph_assert(min_v
== 1);
68 auto a
= public_addrs
.legacy_addr();
69 if (a
!= entity_addr_t()) {
70 encode(a
, bl
, features
);
72 // note: we don't have a legacy addr here, so lie so that it looks
73 // like one, just so that old clients get a valid-looking map.
74 // they won't be able to talk to the v2 mons, but that's better
76 encode(public_addrs
.as_legacy_addr(), bl
, features
);
79 encode(public_addrs
, bl
, features
);
83 encode(crush_loc
, bl
);
87 void mon_info_t::decode(ceph::buffer::list::const_iterator
& p
)
91 decode(public_addrs
, p
);
104 void mon_info_t::print(ostream
& out
) const
106 out
<< "mon." << name
107 << " addrs " << public_addrs
108 << " priority " << priority
109 << " weight " << weight
110 << " crush location " << crush_loc
;
115 bool operator()(const mon_info_t
&a
, const mon_info_t
&b
) const {
116 if (a
.public_addrs
.legacy_or_front_addr() == b
.public_addrs
.legacy_or_front_addr())
117 return a
.name
< b
.name
;
118 return a
.public_addrs
.legacy_or_front_addr() < b
.public_addrs
.legacy_or_front_addr();
123 void MonMap::calc_legacy_ranks()
125 ranks
.resize(mon_info
.size());
127 // Used to order entries according to public_addr, because that's
128 // how the ranks are expected to be ordered by. We may expand this
129 // later on, according to some other criteria, by specifying a
130 // different comparator.
132 // Please note that we use a 'set' here instead of resorting to
133 // std::sort() because we need more info than that's available in
134 // the vector. The vector will thus be ordered by, e.g., public_addr
135 // while only containing the names of each individual monitor.
136 // The only way of achieving this with std::sort() would be to first
137 // insert every mon_info_t entry into a vector 'foo', std::sort() 'foo'
138 // with custom comparison functions, and then copy each invidual entry
139 // to a new vector. Unless there's a simpler way, we don't think the
140 // added complexity makes up for the additional memory usage of a 'set'.
141 set
<mon_info_t
, rank_cmp
> tmp
;
143 for (auto p
= mon_info
.begin(); p
!= mon_info
.end(); ++p
) {
144 mon_info_t
&m
= p
->second
;
148 // map the set to the actual ranks etc
150 for (auto p
= tmp
.begin(); p
!= tmp
.end(); ++p
, ++i
) {
155 void MonMap::encode(ceph::buffer::list
& blist
, uint64_t con_features
) const
157 if ((con_features
& CEPH_FEATURE_MONNAMES
) == 0) {
161 ceph::encode_raw(fsid
, blist
);
162 encode(epoch
, blist
);
163 vector
<entity_inst_t
> mon_inst(ranks
.size());
164 for (unsigned n
= 0; n
< ranks
.size(); n
++) {
165 mon_inst
[n
].name
= entity_name_t::MON(n
);
166 mon_inst
[n
].addr
= get_addrs(n
).legacy_addr();
168 encode(mon_inst
, blist
, con_features
);
169 encode(last_changed
, blist
);
170 encode(created
, blist
);
174 map
<string
,entity_addr_t
> legacy_mon_addr
;
175 if (!HAVE_FEATURE(con_features
, MONENC
) ||
176 !HAVE_FEATURE(con_features
, SERVER_NAUTILUS
)) {
177 for (auto& [name
, info
] : mon_info
) {
178 legacy_mon_addr
[name
] = info
.public_addrs
.legacy_addr();
182 if (!HAVE_FEATURE(con_features
, MONENC
)) {
183 /* we keep the mon_addr map when encoding to ensure compatibility
184 * with clients and other monitors that do not yet support the 'mons'
185 * map. This map keeps its original behavior, containing a mapping of
186 * monitor id (i.e., 'foo' in 'mon.foo') to the monitor's public
187 * address -- which is obtained from the public address of each entry
193 ceph::encode_raw(fsid
, blist
);
194 encode(epoch
, blist
);
195 encode(legacy_mon_addr
, blist
, con_features
);
196 encode(last_changed
, blist
);
197 encode(created
, blist
);
201 if (!HAVE_FEATURE(con_features
, SERVER_NAUTILUS
)) {
202 ENCODE_START(5, 3, blist
);
203 ceph::encode_raw(fsid
, blist
);
204 encode(epoch
, blist
);
205 encode(legacy_mon_addr
, blist
, con_features
);
206 encode(last_changed
, blist
);
207 encode(created
, blist
);
208 encode(persistent_features
, blist
);
209 encode(optional_features
, blist
);
210 encode(mon_info
, blist
, con_features
);
211 ENCODE_FINISH(blist
);
215 ENCODE_START(9, 6, blist
);
216 ceph::encode_raw(fsid
, blist
);
217 encode(epoch
, blist
);
218 encode(last_changed
, blist
);
219 encode(created
, blist
);
220 encode(persistent_features
, blist
);
221 encode(optional_features
, blist
);
222 encode(mon_info
, blist
, con_features
);
223 encode(ranks
, blist
);
224 encode(min_mon_release
, blist
);
225 encode(removed_ranks
, blist
);
226 uint8_t t
= strategy
;
228 encode(disallowed_leaders
, blist
);
229 encode(stretch_mode_enabled
, blist
);
230 encode(tiebreaker_mon
, blist
);
231 encode(stretch_marked_down_mons
, blist
);
232 ENCODE_FINISH(blist
);
235 void MonMap::decode(ceph::buffer::list::const_iterator
& p
)
237 map
<string
,entity_addr_t
> mon_addr
;
238 DECODE_START_LEGACY_COMPAT_LEN_16(9, 3, 3, p
);
239 ceph::decode_raw(fsid
, p
);
242 vector
<entity_inst_t
> mon_inst
;
244 for (unsigned i
= 0; i
< mon_inst
.size(); i
++) {
249 mon_addr
[name
] = mon_inst
[i
].addr
;
251 } else if (struct_v
< 6) {
254 decode(last_changed
, p
);
257 decode(persistent_features
, p
);
258 decode(optional_features
, p
);
261 // generate mon_info from legacy mon_addr
262 for (auto& [name
, addr
] : mon_addr
) {
263 mon_info_t
&m
= mon_info
[name
];
265 m
.public_addrs
= entity_addrvec_t(addr
);
276 decode(min_mon_release
, p
);
278 min_mon_release
= infer_ceph_release_from_mon_features(persistent_features
);
281 decode(removed_ranks
, p
);
284 strategy
= static_cast<election_strategy
>(t
);
285 decode(disallowed_leaders
, p
);
288 decode(stretch_mode_enabled
, p
);
289 decode(tiebreaker_mon
, p
);
290 decode(stretch_marked_down_mons
, p
);
292 stretch_mode_enabled
= false;
294 stretch_marked_down_mons
.clear();
300 void MonMap::generate_test_instances(list
<MonMap
*>& o
)
302 o
.push_back(new MonMap
);
303 o
.push_back(new MonMap
);
305 o
.back()->last_changed
= utime_t(123, 456);
306 o
.back()->created
= utime_t(789, 101112);
307 o
.back()->add("one", entity_addrvec_t());
309 MonMap
*m
= new MonMap
;
312 m
->last_changed
= utime_t(123, 456);
314 entity_addrvec_t empty_addr_one
= entity_addrvec_t(entity_addr_t());
315 empty_addr_one
.v
[0].set_nonce(1);
316 m
->add("empty_addr_one", empty_addr_one
);
317 entity_addrvec_t empty_addr_two
= entity_addrvec_t(entity_addr_t());
318 empty_addr_two
.v
[0].set_nonce(2);
319 m
->add("empty_addr_two", empty_addr_two
);
321 const char *local_pub_addr_s
= "127.0.1.2";
323 const char *end_p
= local_pub_addr_s
+ strlen(local_pub_addr_s
);
324 entity_addrvec_t local_pub_addr
;
325 local_pub_addr
.parse(local_pub_addr_s
, &end_p
);
327 m
->add(mon_info_t("filled_pub_addr", entity_addrvec_t(local_pub_addr
), 1, 1));
329 m
->add("empty_addr_zero", entity_addrvec_t());
334 // read from/write to a file
335 int MonMap::write(const char *fn
)
338 ceph::buffer::list bl
;
339 encode(bl
, CEPH_FEATURES_ALL
);
341 return bl
.write_file(fn
);
344 int MonMap::read(const char *fn
)
347 ceph::buffer::list bl
;
349 int r
= bl
.read_file(fn
, &error
);
356 void MonMap::print_summary(ostream
& out
) const
358 out
<< "e" << epoch
<< ": "
359 << mon_info
.size() << " mons at {";
360 // the map that we used to print, as it was, no longer
361 // maps strings to the monitor's public address, but to
362 // mon_info_t instead. As such, print the map in a way
363 // that keeps the expected format.
364 bool has_printed
= false;
365 for (auto p
= mon_info
.begin(); p
!= mon_info
.end(); ++p
) {
368 out
<< p
->first
<< "=" << p
->second
.public_addrs
;
371 out
<< "}" << " removed_ranks: {" << removed_ranks
<< "}";
374 void MonMap::print(ostream
& out
) const
376 out
<< "epoch " << epoch
<< "\n";
377 out
<< "fsid " << fsid
<< "\n";
378 out
<< "last_changed " << last_changed
<< "\n";
379 out
<< "created " << created
<< "\n";
380 out
<< "min_mon_release " << to_integer
<unsigned>(min_mon_release
)
381 << " (" << min_mon_release
<< ")\n";
382 out
<< "election_strategy: " << strategy
<< "\n";
383 if (stretch_mode_enabled
) {
384 out
<< "stretch_mode_enabled " << stretch_mode_enabled
<< "\n";
385 out
<< "tiebreaker_mon " << tiebreaker_mon
<< "\n";
387 if (stretch_mode_enabled
||
388 !disallowed_leaders
.empty()) {
389 out
<< "disallowed_leaders " << disallowed_leaders
<< "\n";
392 for (auto p
= ranks
.begin(); p
!= ranks
.end(); ++p
) {
393 const auto &mi
= mon_info
.find(*p
);
394 ceph_assert(mi
!= mon_info
.end());
395 out
<< i
++ << ": " << mi
->second
.public_addrs
<< " mon." << *p
;
396 if (!mi
->second
.crush_loc
.empty()) {
397 out
<< "; crush_location " << mi
->second
.crush_loc
;
403 void MonMap::dump(Formatter
*f
) const
405 f
->dump_unsigned("epoch", epoch
);
406 f
->dump_stream("fsid") << fsid
;
407 last_changed
.gmtime(f
->dump_stream("modified"));
408 created
.gmtime(f
->dump_stream("created"));
409 f
->dump_unsigned("min_mon_release", to_integer
<unsigned>(min_mon_release
));
410 f
->dump_string("min_mon_release_name", to_string(min_mon_release
));
411 f
->dump_int ("election_strategy", strategy
);
412 f
->dump_stream("disallowed_leaders: ") << disallowed_leaders
;
413 f
->dump_bool("stretch_mode", stretch_mode_enabled
);
414 f
->dump_string("tiebreaker_mon", tiebreaker_mon
);
415 f
->dump_stream("removed_ranks: ") << removed_ranks
;
416 f
->open_object_section("features");
417 persistent_features
.dump(f
, "persistent");
418 optional_features
.dump(f
, "optional");
420 f
->open_array_section("mons");
422 for (auto p
= ranks
.begin(); p
!= ranks
.end(); ++p
, ++i
) {
423 f
->open_object_section("mon");
424 f
->dump_int("rank", i
);
425 f
->dump_string("name", *p
);
426 f
->dump_object("public_addrs", get_addrs(*p
));
427 // compat: make these look like pre-nautilus entity_addr_t
428 f
->dump_stream("addr") << get_addrs(*p
).get_legacy_str();
429 f
->dump_stream("public_addr") << get_addrs(*p
).get_legacy_str();
430 f
->dump_unsigned("priority", get_priority(*p
));
431 f
->dump_unsigned("weight", get_weight(*p
));
432 const auto &mi
= mon_info
.find(*p
);
433 // we don't need to assert this validity as all the get_* functions did
434 f
->dump_stream("crush_location") << mi
->second
.crush_loc
;
440 void MonMap::dump_summary(Formatter
*f
) const
442 f
->dump_unsigned("epoch", epoch
);
443 f
->dump_string("min_mon_release_name", to_string(min_mon_release
));
444 f
->dump_unsigned("num_mons", ranks
.size());
447 // an ambiguous mon addr may be legacy or may be msgr2--we aren' sure.
448 // when that happens we need to try them both (unless we can
449 // reasonably infer from the port number which it is).
450 void MonMap::_add_ambiguous_addr(const string
& name
,
456 if (addr
.get_type() != entity_addr_t::TYPE_ANY
) {
457 // a v1: or v2: prefix was specified
458 if (addr
.get_port() == 0) {
460 if (addr
.get_type() == entity_addr_t::TYPE_LEGACY
) {
461 addr
.set_port(CEPH_MON_PORT_LEGACY
);
462 } else if (addr
.get_type() == entity_addr_t::TYPE_MSGR2
) {
463 addr
.set_port(CEPH_MON_PORT_IANA
);
468 if (!contains(addr
)) {
469 add(name
, entity_addrvec_t(addr
), priority
, weight
);
472 if (!contains(addr
)) {
473 add(name
, entity_addrvec_t(addr
), priority
, weight
);
477 // no v1: or v2: prefix specified
478 if (addr
.get_port() == CEPH_MON_PORT_LEGACY
) {
479 // legacy port implies legacy addr
480 addr
.set_type(entity_addr_t::TYPE_LEGACY
);
481 if (!contains(addr
)) {
483 add(name
+ "-legacy", entity_addrvec_t(addr
), priority
, weight
);
485 add(name
, entity_addrvec_t(addr
), priority
, weight
);
488 } else if (addr
.get_port() == CEPH_MON_PORT_IANA
) {
489 // iana port implies msgr2 addr
490 addr
.set_type(entity_addr_t::TYPE_MSGR2
);
491 if (!contains(addr
)) {
492 add(name
, entity_addrvec_t(addr
), priority
, weight
);
494 } else if (addr
.get_port() == 0) {
495 // no port; include both msgr2 and legacy ports
497 addr
.set_type(entity_addr_t::TYPE_MSGR2
);
498 addr
.set_port(CEPH_MON_PORT_IANA
);
499 if (!contains(addr
)) {
500 add(name
, entity_addrvec_t(addr
), priority
, weight
);
502 addr
.set_type(entity_addr_t::TYPE_LEGACY
);
503 addr
.set_port(CEPH_MON_PORT_LEGACY
);
504 if (!contains(addr
)) {
505 add(name
+ "-legacy", entity_addrvec_t(addr
), priority
, weight
);
509 addr
.set_type(entity_addr_t::TYPE_MSGR2
);
510 addr
.set_port(CEPH_MON_PORT_IANA
);
511 av
.v
.push_back(addr
);
512 addr
.set_type(entity_addr_t::TYPE_LEGACY
);
513 addr
.set_port(CEPH_MON_PORT_LEGACY
);
514 av
.v
.push_back(addr
);
516 add(name
, av
, priority
, weight
);
520 addr
.set_type(entity_addr_t::TYPE_MSGR2
);
521 if (!contains(addr
)) {
522 add(name
, entity_addrvec_t(addr
), priority
, weight
);
525 // try legacy on same port too
526 addr
.set_type(entity_addr_t::TYPE_LEGACY
);
527 if (!contains(addr
)) {
528 add(name
+ "-legacy", entity_addrvec_t(addr
), priority
, weight
);
535 void MonMap::init_with_addrs(const std::vector
<entity_addrvec_t
>& addrs
,
537 std::string_view prefix
)
540 for (auto& addr
: addrs
) {
543 if (addr
.v
.size() == 1) {
544 _add_ambiguous_addr(name
, addr
.front(), 0, 0, for_mkfs
);
546 // they specified an addrvec, so let's assume they also specified
547 // the addr *type* and *port*. (we could possibly improve this?)
553 int MonMap::init_with_ips(const std::string
& ips
,
555 std::string_view prefix
)
557 vector
<entity_addrvec_t
> addrs
;
558 if (!parse_ip_port_vec(
560 entity_addr_t::TYPE_ANY
)) {
565 init_with_addrs(addrs
, for_mkfs
, prefix
);
569 int MonMap::init_with_hosts(const std::string
& hostlist
,
571 std::string_view prefix
)
573 // maybe they passed us a DNS-resolvable name
574 char *hosts
= resolve_addrs(hostlist
.c_str());
578 vector
<entity_addrvec_t
> addrs
;
579 bool success
= parse_ip_port_vec(
581 entity_addr_t::TYPE_ANY
);
587 init_with_addrs(addrs
, for_mkfs
, prefix
);
592 void MonMap::set_initial_members(CephContext
*cct
,
593 list
<std::string
>& initial_members
,
595 const entity_addrvec_t
& my_addrs
,
596 set
<entity_addrvec_t
> *removed
)
598 // remove non-initial members
601 string n
= get_name(i
);
602 if (std::find(initial_members
.begin(), initial_members
.end(), n
)
603 != initial_members
.end()) {
604 lgeneric_dout(cct
, 1) << " keeping " << n
<< " " << get_addrs(i
) << dendl
;
609 lgeneric_dout(cct
, 1) << " removing " << get_name(i
) << " " << get_addrs(i
)
612 removed
->insert(get_addrs(i
));
615 ceph_assert(!contains(n
));
618 // add missing initial members
619 for (auto& p
: initial_members
) {
622 lgeneric_dout(cct
, 1) << " adding self " << p
<< " " << my_addrs
627 a
.set_type(entity_addr_t::TYPE_LEGACY
);
628 a
.set_family(AF_INET
);
629 for (int n
=1; ; n
++) {
634 lgeneric_dout(cct
, 1) << " adding " << p
<< " " << a
<< dendl
;
635 add(p
, entity_addrvec_t(a
));
637 ceph_assert(contains(p
));
643 int MonMap::init_with_config_file(const ConfigProxy
& conf
,
644 std::ostream
& errout
)
646 std::vector
<std::string
> sections
;
647 int ret
= conf
.get_all_sections(sections
);
649 errout
<< "Unable to find any monitors in the configuration "
650 << "file, because there was an error listing the sections. error "
654 std::vector
<std::string
> mon_names
;
655 for (const auto& section
: sections
) {
656 if (section
.substr(0, 4) == "mon." && section
.size() > 4) {
657 mon_names
.push_back(section
.substr(4));
661 // Find an address for each monitor in the config file.
662 for (const auto& mon_name
: mon_names
) {
663 std::vector
<std::string
> sections
;
664 std::string
m_name("mon");
667 sections
.push_back(m_name
);
668 sections
.push_back("mon");
669 sections
.push_back("global");
671 int res
= conf
.get_val_from_conf_file(sections
, "mon addr", val
, true);
673 errout
<< "failed to get an address for mon." << mon_name
674 << ": error " << res
<< std::endl
;
677 // the 'mon addr' field is a legacy field, so assume anything
678 // there on a weird port is a v1 address, and do not handle
681 if (!addr
.parse(val
, entity_addr_t::TYPE_LEGACY
)) {
682 errout
<< "unable to parse address for mon." << mon_name
683 << ": addr='" << val
<< "'" << std::endl
;
686 if (addr
.get_port() == 0) {
687 addr
.set_port(CEPH_MON_PORT_LEGACY
);
689 uint16_t priority
= 0;
690 if (!conf
.get_val_from_conf_file(sections
, "mon priority", val
, false)) {
692 priority
= std::stoul(val
);
693 } catch (std::logic_error
&) {
694 errout
<< "unable to parse priority for mon." << mon_name
695 << ": priority='" << val
<< "'" << std::endl
;
700 if (!conf
.get_val_from_conf_file(sections
, "mon weight", val
, false)) {
702 weight
= std::stoul(val
);
703 } catch (std::logic_error
&) {
704 errout
<< "unable to parse weight for mon." << mon_name
705 << ": weight='" << val
<< "'"
711 // make sure this mon isn't already in the map
713 remove(get_name(addr
));
714 if (contains(mon_name
))
716 _add_ambiguous_addr(mon_name
, addr
, priority
, weight
, false);
721 void MonMap::check_health(health_check_map_t
*checks
) const
723 if (stretch_mode_enabled
) {
725 for (auto& p
: mon_info
) {
726 if (p
.second
.crush_loc
.empty()) {
728 ss
<< "mon " << p
.first
<< " has no location set while in stretch mode";
729 detail
.push_back(ss
.str());
732 if (!detail
.empty()) {
734 ss
<< detail
.size() << " monitor(s) have no location set while in stretch mode"
735 << "; this may cause issues with failover, OSD connections, netsplit handling, etc";
736 auto& d
= checks
->add("MON_LOCATION_NOT_SET", HEALTH_WARN
,
737 ss
.str(), detail
.size());
738 d
.detail
.swap(detail
);
745 seastar::future
<> MonMap::read_monmap(const std::string
& monmap
)
747 using namespace seastar
;
748 return open_file_dma(monmap
, open_flags::ro
).then([this] (file f
) {
749 return f
.size().then([this, f
= std::move(f
)](size_t s
) {
750 return do_with(make_file_input_stream(f
), [this, s
](input_stream
<char>& in
) {
751 return in
.read_exactly(s
).then([this](temporary_buffer
<char> buf
) {
752 ceph::buffer::list bl
;
753 bl
.push_back(ceph::buffer::ptr_node::create(
754 ceph::buffer::create(std::move(buf
))));
762 seastar::future
<> MonMap::init_with_dns_srv(bool for_mkfs
, const std::string
& name
)
764 logger().debug("{}: for_mkfs={}, name={}", __func__
, for_mkfs
, name
);
766 string service
= name
;
767 // check if domain is also provided and extract it from srv_name
768 size_t idx
= name
.find("_");
769 if (idx
!= name
.npos
) {
770 domain
= name
.substr(idx
+ 1);
771 service
= name
.substr(0, idx
);
773 return seastar::net::dns::get_srv_records(
774 seastar::net::dns_resolver::srv_proto::tcp
,
775 service
, domain
).then([this](seastar::net::dns_resolver::srv_records records
) {
776 return seastar::parallel_for_each(records
, [this](auto record
) {
777 return seastar::net::dns::resolve_name(record
.target
).then(
778 [record
,this](seastar::net::inet_address a
) {
779 // the resolved address does not contain ceph specific info like nonce
780 // nonce or msgr proto (legacy, msgr2), so set entity_addr_t manually
782 addr
.set_type(entity_addr_t::TYPE_ANY
);
783 addr
.set_family(int(a
.in_family()));
784 addr
.set_port(record
.port
);
785 switch (a
.in_family()) {
786 case seastar::net::inet_address::family::INET
:
787 addr
.in4_addr().sin_addr
= a
;
789 case seastar::net::inet_address::family::INET6
:
790 addr
.in6_addr().sin6_addr
= a
;
793 _add_ambiguous_addr(record
.target
,
798 }).handle_exception_type([t
=record
.target
](const std::system_error
& e
) {
799 logger().debug("{}: unable to resolve name for {}: {}",
800 "init_with_dns_srv", t
, e
);
803 }).handle_exception_type([name
](const std::system_error
& e
) {
804 logger().debug("{}: unable to get monitor info from DNS SRV with {}: {}",
805 "init_with_dns_srv", name
, e
);
806 // ignore DNS failures
807 return seastar::make_ready_future
<>();
811 bool MonMap::maybe_init_with_mon_host(const std::string
& mon_host
,
814 if (!mon_host
.empty()) {
815 if (auto ret
= init_with_ips(mon_host
, for_mkfs
, "noname-"); ret
== 0) {
818 // TODO: resolve_addrs() is a blocking call
819 if (auto ret
= init_with_hosts(mon_host
, for_mkfs
, "noname-"); ret
== 0) {
822 throw std::runtime_error(cpp_strerror(ret
));
828 seastar::future
<> MonMap::build_monmap(const crimson::common::ConfigProxy
& conf
,
831 logger().debug("{}: for_mkfs={}", __func__
, for_mkfs
);
833 if (maybe_init_with_mon_host(conf
.get_val
<std::string
>("mon_host"), for_mkfs
)) {
834 return seastar::make_ready_future
<>();
837 // What monitors are in the config file?
838 ostringstream errout
;
839 if (auto ret
= init_with_config_file(conf
, errout
); ret
< 0) {
840 throw std::runtime_error(errout
.str());
843 return seastar::make_ready_future
<>();
845 // no info found from conf options lets try use DNS SRV records
846 const string srv_name
= conf
.get_val
<std::string
>("mon_dns_srv_name");
847 return init_with_dns_srv(for_mkfs
, srv_name
).then([this] {
849 throw std::runtime_error("no monitors specified to connect to.");
854 seastar::future
<> MonMap::build_initial(const crimson::common::ConfigProxy
& conf
, bool for_mkfs
)
856 // mon_host_override?
857 if (maybe_init_with_mon_host(conf
.get_val
<std::string
>("mon_host_override"),
859 return seastar::make_ready_future
<>();
863 if (const auto monmap
= conf
.get_val
<std::string
>("monmap");
865 return read_monmap(monmap
);
868 if (const auto new_fsid
= conf
.get_val
<uuid_d
>("fsid");
869 !new_fsid
.is_zero()) {
872 return build_monmap(conf
, for_mkfs
).then([this] {
873 created
= ceph_clock_now();
874 last_changed
= created
;
880 #else // WITH_SEASTAR
882 int MonMap::init_with_monmap(const std::string
& monmap
, std::ostream
& errout
)
886 r
= read(monmap
.c_str());
887 } catch (ceph::buffer::error
&) {
892 errout
<< "unable to read/decode monmap from " << monmap
893 << ": " << cpp_strerror(-r
) << std::endl
;
897 int MonMap::init_with_dns_srv(CephContext
* cct
,
898 std::string srv_name
,
900 std::ostream
& errout
)
902 lgeneric_dout(cct
, 1) << __func__
<< " srv_name: " << srv_name
<< dendl
;
905 // check if domain is also provided and extract it from srv_name
906 size_t idx
= srv_name
.find("_");
907 if (idx
!= string::npos
) {
908 domain
= srv_name
.substr(idx
+ 1);
909 srv_name
= srv_name
.substr(0, idx
);
912 map
<string
, DNSResolver::Record
> records
;
913 if (DNSResolver::get_instance()->resolve_srv_hosts(cct
, srv_name
,
914 DNSResolver::SRV_Protocol::TCP
, domain
, &records
) != 0) {
916 errout
<< "unable to get monitor info from DNS SRV with service name: "
917 << "ceph-mon" << std::endl
;
920 for (auto& record
: records
) {
921 record
.second
.addr
.set_type(entity_addr_t::TYPE_ANY
);
922 _add_ambiguous_addr(record
.first
,
924 record
.second
.priority
,
925 record
.second
.weight
,
932 int MonMap::build_initial(CephContext
*cct
, bool for_mkfs
, ostream
& errout
)
934 lgeneric_dout(cct
, 1) << __func__
<< " for_mkfs: " << for_mkfs
<< dendl
;
935 const auto& conf
= cct
->_conf
;
937 // mon_host_override?
938 auto mon_host_override
= conf
.get_val
<std::string
>("mon_host_override");
939 if (!mon_host_override
.empty()) {
940 lgeneric_dout(cct
, 1) << "Using mon_host_override " << mon_host_override
<< dendl
;
941 auto ret
= init_with_ips(mon_host_override
, for_mkfs
, "noname-");
942 if (ret
== -EINVAL
) {
943 ret
= init_with_hosts(mon_host_override
, for_mkfs
, "noname-");
946 errout
<< "unable to parse addrs in '" << mon_host_override
<< "'"
953 auto addrs
= cct
->get_mon_addrs();
954 if (addrs
!= nullptr && (addrs
->size() > 0)) {
955 init_with_addrs(*addrs
, for_mkfs
, "noname-");
960 if (const auto monmap
= conf
.get_val
<std::string
>("monmap");
962 return init_with_monmap(monmap
, errout
);
966 if (const auto new_fsid
= conf
.get_val
<uuid_d
>("fsid");
967 !new_fsid
.is_zero()) {
971 if (const auto mon_host
= conf
.get_val
<std::string
>("mon_host");
973 auto ret
= init_with_ips(mon_host
, for_mkfs
, "noname-");
974 if (ret
== -EINVAL
) {
975 ret
= init_with_hosts(mon_host
, for_mkfs
, "noname-");
978 errout
<< "unable to parse addrs in '" << mon_host
<< "'"
984 // What monitors are in the config file?
985 if (auto ret
= init_with_config_file(conf
, errout
); ret
< 0) {
990 // no info found from conf options lets try use DNS SRV records
991 string srv_name
= conf
.get_val
<std::string
>("mon_dns_srv_name");
992 if (auto ret
= init_with_dns_srv(cct
, srv_name
, for_mkfs
, errout
); ret
< 0) {
997 errout
<< "no monitors specified to connect to." << std::endl
;
1000 strategy
= static_cast<election_strategy
>(conf
.get_val
<uint64_t>("mon_election_default_strategy"));
1001 created
= ceph_clock_now();
1002 last_changed
= created
;
1003 calc_legacy_ranks();
1006 #endif // WITH_SEASTAR