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::vector
<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 epoch_t
get_epoch() const { return epoch
; }
261 epoch_t
get_last_failure_osd_epoch() const { return last_failure_osd_epoch
; }
262 const entity_addrvec_t
& get_active_addrs() const { return active_addrs
; }
263 uint64_t get_active_gid() const { return active_gid
; }
264 bool get_available() const { return available
; }
265 const std::string
&get_active_name() const { return active_name
; }
266 const utime_t
& get_active_change() const { return active_change
; }
267 int get_num_standby() const { return standbys
.size(); }
269 bool all_support_module(const std::string
& module
) {
270 if (!have_module(module
)) {
273 for (auto& p
: standbys
) {
274 if (!p
.second
.have_module(module
)) {
281 bool have_module(const std::string
&module_name
) const
283 for (const auto &i
: available_modules
) {
284 if (i
.name
== module_name
) {
292 const ModuleInfo
*get_module_info(const std::string
&module_name
) const {
293 for (const auto &i
: available_modules
) {
294 if (i
.name
== module_name
) {
301 bool can_run_module(const std::string
&module_name
, std::string
*error
) const
303 for (const auto &i
: available_modules
) {
304 if (i
.name
== module_name
) {
305 *error
= i
.error_string
;
310 std::ostringstream oss
;
311 oss
<< "Module '" << module_name
<< "' does not exist";
312 throw std::logic_error(oss
.str());
315 bool module_enabled(const std::string
& module_name
) const
317 return modules
.find(module_name
) != modules
.end();
320 bool any_supports_module(const std::string
& module
) const {
321 if (have_module(module
)) {
324 for (auto& p
: standbys
) {
325 if (p
.second
.have_module(module
)) {
332 bool have_name(const std::string
& name
) const {
333 if (active_name
== name
) {
336 for (auto& p
: standbys
) {
337 if (p
.second
.name
== name
) {
344 std::set
<std::string
> get_all_names() const {
345 std::set
<std::string
> ls
;
346 if (active_name
.size()) {
347 ls
.insert(active_name
);
349 for (auto& p
: standbys
) {
350 ls
.insert(p
.second
.name
);
355 std::set
<std::string
> get_always_on_modules() const {
356 unsigned rnum
= to_integer
<uint32_t>(ceph_release());
357 auto it
= always_on_modules
.find(rnum
);
358 if (it
== always_on_modules
.end()) {
359 // ok, try the most recent release
360 if (always_on_modules
.empty()) {
364 if (it
->first
< rnum
) {
372 void encode(ceph::buffer::list
& bl
, uint64_t features
) const
374 if (!HAVE_FEATURE(features
, SERVER_NAUTILUS
)) {
375 ENCODE_START(5, 1, bl
);
377 encode(active_addrs
.legacy_addr(), bl
, features
);
378 encode(active_gid
, bl
);
379 encode(available
, bl
);
380 encode(active_name
, bl
);
381 encode(standbys
, bl
);
384 // Pre-version 4 std::string std::list of available modules
385 // (replaced by direct encode of ModuleInfo below)
386 std::set
<std::string
> old_available_modules
;
387 for (const auto &i
: available_modules
) {
388 old_available_modules
.insert(i
.name
);
390 encode(old_available_modules
, bl
);
392 encode(services
, bl
);
393 encode(available_modules
, bl
);
397 ENCODE_START(11, 6, bl
);
399 encode(active_addrs
, bl
, features
);
400 encode(active_gid
, bl
);
401 encode(available
, bl
);
402 encode(active_name
, bl
);
403 encode(standbys
, bl
);
405 encode(services
, bl
);
406 encode(available_modules
, bl
);
407 encode(active_change
, bl
);
408 encode(always_on_modules
, bl
);
409 encode(active_mgr_features
, bl
);
410 encode(last_failure_osd_epoch
, bl
);
411 encode(clients
, bl
, features
);
416 void decode(ceph::buffer::list::const_iterator
& p
)
420 decode(active_addrs
, p
);
421 decode(active_gid
, p
);
422 decode(available
, p
);
423 decode(active_name
, p
);
429 // Reconstitute ModuleInfos from names
430 std::set
<std::string
> module_name_list
;
431 decode(module_name_list
, p
);
432 // Only need to unpack this field if we won't have the full
433 // MgrMap::ModuleInfo structures added in v4
435 for (const auto &i
: module_name_list
) {
436 MgrMap::ModuleInfo info
;
438 available_modules
.push_back(std::move(info
));
447 decode(available_modules
, p
);
450 decode(active_change
, p
);
455 decode(always_on_modules
, p
);
458 decode(active_mgr_features
, p
);
460 if (struct_v
>= 10) {
461 decode(last_failure_osd_epoch
, p
);
463 if (struct_v
>= 11) {
469 void dump(ceph::Formatter
*f
) const {
470 f
->dump_int("epoch", epoch
);
471 f
->dump_int("active_gid", get_active_gid());
472 f
->dump_string("active_name", get_active_name());
473 f
->dump_object("active_addrs", active_addrs
);
474 f
->dump_stream("active_addr") << active_addrs
.get_legacy_str();
475 f
->dump_stream("active_change") << active_change
;
476 f
->dump_unsigned("active_mgr_features", active_mgr_features
);
477 f
->dump_bool("available", available
);
478 f
->open_array_section("standbys");
479 for (const auto &i
: standbys
) {
480 f
->open_object_section("standby");
481 f
->dump_int("gid", i
.second
.gid
);
482 f
->dump_string("name", i
.second
.name
);
483 f
->dump_unsigned("mgr_features", i
.second
.mgr_features
);
484 f
->open_array_section("available_modules");
485 for (const auto& j
: i
.second
.available_modules
) {
492 f
->open_array_section("modules");
493 for (auto& i
: modules
) {
494 f
->dump_string("module", i
);
497 f
->open_array_section("available_modules");
498 for (const auto& j
: available_modules
) {
503 f
->open_object_section("services");
504 for (const auto &i
: services
) {
505 f
->dump_string(i
.first
.c_str(), i
.second
);
509 f
->open_object_section("always_on_modules");
510 for (auto& v
: always_on_modules
) {
511 f
->open_array_section(ceph_release_name(v
.first
));
512 for (auto& m
: v
.second
) {
513 f
->dump_string("module", m
);
517 f
->dump_int("last_failure_osd_epoch", last_failure_osd_epoch
);
518 f
->open_array_section("active_clients");
519 for (const auto &c
: clients
) {
520 f
->dump_object("client", c
);
526 static void generate_test_instances(std::list
<MgrMap
*> &l
) {
527 l
.push_back(new MgrMap
);
530 void print_summary(ceph::Formatter
*f
, std::ostream
*ss
) const
532 // One or the other, not both
533 ceph_assert((ss
!= nullptr) != (f
!= nullptr));
535 f
->dump_bool("available", available
);
536 f
->dump_int("num_standbys", standbys
.size());
537 f
->open_array_section("modules");
538 for (auto& i
: modules
) {
539 f
->dump_string("module", i
);
542 f
->open_object_section("services");
543 for (const auto &i
: services
) {
544 f
->dump_string(i
.first
.c_str(), i
.second
);
548 utime_t now
= ceph_clock_now();
549 if (get_active_gid() != 0) {
550 *ss
<< get_active_name();
552 // If the daemon hasn't gone active yet, indicate that.
553 *ss
<< "(active, starting";
558 *ss
<< ", since " << utimespan_str(now
- active_change
);
562 *ss
<< "no daemons active";
564 *ss
<< " (since " << utimespan_str(now
- active_change
) << ")";
567 if (standbys
.size()) {
568 *ss
<< ", standbys: ";
570 for (const auto &i
: standbys
) {
574 *ss
<< i
.second
.name
;
581 friend std::ostream
& operator<<(std::ostream
& out
, const MgrMap
& m
) {
582 std::ostringstream ss
;
583 m
.print_summary(nullptr, &ss
);
584 return out
<< ss
.str();
587 friend std::ostream
& operator<<(std::ostream
& out
, const std::vector
<ModuleInfo
>& mi
) {
588 for (const auto &i
: mi
) {
589 out
<< i
.name
<< " ";
595 WRITE_CLASS_ENCODER_FEATURES(MgrMap
)
596 WRITE_CLASS_ENCODER(MgrMap::StandbyInfo
)
597 WRITE_CLASS_ENCODER(MgrMap::ModuleInfo
);
598 WRITE_CLASS_ENCODER(MgrMap::ModuleOption
);