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
;
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
->open_object_section("features");
416 persistent_features
.dump(f
, "persistent");
417 optional_features
.dump(f
, "optional");
419 f
->open_array_section("mons");
421 for (auto p
= ranks
.begin(); p
!= ranks
.end(); ++p
, ++i
) {
422 f
->open_object_section("mon");
423 f
->dump_int("rank", i
);
424 f
->dump_string("name", *p
);
425 f
->dump_object("public_addrs", get_addrs(*p
));
426 // compat: make these look like pre-nautilus entity_addr_t
427 f
->dump_stream("addr") << get_addrs(*p
).get_legacy_str();
428 f
->dump_stream("public_addr") << get_addrs(*p
).get_legacy_str();
429 f
->dump_unsigned("priority", get_priority(*p
));
430 f
->dump_unsigned("weight", get_weight(*p
));
431 const auto &mi
= mon_info
.find(*p
);
432 // we don't need to assert this validity as all the get_* functions did
433 f
->dump_stream("crush_location") << mi
->second
.crush_loc
;
439 void MonMap::dump_summary(Formatter
*f
) const
441 f
->dump_unsigned("epoch", epoch
);
442 f
->dump_string("min_mon_release_name", to_string(min_mon_release
));
443 f
->dump_unsigned("num_mons", ranks
.size());
446 // an ambiguous mon addr may be legacy or may be msgr2--we aren' sure.
447 // when that happens we need to try them both (unless we can
448 // reasonably infer from the port number which it is).
449 void MonMap::_add_ambiguous_addr(const string
& name
,
455 if (addr
.get_type() != entity_addr_t::TYPE_ANY
) {
456 // a v1: or v2: prefix was specified
457 if (addr
.get_port() == 0) {
459 if (addr
.get_type() == entity_addr_t::TYPE_LEGACY
) {
460 addr
.set_port(CEPH_MON_PORT_LEGACY
);
461 } else if (addr
.get_type() == entity_addr_t::TYPE_MSGR2
) {
462 addr
.set_port(CEPH_MON_PORT_IANA
);
467 if (!contains(addr
)) {
468 add(name
, entity_addrvec_t(addr
), priority
, weight
);
471 if (!contains(addr
)) {
472 add(name
, entity_addrvec_t(addr
), priority
, weight
);
476 // no v1: or v2: prefix specified
477 if (addr
.get_port() == CEPH_MON_PORT_LEGACY
) {
478 // legacy port implies legacy addr
479 addr
.set_type(entity_addr_t::TYPE_LEGACY
);
480 if (!contains(addr
)) {
482 add(name
+ "-legacy", entity_addrvec_t(addr
), priority
, weight
);
484 add(name
, entity_addrvec_t(addr
), priority
, weight
);
487 } else if (addr
.get_port() == CEPH_MON_PORT_IANA
) {
488 // iana port implies msgr2 addr
489 addr
.set_type(entity_addr_t::TYPE_MSGR2
);
490 if (!contains(addr
)) {
491 add(name
, entity_addrvec_t(addr
), priority
, weight
);
493 } else if (addr
.get_port() == 0) {
494 // no port; include both msgr2 and legacy ports
496 addr
.set_type(entity_addr_t::TYPE_MSGR2
);
497 addr
.set_port(CEPH_MON_PORT_IANA
);
498 if (!contains(addr
)) {
499 add(name
, entity_addrvec_t(addr
), priority
, weight
);
501 addr
.set_type(entity_addr_t::TYPE_LEGACY
);
502 addr
.set_port(CEPH_MON_PORT_LEGACY
);
503 if (!contains(addr
)) {
504 add(name
+ "-legacy", entity_addrvec_t(addr
), priority
, weight
);
508 addr
.set_type(entity_addr_t::TYPE_MSGR2
);
509 addr
.set_port(CEPH_MON_PORT_IANA
);
510 av
.v
.push_back(addr
);
511 addr
.set_type(entity_addr_t::TYPE_LEGACY
);
512 addr
.set_port(CEPH_MON_PORT_LEGACY
);
513 av
.v
.push_back(addr
);
515 add(name
, av
, priority
, weight
);
519 addr
.set_type(entity_addr_t::TYPE_MSGR2
);
520 if (!contains(addr
)) {
521 add(name
, entity_addrvec_t(addr
), priority
, weight
);
524 // try legacy on same port too
525 addr
.set_type(entity_addr_t::TYPE_LEGACY
);
526 if (!contains(addr
)) {
527 add(name
+ "-legacy", entity_addrvec_t(addr
), priority
, weight
);
534 void MonMap::init_with_addrs(const std::vector
<entity_addrvec_t
>& addrs
,
536 std::string_view prefix
)
539 for (auto& addr
: addrs
) {
542 if (addr
.v
.size() == 1) {
543 _add_ambiguous_addr(name
, addr
.front(), 0, 0, for_mkfs
);
545 // they specified an addrvec, so let's assume they also specified
546 // the addr *type* and *port*. (we could possibly improve this?)
552 int MonMap::init_with_ips(const std::string
& ips
,
554 std::string_view prefix
)
556 vector
<entity_addrvec_t
> addrs
;
557 if (!parse_ip_port_vec(
559 entity_addr_t::TYPE_ANY
)) {
564 init_with_addrs(addrs
, for_mkfs
, prefix
);
568 int MonMap::init_with_hosts(const std::string
& hostlist
,
570 std::string_view prefix
)
572 // maybe they passed us a DNS-resolvable name
573 char *hosts
= resolve_addrs(hostlist
.c_str());
577 vector
<entity_addrvec_t
> addrs
;
578 bool success
= parse_ip_port_vec(
580 entity_addr_t::TYPE_ANY
);
586 init_with_addrs(addrs
, for_mkfs
, prefix
);
591 void MonMap::set_initial_members(CephContext
*cct
,
592 list
<std::string
>& initial_members
,
594 const entity_addrvec_t
& my_addrs
,
595 set
<entity_addrvec_t
> *removed
)
597 // remove non-initial members
600 string n
= get_name(i
);
601 if (std::find(initial_members
.begin(), initial_members
.end(), n
)
602 != initial_members
.end()) {
603 lgeneric_dout(cct
, 1) << " keeping " << n
<< " " << get_addrs(i
) << dendl
;
608 lgeneric_dout(cct
, 1) << " removing " << get_name(i
) << " " << get_addrs(i
)
611 removed
->insert(get_addrs(i
));
614 ceph_assert(!contains(n
));
617 // add missing initial members
618 for (auto& p
: initial_members
) {
621 lgeneric_dout(cct
, 1) << " adding self " << p
<< " " << my_addrs
626 a
.set_type(entity_addr_t::TYPE_LEGACY
);
627 a
.set_family(AF_INET
);
628 for (int n
=1; ; n
++) {
633 lgeneric_dout(cct
, 1) << " adding " << p
<< " " << a
<< dendl
;
634 add(p
, entity_addrvec_t(a
));
636 ceph_assert(contains(p
));
642 int MonMap::init_with_config_file(const ConfigProxy
& conf
,
643 std::ostream
& errout
)
645 std::vector
<std::string
> sections
;
646 int ret
= conf
.get_all_sections(sections
);
648 errout
<< "Unable to find any monitors in the configuration "
649 << "file, because there was an error listing the sections. error "
653 std::vector
<std::string
> mon_names
;
654 for (const auto& section
: sections
) {
655 if (section
.substr(0, 4) == "mon." && section
.size() > 4) {
656 mon_names
.push_back(section
.substr(4));
660 // Find an address for each monitor in the config file.
661 for (const auto& mon_name
: mon_names
) {
662 std::vector
<std::string
> sections
;
663 std::string
m_name("mon");
666 sections
.push_back(m_name
);
667 sections
.push_back("mon");
668 sections
.push_back("global");
670 int res
= conf
.get_val_from_conf_file(sections
, "mon addr", val
, true);
672 errout
<< "failed to get an address for mon." << mon_name
673 << ": error " << res
<< std::endl
;
676 // the 'mon addr' field is a legacy field, so assume anything
677 // there on a weird port is a v1 address, and do not handle
680 if (!addr
.parse(val
, entity_addr_t::TYPE_LEGACY
)) {
681 errout
<< "unable to parse address for mon." << mon_name
682 << ": addr='" << val
<< "'" << std::endl
;
685 if (addr
.get_port() == 0) {
686 addr
.set_port(CEPH_MON_PORT_LEGACY
);
688 uint16_t priority
= 0;
689 if (!conf
.get_val_from_conf_file(sections
, "mon priority", val
, false)) {
691 priority
= std::stoul(val
);
692 } catch (std::logic_error
&) {
693 errout
<< "unable to parse priority for mon." << mon_name
694 << ": priority='" << val
<< "'" << std::endl
;
699 if (!conf
.get_val_from_conf_file(sections
, "mon weight", val
, false)) {
701 weight
= std::stoul(val
);
702 } catch (std::logic_error
&) {
703 errout
<< "unable to parse weight for mon." << mon_name
704 << ": weight='" << val
<< "'"
710 // make sure this mon isn't already in the map
712 remove(get_name(addr
));
713 if (contains(mon_name
))
715 _add_ambiguous_addr(mon_name
, addr
, priority
, weight
, false);
720 void MonMap::check_health(health_check_map_t
*checks
) const
722 if (stretch_mode_enabled
) {
724 for (auto& p
: mon_info
) {
725 if (p
.second
.crush_loc
.empty()) {
727 ss
<< "mon " << p
.first
<< " has no location set while in stretch mode";
728 detail
.push_back(ss
.str());
731 if (!detail
.empty()) {
733 ss
<< detail
.size() << " monitor(s) have no location set while in stretch mode"
734 << "; this may cause issues with failover, OSD connections, netsplit handling, etc";
735 auto& d
= checks
->add("MON_LOCATION_NOT_SET", HEALTH_WARN
,
736 ss
.str(), detail
.size());
737 d
.detail
.swap(detail
);
744 seastar::future
<> MonMap::read_monmap(const std::string
& monmap
)
746 using namespace seastar
;
747 return open_file_dma(monmap
, open_flags::ro
).then([this] (file f
) {
748 return f
.size().then([this, f
= std::move(f
)](size_t s
) {
749 return do_with(make_file_input_stream(f
), [this, s
](input_stream
<char>& in
) {
750 return in
.read_exactly(s
).then([this](temporary_buffer
<char> buf
) {
751 ceph::buffer::list bl
;
752 bl
.push_back(ceph::buffer::ptr_node::create(
753 ceph::buffer::create(std::move(buf
))));
761 seastar::future
<> MonMap::init_with_dns_srv(bool for_mkfs
, const std::string
& name
)
763 logger().debug("{}: for_mkfs={}, name={}", __func__
, for_mkfs
, name
);
765 string service
= name
;
766 // check if domain is also provided and extract it from srv_name
767 size_t idx
= name
.find("_");
768 if (idx
!= name
.npos
) {
769 domain
= name
.substr(idx
+ 1);
770 service
= name
.substr(0, idx
);
772 return seastar::net::dns::get_srv_records(
773 seastar::net::dns_resolver::srv_proto::tcp
,
774 service
, domain
).then([this](seastar::net::dns_resolver::srv_records records
) {
775 return seastar::parallel_for_each(records
, [this](auto record
) {
776 return seastar::net::dns::resolve_name(record
.target
).then(
777 [record
,this](seastar::net::inet_address a
) {
778 // the resolved address does not contain ceph specific info like nonce
779 // nonce or msgr proto (legacy, msgr2), so set entity_addr_t manually
781 addr
.set_type(entity_addr_t::TYPE_ANY
);
782 addr
.set_family(int(a
.in_family()));
783 addr
.set_port(record
.port
);
784 switch (a
.in_family()) {
785 case seastar::net::inet_address::family::INET
:
786 addr
.in4_addr().sin_addr
= a
;
788 case seastar::net::inet_address::family::INET6
:
789 addr
.in6_addr().sin6_addr
= a
;
792 _add_ambiguous_addr(record
.target
,
797 }).handle_exception_type([t
=record
.target
](const std::system_error
& e
) {
798 logger().debug("{}: unable to resolve name for {}: {}",
799 "init_with_dns_srv", t
, e
);
802 }).handle_exception_type([name
](const std::system_error
& e
) {
803 logger().debug("{}: unable to get monitor info from DNS SRV with {}: {}",
804 "init_with_dns_srv", name
, e
);
805 // ignore DNS failures
806 return seastar::make_ready_future
<>();
810 bool MonMap::maybe_init_with_mon_host(const std::string
& mon_host
,
813 if (!mon_host
.empty()) {
814 if (auto ret
= init_with_ips(mon_host
, for_mkfs
, "noname-"); ret
== 0) {
817 // TODO: resolve_addrs() is a blocking call
818 if (auto ret
= init_with_hosts(mon_host
, for_mkfs
, "noname-"); ret
== 0) {
821 throw std::runtime_error(cpp_strerror(ret
));
827 seastar::future
<> MonMap::build_monmap(const crimson::common::ConfigProxy
& conf
,
830 logger().debug("{}: for_mkfs={}", __func__
, for_mkfs
);
832 if (maybe_init_with_mon_host(conf
.get_val
<std::string
>("mon_host"), for_mkfs
)) {
833 return seastar::make_ready_future
<>();
836 // What monitors are in the config file?
837 ostringstream errout
;
838 if (auto ret
= init_with_config_file(conf
, errout
); ret
< 0) {
839 throw std::runtime_error(errout
.str());
842 return seastar::make_ready_future
<>();
844 // no info found from conf options lets try use DNS SRV records
845 const string srv_name
= conf
.get_val
<std::string
>("mon_dns_srv_name");
846 return init_with_dns_srv(for_mkfs
, srv_name
).then([this] {
848 throw std::runtime_error("no monitors specified to connect to.");
853 seastar::future
<> MonMap::build_initial(const crimson::common::ConfigProxy
& conf
, bool for_mkfs
)
855 // mon_host_override?
856 if (maybe_init_with_mon_host(conf
.get_val
<std::string
>("mon_host_override"),
858 return seastar::make_ready_future
<>();
862 if (const auto monmap
= conf
.get_val
<std::string
>("monmap");
864 return read_monmap(monmap
);
867 if (const auto new_fsid
= conf
.get_val
<uuid_d
>("fsid");
868 !new_fsid
.is_zero()) {
871 return build_monmap(conf
, for_mkfs
).then([this] {
872 created
= ceph_clock_now();
873 last_changed
= created
;
879 #else // WITH_SEASTAR
881 int MonMap::init_with_monmap(const std::string
& monmap
, std::ostream
& errout
)
885 r
= read(monmap
.c_str());
886 } catch (ceph::buffer::error
&) {
891 errout
<< "unable to read/decode monmap from " << monmap
892 << ": " << cpp_strerror(-r
) << std::endl
;
896 int MonMap::init_with_dns_srv(CephContext
* cct
,
897 std::string srv_name
,
899 std::ostream
& errout
)
901 lgeneric_dout(cct
, 1) << __func__
<< " srv_name: " << srv_name
<< dendl
;
904 // check if domain is also provided and extract it from srv_name
905 size_t idx
= srv_name
.find("_");
906 if (idx
!= string::npos
) {
907 domain
= srv_name
.substr(idx
+ 1);
908 srv_name
= srv_name
.substr(0, idx
);
911 map
<string
, DNSResolver::Record
> records
;
912 if (DNSResolver::get_instance()->resolve_srv_hosts(cct
, srv_name
,
913 DNSResolver::SRV_Protocol::TCP
, domain
, &records
) != 0) {
915 errout
<< "unable to get monitor info from DNS SRV with service name: "
916 << "ceph-mon" << std::endl
;
919 for (auto& record
: records
) {
920 record
.second
.addr
.set_type(entity_addr_t::TYPE_ANY
);
921 _add_ambiguous_addr(record
.first
,
923 record
.second
.priority
,
924 record
.second
.weight
,
931 int MonMap::build_initial(CephContext
*cct
, bool for_mkfs
, ostream
& errout
)
933 lgeneric_dout(cct
, 1) << __func__
<< " for_mkfs: " << for_mkfs
<< dendl
;
934 const auto& conf
= cct
->_conf
;
936 // mon_host_override?
937 auto mon_host_override
= conf
.get_val
<std::string
>("mon_host_override");
938 if (!mon_host_override
.empty()) {
939 lgeneric_dout(cct
, 1) << "Using mon_host_override " << mon_host_override
<< dendl
;
940 auto ret
= init_with_ips(mon_host_override
, for_mkfs
, "noname-");
941 if (ret
== -EINVAL
) {
942 ret
= init_with_hosts(mon_host_override
, for_mkfs
, "noname-");
945 errout
<< "unable to parse addrs in '" << mon_host_override
<< "'"
952 auto addrs
= cct
->get_mon_addrs();
953 if (addrs
!= nullptr && (addrs
->size() > 0)) {
954 init_with_addrs(*addrs
, for_mkfs
, "noname-");
959 if (const auto monmap
= conf
.get_val
<std::string
>("monmap");
961 return init_with_monmap(monmap
, errout
);
965 if (const auto new_fsid
= conf
.get_val
<uuid_d
>("fsid");
966 !new_fsid
.is_zero()) {
970 if (const auto mon_host
= conf
.get_val
<std::string
>("mon_host");
972 auto ret
= init_with_ips(mon_host
, for_mkfs
, "noname-");
973 if (ret
== -EINVAL
) {
974 ret
= init_with_hosts(mon_host
, for_mkfs
, "noname-");
977 errout
<< "unable to parse addrs in '" << mon_host
<< "'"
983 // What monitors are in the config file?
984 if (auto ret
= init_with_config_file(conf
, errout
); ret
< 0) {
989 // no info found from conf options lets try use DNS SRV records
990 string srv_name
= conf
.get_val
<std::string
>("mon_dns_srv_name");
991 if (auto ret
= init_with_dns_srv(cct
, srv_name
, for_mkfs
, errout
); ret
< 0) {
996 errout
<< "no monitors specified to connect to." << std::endl
;
999 strategy
= static_cast<election_strategy
>(conf
.get_val
<uint64_t>("mon_election_default_strategy"));
1000 created
= ceph_clock_now();
1001 last_changed
= created
;
1002 calc_legacy_ranks();
1005 #endif // WITH_SEASTAR