1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2016 John Spray <john.spray@redhat.com>
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.
20 #include "msg/msg_types.h"
21 #include "include/encoding.h"
22 #include "include/utime.h"
23 #include "common/Formatter.h"
24 #include "common/ceph_releases.h"
25 #include "common/version.h"
26 #include "common/options.h"
27 #include "common/Clock.h"
35 uint8_t type
= Option::TYPE_STR
; // Option::type_t TYPE_*
36 uint8_t level
= Option::LEVEL_ADVANCED
; // Option::level_t LEVEL_*
37 uint32_t flags
= 0; // Option::flag_t FLAG_*
38 std::string default_value
;
40 std::set
<std::string
> enum_allowed
;
41 std::string desc
, long_desc
;
42 std::set
<std::string
> tags
;
43 std::set
<std::string
> see_also
;
45 void encode(ceph::buffer::list
& bl
) const {
46 ENCODE_START(1, 1, bl
);
51 encode(default_value
, bl
);
54 encode(enum_allowed
, bl
);
56 encode(long_desc
, bl
);
61 void decode(ceph::buffer::list::const_iterator
& p
) {
67 decode(default_value
, p
);
70 decode(enum_allowed
, p
);
77 void dump(ceph::Formatter
*f
) const {
78 f
->dump_string("name", name
);
79 f
->dump_string("type", Option::type_to_str(
80 static_cast<Option::type_t
>(type
)));
81 f
->dump_string("level", Option::level_to_str(
82 static_cast<Option::level_t
>(level
)));
83 f
->dump_unsigned("flags", flags
);
84 f
->dump_string("default_value", default_value
);
85 f
->dump_string("min", min
);
86 f
->dump_string("max", max
);
87 f
->open_array_section("enum_allowed");
88 for (auto& i
: enum_allowed
) {
89 f
->dump_string("value", i
);
92 f
->dump_string("desc", desc
);
93 f
->dump_string("long_desc", long_desc
);
94 f
->open_array_section("tags");
95 for (auto& i
: tags
) {
96 f
->dump_string("tag", i
);
99 f
->open_array_section("see_also");
100 for (auto& i
: see_also
) {
101 f
->dump_string("option", i
);
112 std::string error_string
;
113 std::map
<std::string
,ModuleOption
> module_options
;
115 // We do not include the module's `failed` field in the beacon,
116 // because it is exposed via health checks.
117 void encode(ceph::buffer::list
&bl
) const {
118 ENCODE_START(2, 1, bl
);
121 encode(error_string
, bl
);
122 encode(module_options
, bl
);
126 void decode(ceph::buffer::list::const_iterator
&bl
) {
130 decode(error_string
, bl
);
132 decode(module_options
, bl
);
137 bool operator==(const ModuleInfo
&rhs
) const
139 return (name
== rhs
.name
) && (can_run
== rhs
.can_run
);
142 void dump(ceph::Formatter
*f
) const {
143 f
->open_object_section("module");
144 f
->dump_string("name", name
);
145 f
->dump_bool("can_run", can_run
);
146 f
->dump_string("error_string", error_string
);
147 f
->open_object_section("module_options");
148 for (auto& i
: module_options
) {
149 f
->dump_object(i
.first
.c_str(), i
.second
);
161 std::vector
<ModuleInfo
> available_modules
;
162 uint64_t mgr_features
= 0;
164 StandbyInfo(uint64_t gid_
, const std::string
&name_
,
165 const std::vector
<ModuleInfo
>& am
,
167 : gid(gid_
), name(name_
), available_modules(am
),
173 void encode(ceph::buffer::list
& bl
) const
175 ENCODE_START(4, 1, bl
);
178 std::set
<std::string
> old_available_modules
;
179 for (const auto &i
: available_modules
) {
180 old_available_modules
.insert(i
.name
);
182 encode(old_available_modules
, bl
); // version 2
183 encode(available_modules
, bl
); // version 3
184 encode(mgr_features
, bl
); // v4
188 void decode(ceph::buffer::list::const_iterator
& p
)
194 std::set
<std::string
> old_available_modules
;
195 decode(old_available_modules
, p
);
197 for (const auto &name
: old_available_modules
) {
198 MgrMap::ModuleInfo info
;
200 available_modules
.push_back(std::move(info
));
205 decode(available_modules
, p
);
208 decode(mgr_features
, p
);
213 bool have_module(const std::string
&module_name
) const
215 auto it
= std::find_if(available_modules
.begin(),
216 available_modules
.end(),
217 [module_name
](const ModuleInfo
&m
) -> bool {
218 return m
.name
== module_name
;
221 return it
!= available_modules
.end();
226 epoch_t last_failure_osd_epoch
= 0;
228 /// global_id of the ceph-mgr instance selected as a leader
229 uint64_t active_gid
= 0;
230 /// server address reported by the leader once it is active
231 entity_addrvec_t active_addrs
;
232 /// whether the nominated leader is active (i.e. has initialized its server)
233 bool available
= false;
234 /// the name (foo in mgr.<foo>) of the active daemon
235 std::string active_name
;
236 /// when the active mgr became active, or we lost the active mgr
237 utime_t active_change
;
239 uint64_t active_mgr_features
= 0;
241 std::multimap
<std::string
, entity_addrvec_t
> clients
; // for blocklist
243 std::map
<uint64_t, StandbyInfo
> standbys
;
245 // Modules which are enabled
246 std::set
<std::string
> modules
;
248 // Modules which should always be enabled. A manager daemon will enable
249 // modules from the union of this set and the `modules` set above, latest
251 std::map
<uint32_t, std::set
<std::string
>> always_on_modules
;
253 // Modules which are reported to exist
254 std::vector
<ModuleInfo
> available_modules
;
256 // Map of module name to URI, indicating services exposed by
257 // running modules on the active mgr daemon.
258 std::map
<std::string
, std::string
> services
;
260 static MgrMap
create_null_mgrmap() {
262 /* Use the largest epoch so it's always bigger than whatever the mgr has. */
263 null_map
.epoch
= std::numeric_limits
<decltype(epoch
)>::max();
267 epoch_t
get_epoch() const { return epoch
; }
268 epoch_t
get_last_failure_osd_epoch() const { return last_failure_osd_epoch
; }
269 const entity_addrvec_t
& get_active_addrs() const { return active_addrs
; }
270 uint64_t get_active_gid() const { return active_gid
; }
271 bool get_available() const { return available
; }
272 const std::string
&get_active_name() const { return active_name
; }
273 const utime_t
& get_active_change() const { return active_change
; }
274 int get_num_standby() const { return standbys
.size(); }
276 bool all_support_module(const std::string
& module
) {
277 if (!have_module(module
)) {
280 for (auto& p
: standbys
) {
281 if (!p
.second
.have_module(module
)) {
288 bool have_module(const std::string
&module_name
) const
290 for (const auto &i
: available_modules
) {
291 if (i
.name
== module_name
) {
299 const ModuleInfo
*get_module_info(const std::string
&module_name
) const {
300 for (const auto &i
: available_modules
) {
301 if (i
.name
== module_name
) {
308 bool can_run_module(const std::string
&module_name
, std::string
*error
) const
310 for (const auto &i
: available_modules
) {
311 if (i
.name
== module_name
) {
312 *error
= i
.error_string
;
317 std::ostringstream oss
;
318 oss
<< "Module '" << module_name
<< "' does not exist";
319 throw std::logic_error(oss
.str());
322 bool module_enabled(const std::string
& module_name
) const
324 return modules
.find(module_name
) != modules
.end();
327 bool any_supports_module(const std::string
& module
) const {
328 if (have_module(module
)) {
331 for (auto& p
: standbys
) {
332 if (p
.second
.have_module(module
)) {
339 bool have_name(const std::string
& name
) const {
340 if (active_name
== name
) {
343 for (auto& p
: standbys
) {
344 if (p
.second
.name
== name
) {
351 std::set
<std::string
> get_all_names() const {
352 std::set
<std::string
> ls
;
353 if (active_name
.size()) {
354 ls
.insert(active_name
);
356 for (auto& p
: standbys
) {
357 ls
.insert(p
.second
.name
);
362 std::set
<std::string
> get_always_on_modules() const {
363 unsigned rnum
= to_integer
<uint32_t>(ceph_release());
364 auto it
= always_on_modules
.find(rnum
);
365 if (it
== always_on_modules
.end()) {
366 // ok, try the most recent release
367 if (always_on_modules
.empty()) {
371 if (it
->first
< rnum
) {
379 void encode(ceph::buffer::list
& bl
, uint64_t features
) const
381 if (!HAVE_FEATURE(features
, SERVER_NAUTILUS
)) {
382 ENCODE_START(5, 1, bl
);
384 encode(active_addrs
.legacy_addr(), bl
, features
);
385 encode(active_gid
, bl
);
386 encode(available
, bl
);
387 encode(active_name
, bl
);
388 encode(standbys
, bl
);
391 // Pre-version 4 std::string std::list of available modules
392 // (replaced by direct encode of ModuleInfo below)
393 std::set
<std::string
> old_available_modules
;
394 for (const auto &i
: available_modules
) {
395 old_available_modules
.insert(i
.name
);
397 encode(old_available_modules
, bl
);
399 encode(services
, bl
);
400 encode(available_modules
, bl
);
404 ENCODE_START(12, 6, bl
);
406 encode(active_addrs
, bl
, features
);
407 encode(active_gid
, bl
);
408 encode(available
, bl
);
409 encode(active_name
, bl
);
410 encode(standbys
, bl
);
412 encode(services
, bl
);
413 encode(available_modules
, bl
);
414 encode(active_change
, bl
);
415 encode(always_on_modules
, bl
);
416 encode(active_mgr_features
, bl
);
417 encode(last_failure_osd_epoch
, bl
);
418 std::vector
<std::string
> clients_names
;
419 std::vector
<entity_addrvec_t
> clients_addrs
;
420 for (const auto& i
: clients
) {
421 clients_names
.push_back(i
.first
);
422 clients_addrs
.push_back(i
.second
);
424 // The address vector needs to be encoded first to produce a
425 // backwards compatible messsage for older monitors.
426 encode(clients_addrs
, bl
, features
);
427 encode(clients_names
, bl
, features
);
432 void decode(ceph::buffer::list::const_iterator
& p
)
436 decode(active_addrs
, p
);
437 decode(active_gid
, p
);
438 decode(available
, p
);
439 decode(active_name
, p
);
445 // Reconstitute ModuleInfos from names
446 std::set
<std::string
> module_name_list
;
447 decode(module_name_list
, p
);
448 // Only need to unpack this field if we won't have the full
449 // MgrMap::ModuleInfo structures added in v4
451 for (const auto &i
: module_name_list
) {
452 MgrMap::ModuleInfo info
;
454 available_modules
.push_back(std::move(info
));
463 decode(available_modules
, p
);
466 decode(active_change
, p
);
471 decode(always_on_modules
, p
);
474 decode(active_mgr_features
, p
);
476 if (struct_v
>= 10) {
477 decode(last_failure_osd_epoch
, p
);
479 if (struct_v
>= 11) {
480 std::vector
<entity_addrvec_t
> clients_addrs
;
481 decode(clients_addrs
, p
);
483 if (struct_v
>= 12) {
484 std::vector
<std::string
> clients_names
;
485 decode(clients_names
, p
);
486 if (clients_names
.size() != clients_addrs
.size()) {
487 throw ceph::buffer::malformed_input(
488 "clients_names.size() != clients_addrs.size()");
490 auto cn
= clients_names
.begin();
491 auto ca
= clients_addrs
.begin();
492 for(; cn
!= clients_names
.end(); ++cn
, ++ca
) {
493 clients
.emplace(*cn
, *ca
);
496 for (const auto& i
: clients_addrs
) {
497 clients
.emplace("", i
);
504 void dump(ceph::Formatter
*f
) const {
505 f
->dump_int("epoch", epoch
);
506 f
->dump_int("active_gid", get_active_gid());
507 f
->dump_string("active_name", get_active_name());
508 f
->dump_object("active_addrs", active_addrs
);
509 f
->dump_stream("active_addr") << active_addrs
.get_legacy_str();
510 f
->dump_stream("active_change") << active_change
;
511 f
->dump_unsigned("active_mgr_features", active_mgr_features
);
512 f
->dump_bool("available", available
);
513 f
->open_array_section("standbys");
514 for (const auto &i
: standbys
) {
515 f
->open_object_section("standby");
516 f
->dump_int("gid", i
.second
.gid
);
517 f
->dump_string("name", i
.second
.name
);
518 f
->dump_unsigned("mgr_features", i
.second
.mgr_features
);
519 f
->open_array_section("available_modules");
520 for (const auto& j
: i
.second
.available_modules
) {
527 f
->open_array_section("modules");
528 for (auto& i
: modules
) {
529 f
->dump_string("module", i
);
532 f
->open_array_section("available_modules");
533 for (const auto& j
: available_modules
) {
538 f
->open_object_section("services");
539 for (const auto &i
: services
) {
540 f
->dump_string(i
.first
.c_str(), i
.second
);
544 f
->open_object_section("always_on_modules");
545 for (auto& v
: always_on_modules
) {
546 f
->open_array_section(ceph_release_name(v
.first
));
547 for (auto& m
: v
.second
) {
548 f
->dump_string("module", m
);
552 f
->close_section(); // always_on_modules
553 f
->dump_int("last_failure_osd_epoch", last_failure_osd_epoch
);
554 f
->open_array_section("active_clients");
555 for (const auto& i
: clients
) {
556 f
->open_object_section("client");
557 f
->dump_string("name", i
.first
);
561 f
->close_section(); // active_clients
564 static void generate_test_instances(std::list
<MgrMap
*> &l
) {
565 l
.push_back(new MgrMap
);
568 void print_summary(ceph::Formatter
*f
, std::ostream
*ss
) const
570 // One or the other, not both
571 ceph_assert((ss
!= nullptr) != (f
!= nullptr));
573 f
->dump_bool("available", available
);
574 f
->dump_int("num_standbys", standbys
.size());
575 f
->open_array_section("modules");
576 for (auto& i
: modules
) {
577 f
->dump_string("module", i
);
580 f
->open_object_section("services");
581 for (const auto &i
: services
) {
582 f
->dump_string(i
.first
.c_str(), i
.second
);
586 utime_t now
= ceph_clock_now();
587 if (get_active_gid() != 0) {
588 *ss
<< get_active_name();
590 // If the daemon hasn't gone active yet, indicate that.
591 *ss
<< "(active, starting";
596 *ss
<< ", since " << utimespan_str(now
- active_change
);
600 *ss
<< "no daemons active";
602 *ss
<< " (since " << utimespan_str(now
- active_change
) << ")";
605 if (standbys
.size()) {
606 *ss
<< ", standbys: ";
608 for (const auto &i
: standbys
) {
612 *ss
<< i
.second
.name
;
619 friend std::ostream
& operator<<(std::ostream
& out
, const MgrMap
& m
) {
620 std::ostringstream ss
;
621 m
.print_summary(nullptr, &ss
);
622 return out
<< ss
.str();
625 friend std::ostream
& operator<<(std::ostream
& out
, const std::vector
<ModuleInfo
>& mi
) {
626 for (const auto &i
: mi
) {
627 out
<< i
.name
<< " ";
633 WRITE_CLASS_ENCODER_FEATURES(MgrMap
)
634 WRITE_CLASS_ENCODER(MgrMap::StandbyInfo
)
635 WRITE_CLASS_ENCODER(MgrMap::ModuleInfo
);
636 WRITE_CLASS_ENCODER(MgrMap::ModuleOption
);