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.
14 #include <boost/tokenizer.hpp>
16 #include "messages/MMgrBeacon.h"
17 #include "messages/MMgrMap.h"
18 #include "messages/MMgrDigest.h"
20 #include "PGStatService.h"
21 #include "include/stringify.h"
22 #include "mgr/MgrContext.h"
23 #include "mgr/mgr_commands.h"
24 #include "OSDMonitor.h"
26 #include "MgrMonitor.h"
28 #define MGR_METADATA_PREFIX "mgr_metadata"
30 #define dout_subsys ceph_subsys_mon
32 #define dout_prefix _prefix(_dout, mon, map)
33 static ostream
& _prefix(std::ostream
*_dout
, Monitor
*mon
,
34 const MgrMap
& mgrmap
) {
35 return *_dout
<< "mon." << mon
->name
<< "@" << mon
->rank
36 << "(" << mon
->get_state_name()
37 << ").mgr e" << mgrmap
.get_epoch() << " ";
40 // Prefix for mon store of active mgr's command descriptions
41 const static std::string command_descs_prefix
= "mgr_command_descs";
44 version_t
MgrMonitor::get_trim_to()
46 int64_t max
= g_conf
->get_val
<int64_t>("mon_max_mgrmap_epochs");
47 if (map
.epoch
> max
) {
48 return map
.epoch
- max
;
53 void MgrMonitor::create_initial()
55 // Take a local copy of initial_modules for tokenizer to iterate over.
56 auto initial_modules
= g_conf
->get_val
<std::string
>("mgr_initial_modules");
57 boost::tokenizer
<> tok(initial_modules
);
59 pending_map
.modules
.insert(m
);
61 pending_command_descs
= mgr_commands
;
62 dout(10) << __func__
<< " initial modules " << pending_map
.modules
63 << ", " << pending_command_descs
.size() << " commands"
67 void MgrMonitor::get_store_prefixes(std::set
<string
>& s
)
69 s
.insert(service_name
);
70 s
.insert(command_descs_prefix
);
71 s
.insert(MGR_METADATA_PREFIX
);
74 void MgrMonitor::update_from_paxos(bool *need_bootstrap
)
76 version_t version
= get_last_committed();
77 if (version
!= map
.epoch
) {
78 dout(4) << "loading version " << version
<< dendl
;
81 int err
= get_version(version
, bl
);
84 bool old_available
= map
.get_available();
85 uint64_t old_gid
= map
.get_active_gid();
87 bufferlist::iterator p
= bl
.begin();
90 dout(4) << "active server: " << map
.active_addr
91 << "(" << map
.active_gid
<< ")" << dendl
;
93 ever_had_active_mgr
= get_value("ever_had_active_mgr");
98 first_seen_inactive
= utime_t();
100 first_seen_inactive
= ceph_clock_now();
106 || command_descs
.empty()
107 || (map
.get_available()
108 && (!old_available
|| old_gid
!= map
.get_active_gid()))) {
109 dout(4) << "mkfs or daemon transitioned to available, loading commands"
111 bufferlist loaded_commands
;
112 int r
= mon
->store
->get(command_descs_prefix
, "", loaded_commands
);
114 derr
<< "Failed to load mgr commands: " << cpp_strerror(r
) << dendl
;
116 auto p
= loaded_commands
.begin();
117 ::decode(command_descs
, p
);
122 // feed our pet MgrClient
123 mon
->mgr_client
.ms_dispatch(new MMgrMap(map
));
126 void MgrMonitor::create_pending()
131 if (map
.get_epoch() == 1 &&
132 command_descs
.empty() &&
133 pending_command_descs
.empty()) {
134 // we've been through the initial map and we haven't populated the
135 // command_descs vector. This likely means we came from kraken, where
136 // we wouldn't populate the vector, nor would we write it to disk, on
142 health_status_t
MgrMonitor::should_warn_about_mgr_down()
144 utime_t now
= ceph_clock_now();
146 // - we've ever had an active mgr, or
147 // - we have osds AND we've exceeded the grace period
148 // which means a new mon cluster and be HEALTH_OK indefinitely as long as
149 // no OSDs are ever created.
150 if (ever_had_active_mgr
||
151 (mon
->osdmon()->osdmap
.get_num_osds() > 0 &&
152 now
> mon
->monmap
->created
+ g_conf
->get_val
<int64_t>("mon_mgr_mkfs_grace"))) {
153 health_status_t level
= HEALTH_WARN
;
154 if (first_seen_inactive
!= utime_t() &&
155 now
- first_seen_inactive
> g_conf
->get_val
<int64_t>("mon_mgr_inactive_grace")) {
163 void MgrMonitor::encode_pending(MonitorDBStore::TransactionRef t
)
165 dout(10) << __func__
<< " " << pending_map
<< dendl
;
167 pending_map
.encode(bl
, mon
->get_quorum_con_features());
168 put_version(t
, pending_map
.epoch
, bl
);
169 put_last_committed(t
, pending_map
.epoch
);
171 for (auto& p
: pending_metadata
) {
172 dout(10) << __func__
<< " set metadata for " << p
.first
<< dendl
;
173 t
->put(MGR_METADATA_PREFIX
, p
.first
, p
.second
);
175 for (auto& name
: pending_metadata_rm
) {
176 dout(10) << __func__
<< " rm metadata for " << name
<< dendl
;
177 t
->erase(MGR_METADATA_PREFIX
, name
);
179 pending_metadata
.clear();
180 pending_metadata_rm
.clear();
182 health_check_map_t next
;
183 if (pending_map
.active_gid
== 0) {
184 auto level
= should_warn_about_mgr_down();
185 if (level
!= HEALTH_OK
) {
186 next
.add("MGR_DOWN", level
, "no active mgr");
188 dout(10) << __func__
<< " no health warning (never active and new cluster)"
192 put_value(t
, "ever_had_active_mgr", 1);
194 encode_health(next
, t
);
196 if (pending_command_descs
.size()) {
197 dout(4) << __func__
<< " encoding " << pending_command_descs
.size()
198 << " command_descs" << dendl
;
199 for (auto& p
: pending_command_descs
) {
200 p
.set_flag(MonCommand::FLAG_MGR
);
203 ::encode(pending_command_descs
, bl
);
204 t
->put(command_descs_prefix
, "", bl
);
205 pending_command_descs
.clear();
209 bool MgrMonitor::check_caps(MonOpRequestRef op
, const uuid_d
& fsid
)
212 MonSession
*session
= op
->get_session();
215 if (!session
->is_capable("mgr", MON_CAP_X
)) {
216 dout(1) << __func__
<< " insufficient caps " << session
->caps
<< dendl
;
219 if (fsid
!= mon
->monmap
->fsid
) {
220 dout(1) << __func__
<< " op fsid " << fsid
221 << " != " << mon
->monmap
->fsid
<< dendl
;
227 bool MgrMonitor::preprocess_query(MonOpRequestRef op
)
229 PaxosServiceMessage
*m
= static_cast<PaxosServiceMessage
*>(op
->get_req());
230 switch (m
->get_type()) {
232 return preprocess_beacon(op
);
233 case MSG_MON_COMMAND
:
235 return preprocess_command(op
);
237 catch (const bad_cmd_get
& e
) {
239 mon
->reply_command(op
, -EINVAL
, e
.what(), bl
, get_last_committed());
245 derr
<< "Unhandled message type " << m
->get_type() << dendl
;
250 bool MgrMonitor::prepare_update(MonOpRequestRef op
)
252 PaxosServiceMessage
*m
= static_cast<PaxosServiceMessage
*>(op
->get_req());
253 switch (m
->get_type()) {
255 return prepare_beacon(op
);
257 case MSG_MON_COMMAND
:
259 return prepare_command(op
);
261 catch (const bad_cmd_get
& e
) {
263 mon
->reply_command(op
, -EINVAL
, e
.what(), bl
, get_last_committed());
269 derr
<< "Unhandled message type " << m
->get_type() << dendl
;
276 class C_Updated
: public Context
{
280 C_Updated(MgrMonitor
*a
, MonOpRequestRef c
) :
282 void finish(int r
) override
{
285 } else if (r
== -ECANCELED
) {
286 mm
->mon
->no_reply(op
);
288 mm
->dispatch(op
); // try again
293 bool MgrMonitor::preprocess_beacon(MonOpRequestRef op
)
295 MMgrBeacon
*m
= static_cast<MMgrBeacon
*>(op
->get_req());
296 mon
->no_reply(op
); // we never reply to beacons
297 dout(4) << "beacon from " << m
->get_gid() << dendl
;
299 if (!check_caps(op
, m
->get_fsid())) {
300 // drop it on the floor
304 // always send this to the leader's prepare_beacon()
308 bool MgrMonitor::prepare_beacon(MonOpRequestRef op
)
310 MMgrBeacon
*m
= static_cast<MMgrBeacon
*>(op
->get_req());
311 dout(4) << "beacon from " << m
->get_gid() << dendl
;
313 // See if we are seeing same name, new GID for the active daemon
314 if (m
->get_name() == pending_map
.active_name
315 && m
->get_gid() != pending_map
.active_gid
)
317 dout(4) << "Active daemon restart (mgr." << m
->get_name() << ")" << dendl
;
318 mon
->clog
->info() << "Active manager daemon " << m
->get_name()
323 // See if we are seeing same name, new GID for any standbys
324 for (const auto &i
: pending_map
.standbys
) {
325 const StandbyInfo
&s
= i
.second
;
326 if (s
.name
== m
->get_name() && s
.gid
!= m
->get_gid()) {
327 dout(4) << "Standby daemon restart (mgr." << m
->get_name() << ")" << dendl
;
328 mon
->clog
->debug() << "Standby manager daemon " << m
->get_name()
330 drop_standby(i
.first
);
335 last_beacon
[m
->get_gid()] = ceph::coarse_mono_clock::now();
337 // Track whether we modified pending_map
338 bool updated
= false;
340 if (pending_map
.active_gid
== m
->get_gid()) {
341 if (pending_map
.services
!= m
->get_services()) {
342 dout(4) << "updated services from mgr." << m
->get_name()
343 << ": " << m
->get_services() << dendl
;
344 pending_map
.services
= m
->get_services();
348 // A beacon from the currently active daemon
349 if (pending_map
.active_addr
!= m
->get_server_addr()) {
350 dout(4) << "learned address " << m
->get_server_addr()
351 << " (was " << pending_map
.active_addr
<< ")" << dendl
;
352 pending_map
.active_addr
= m
->get_server_addr();
356 if (pending_map
.get_available() != m
->get_available()) {
357 dout(4) << "available " << m
->get_gid() << dendl
;
358 mon
->clog
->info() << "Manager daemon " << pending_map
.active_name
359 << " is now available";
361 // This beacon should include command descriptions
362 pending_command_descs
= m
->get_command_descs();
363 if (pending_command_descs
.empty()) {
364 // This should not happen, but it also isn't fatal: we just
365 // won't successfully update our list of commands.
366 dout(4) << "First available beacon from " << pending_map
.active_name
367 << "(" << m
->get_gid() << ") does not include command descs"
370 dout(4) << "First available beacon from " << pending_map
.active_name
371 << "(" << m
->get_gid() << ") includes "
372 << pending_command_descs
.size() << " command descs" << dendl
;
375 pending_map
.available
= m
->get_available();
378 if (pending_map
.available_modules
!= m
->get_available_modules()) {
379 dout(4) << "available_modules " << m
->get_available_modules()
380 << " (was " << pending_map
.available_modules
<< ")" << dendl
;
381 pending_map
.available_modules
= m
->get_available_modules();
384 } else if (pending_map
.active_gid
== 0) {
385 // There is no currently active daemon, select this one.
386 if (pending_map
.standbys
.count(m
->get_gid())) {
387 drop_standby(m
->get_gid(), false);
389 dout(4) << "selecting new active " << m
->get_gid()
390 << " " << m
->get_name()
391 << " (was " << pending_map
.active_gid
<< " "
392 << pending_map
.active_name
<< ")" << dendl
;
393 pending_map
.active_gid
= m
->get_gid();
394 pending_map
.active_name
= m
->get_name();
395 pending_map
.available_modules
= m
->get_available_modules();
396 ::encode(m
->get_metadata(), pending_metadata
[m
->get_name()]);
397 pending_metadata_rm
.erase(m
->get_name());
399 mon
->clog
->info() << "Activating manager daemon "
400 << pending_map
.active_name
;
404 if (pending_map
.standbys
.count(m
->get_gid()) > 0) {
405 dout(10) << "from existing standby " << m
->get_gid() << dendl
;
406 if (pending_map
.standbys
[m
->get_gid()].available_modules
!=
407 m
->get_available_modules()) {
408 dout(10) << "existing standby " << m
->get_gid() << " available_modules "
409 << m
->get_available_modules() << " (was "
410 << pending_map
.standbys
[m
->get_gid()].available_modules
<< ")"
412 pending_map
.standbys
[m
->get_gid()].available_modules
=
413 m
->get_available_modules();
417 dout(10) << "new standby " << m
->get_gid() << dendl
;
418 mon
->clog
->debug() << "Standby manager daemon " << m
->get_name()
420 pending_map
.standbys
[m
->get_gid()] = {m
->get_gid(), m
->get_name(),
421 m
->get_available_modules()};
422 ::encode(m
->get_metadata(), pending_metadata
[m
->get_name()]);
423 pending_metadata_rm
.erase(m
->get_name());
429 dout(4) << "updating map" << dendl
;
430 wait_for_finished_proposal(op
, new C_Updated(this, op
));
432 dout(10) << "no change" << dendl
;
438 void MgrMonitor::check_subs()
440 const std::string type
= "mgrmap";
441 if (mon
->session_map
.subs
.count(type
) == 0)
443 for (auto sub
: *(mon
->session_map
.subs
[type
])) {
448 void MgrMonitor::check_sub(Subscription
*sub
)
450 if (sub
->type
== "mgrmap") {
451 if (sub
->next
<= map
.get_epoch()) {
452 dout(20) << "Sending map to subscriber " << sub
->session
->con
453 << " " << sub
->session
->con
->get_peer_addr() << dendl
;
454 sub
->session
->con
->send_message(new MMgrMap(map
));
456 mon
->session_map
.remove_sub(sub
);
458 sub
->next
= map
.get_epoch() + 1;
462 assert(sub
->type
== "mgrdigest");
463 if (sub
->next
== 0) {
464 // new registration; cancel previous timer
467 if (digest_event
== nullptr) {
474 * Handle digest subscriptions separately (outside of check_sub) because
475 * they are going to be periodic rather than version-driven.
477 void MgrMonitor::send_digests()
481 const std::string type
= "mgrdigest";
482 if (mon
->session_map
.subs
.count(type
) == 0)
486 // if paxos is currently not active, don't send a digest but reenable timer
489 dout(10) << __func__
<< dendl
;
491 for (auto sub
: *(mon
->session_map
.subs
[type
])) {
492 dout(10) << __func__
<< " sending digest to subscriber " << sub
->session
->con
493 << " " << sub
->session
->con
->get_peer_addr() << dendl
;
494 MMgrDigest
*mdigest
= new MMgrDigest
;
497 mon
->get_health_status(true, &f
, nullptr, nullptr, nullptr);
498 f
.flush(mdigest
->health_json
);
501 std::ostringstream ss
;
502 mon
->get_mon_status(&f
, ss
);
503 f
.flush(mdigest
->mon_status_json
);
506 sub
->session
->con
->send_message(mdigest
);
510 digest_event
= mon
->timer
.add_event_after(
511 g_conf
->get_val
<int64_t>("mon_mgr_digest_period"),
512 new C_MonContext(mon
, [this](int) {
517 void MgrMonitor::cancel_timer()
520 mon
->timer
.cancel_event(digest_event
);
521 digest_event
= nullptr;
525 void MgrMonitor::on_active()
527 if (mon
->is_leader()) {
528 mon
->clog
->debug() << "mgrmap e" << map
.epoch
<< ": " << map
;
532 void MgrMonitor::get_health(
533 list
<pair
<health_status_t
,string
> >& summary
,
534 list
<pair
<health_status_t
,string
> > *detail
,
535 CephContext
*cct
) const
537 // start mgr warnings as soon as the mons and osds are all upgraded,
538 // but before the require_luminous osdmap flag is set. this way the
539 // user gets some warning before the osd flag is set and mgr is
540 // actually *required*.
541 if (!mon
->monmap
->get_required_features().contains_all(
542 ceph::features::mon::FEATURE_LUMINOUS
) ||
543 !HAVE_FEATURE(mon
->osdmon()->osdmap
.get_up_osd_features(),
548 if (map
.active_gid
== 0) {
549 auto level
= HEALTH_WARN
;
550 // do not escalate to ERR if they are still upgrading to jewel.
551 if (mon
->osdmon()->osdmap
.require_osd_release
>= CEPH_RELEASE_LUMINOUS
) {
552 utime_t now
= ceph_clock_now();
553 if (first_seen_inactive
!= utime_t() &&
554 now
- first_seen_inactive
> g_conf
->get_val
<int64_t>("mon_mgr_inactive_grace")) {
558 summary
.push_back(make_pair(level
, "no active mgr"));
562 void MgrMonitor::tick()
564 if (!is_active() || !mon
->is_leader())
567 const auto now
= ceph::coarse_mono_clock::now();
569 const auto mgr_beacon_grace
= std::chrono::seconds(
570 g_conf
->get_val
<int64_t>("mon_mgr_beacon_grace"));
572 // Note that this is the mgr daemon's tick period, not ours (the
573 // beacon is sent with this period).
574 const auto mgr_tick_period
= std::chrono::seconds(
575 g_conf
->get_val
<int64_t>("mgr_tick_period"));
577 if (last_tick
!= ceph::coarse_mono_clock::time_point::min()
578 && (now
- last_tick
> (mgr_beacon_grace
- mgr_tick_period
))) {
579 // This case handles either local slowness (calls being delayed
580 // for whatever reason) or cluster election slowness (a long gap
581 // between calls while an election happened)
582 dout(4) << __func__
<< ": resetting beacon timeouts due to mon delay "
583 "(slow election?) of " << now
- last_tick
<< " seconds" << dendl
;
584 for (auto &i
: last_beacon
) {
591 // Populate any missing beacons (i.e. no beacon since MgrMonitor
592 // instantiation) with the current time, so that they will
593 // eventually look laggy if they fail to give us a beacon.
594 if (pending_map
.active_gid
!= 0
595 && last_beacon
.count(pending_map
.active_gid
) == 0) {
596 last_beacon
[pending_map
.active_gid
] = now
;
598 for (auto s
: pending_map
.standbys
) {
599 if (last_beacon
.count(s
.first
) == 0) {
600 last_beacon
[s
.first
] = now
;
604 // Cull standbys first so that any remaining standbys
605 // will be eligible to take over from the active if we cull him.
606 std::list
<uint64_t> dead_standbys
;
607 const auto cutoff
= now
- mgr_beacon_grace
;
608 for (const auto &i
: pending_map
.standbys
) {
609 auto last_beacon_time
= last_beacon
.at(i
.first
);
610 if (last_beacon_time
< cutoff
) {
611 dead_standbys
.push_back(i
.first
);
615 bool propose
= false;
617 for (auto i
: dead_standbys
) {
618 dout(4) << "Dropping laggy standby " << i
<< dendl
;
623 if (pending_map
.active_gid
!= 0
624 && last_beacon
.at(pending_map
.active_gid
) < cutoff
) {
625 const std::string old_active_name
= pending_map
.active_name
;
628 dout(4) << "Dropping active" << pending_map
.active_gid
<< dendl
;
629 if (promote_standby()) {
630 dout(4) << "Promoted standby " << pending_map
.active_gid
<< dendl
;
631 mon
->clog
->info() << "Manager daemon " << old_active_name
632 << " is unresponsive, replacing it with standby"
633 << " daemon " << pending_map
.active_name
;
635 dout(4) << "Active is laggy but have no standbys to replace it" << dendl
;
636 mon
->clog
->info() << "Manager daemon " << old_active_name
637 << " is unresponsive. No standby daemons available.";
639 } else if (pending_map
.active_gid
== 0) {
640 if (promote_standby()) {
641 dout(4) << "Promoted standby " << pending_map
.active_gid
<< dendl
;
642 mon
->clog
->info() << "Activating manager daemon "
643 << pending_map
.active_name
;
648 if (!pending_map
.available
&&
649 !ever_had_active_mgr
&&
650 should_warn_about_mgr_down() != HEALTH_OK
) {
651 dout(10) << " exceeded mon_mgr_mkfs_grace "
652 << g_conf
->get_val
<int64_t>("mon_mgr_mkfs_grace")
653 << " seconds" << dendl
;
662 void MgrMonitor::on_restart()
664 // Clear out the leader-specific state.
666 last_tick
= ceph::coarse_mono_clock::now();
670 bool MgrMonitor::promote_standby()
672 assert(pending_map
.active_gid
== 0);
673 if (pending_map
.standbys
.size()) {
674 // Promote a replacement (arbitrary choice of standby)
675 auto replacement_gid
= pending_map
.standbys
.begin()->first
;
676 pending_map
.active_gid
= replacement_gid
;
677 pending_map
.active_name
= pending_map
.standbys
.at(replacement_gid
).name
;
678 pending_map
.available
= false;
679 pending_map
.active_addr
= entity_addr_t();
681 drop_standby(replacement_gid
, false);
689 void MgrMonitor::drop_active()
691 if (last_beacon
.count(pending_map
.active_gid
) > 0) {
692 last_beacon
.erase(pending_map
.active_gid
);
695 pending_metadata_rm
.insert(pending_map
.active_name
);
696 pending_metadata
.erase(pending_map
.active_name
);
697 pending_map
.active_name
= "";
698 pending_map
.active_gid
= 0;
699 pending_map
.available
= false;
700 pending_map
.active_addr
= entity_addr_t();
701 pending_map
.services
.clear();
703 // So that when new active mgr subscribes to mgrdigest, it will
704 // get an immediate response instead of waiting for next timer
708 void MgrMonitor::drop_standby(uint64_t gid
, bool drop_meta
)
711 pending_metadata_rm
.insert(pending_map
.standbys
[gid
].name
);
712 pending_metadata
.erase(pending_map
.standbys
[gid
].name
);
714 pending_map
.standbys
.erase(gid
);
715 if (last_beacon
.count(gid
) > 0) {
716 last_beacon
.erase(gid
);
720 bool MgrMonitor::preprocess_command(MonOpRequestRef op
)
722 MMonCommand
*m
= static_cast<MMonCommand
*>(op
->get_req());
723 std::stringstream ss
;
726 std::map
<std::string
, cmd_vartype
> cmdmap
;
727 if (!cmdmap_from_json(m
->cmd
, &cmdmap
, ss
)) {
728 string rs
= ss
.str();
729 mon
->reply_command(op
, -EINVAL
, rs
, rdata
, get_last_committed());
733 MonSession
*session
= m
->get_session();
735 mon
->reply_command(op
, -EACCES
, "access denied", rdata
,
736 get_last_committed());
741 cmd_getval_throws(g_ceph_context
, cmdmap
, "format", format
, string("json-pretty"));
742 boost::scoped_ptr
<Formatter
> f(Formatter::create(format
));
745 cmd_getval_throws(g_ceph_context
, cmdmap
, "prefix", prefix
);
748 if (prefix
== "mgr dump") {
750 cmd_getval_throws(g_ceph_context
, cmdmap
, "epoch", epoch
, (int64_t)map
.get_epoch());
751 if (epoch
== (int64_t)map
.get_epoch()) {
752 f
->dump_object("mgrmap", map
);
755 int err
= get_version(epoch
, bl
);
756 if (err
== -ENOENT
) {
758 ss
<< "there is no map for epoch " << epoch
;
764 f
->dump_object("mgrmap", m
);
767 } else if (prefix
== "mgr module ls") {
768 f
->open_object_section("modules");
770 f
->open_array_section("enabled_modules");
771 for (auto& p
: map
.modules
) {
772 f
->dump_string("module", p
);
775 f
->open_array_section("disabled_modules");
776 for (auto& p
: map
.available_modules
) {
777 if (map
.modules
.count(p
) == 0) {
778 f
->dump_string("module", p
);
785 } else if (prefix
== "mgr services") {
786 f
->open_object_section("services");
787 for (const auto &i
: map
.services
) {
788 f
->dump_string(i
.first
.c_str(), i
.second
);
792 } else if (prefix
== "mgr metadata") {
794 cmd_getval_throws(g_ceph_context
, cmdmap
, "id", name
);
795 if (name
.size() > 0 && !map
.have_name(name
)) {
796 ss
<< "mgr." << name
<< " does not exist";
801 cmd_getval_throws(g_ceph_context
, cmdmap
, "format", format
);
802 boost::scoped_ptr
<Formatter
> f(Formatter::create(format
, "json-pretty", "json-pretty"));
804 f
->open_object_section("mgr_metadata");
805 f
->dump_string("id", name
);
806 r
= dump_metadata(name
, f
.get(), &ss
);
812 f
->open_array_section("mgr_metadata");
813 for (auto& i
: map
.get_all_names()) {
814 f
->open_object_section("mgr");
815 f
->dump_string("id", i
);
816 r
= dump_metadata(i
, f
.get(), NULL
);
817 if (r
== -EINVAL
|| r
== -ENOENT
) {
818 // Drop error, continue to get other daemons' metadata
819 dout(4) << "No metadata for mgr." << i
<< dendl
;
830 } else if (prefix
== "mgr versions") {
832 f
.reset(Formatter::create("json-pretty"));
833 count_metadata("ceph_version", f
.get());
836 } else if (prefix
== "mgr count-metadata") {
838 f
.reset(Formatter::create("json-pretty"));
840 cmd_getval_throws(g_ceph_context
, cmdmap
, "property", field
);
841 count_metadata(field
, f
.get());
851 mon
->reply_command(op
, r
, rs
, rdata
, get_last_committed());
855 bool MgrMonitor::prepare_command(MonOpRequestRef op
)
857 MMonCommand
*m
= static_cast<MMonCommand
*>(op
->get_req());
859 std::stringstream ss
;
862 std::map
<std::string
, cmd_vartype
> cmdmap
;
863 if (!cmdmap_from_json(m
->cmd
, &cmdmap
, ss
)) {
864 string rs
= ss
.str();
865 mon
->reply_command(op
, -EINVAL
, rs
, rdata
, get_last_committed());
869 MonSession
*session
= m
->get_session();
871 mon
->reply_command(op
, -EACCES
, "access denied", rdata
, get_last_committed());
876 cmd_getval_throws(g_ceph_context
, cmdmap
, "format", format
, string("plain"));
877 boost::scoped_ptr
<Formatter
> f(Formatter::create(format
));
880 cmd_getval_throws(g_ceph_context
, cmdmap
, "prefix", prefix
);
884 if (prefix
== "mgr fail") {
886 cmd_getval_throws(g_ceph_context
, cmdmap
, "who", who
);
889 uint64_t gid
= strict_strtol(who
.c_str(), 10, &err
);
890 bool changed
= false;
892 // Does not parse as a gid, treat it as a name
893 if (pending_map
.active_name
== who
) {
898 for (const auto &i
: pending_map
.standbys
) {
899 if (i
.second
.name
== who
) {
908 ss
<< "Daemon not found '" << who
<< "', already failed?";
912 if (pending_map
.active_gid
== gid
) {
915 } else if (pending_map
.standbys
.count(gid
) > 0) {
919 ss
<< "Daemon not found '" << gid
<< "', already failed?";
923 if (changed
&& pending_map
.active_gid
== 0) {
926 } else if (prefix
== "mgr module enable") {
928 cmd_getval_throws(g_ceph_context
, cmdmap
, "module", module
);
929 if (module
.empty()) {
934 cmd_getval_throws(g_ceph_context
, cmdmap
, "force", force
);
935 if (!pending_map
.all_support_module(module
) &&
936 force
!= "--force") {
937 ss
<< "all mgr daemons do not support module '" << module
<< "', pass "
938 << "--force to force enablement";
942 pending_map
.modules
.insert(module
);
943 } else if (prefix
== "mgr module disable") {
945 cmd_getval_throws(g_ceph_context
, cmdmap
, "module", module
);
946 if (module
.empty()) {
950 pending_map
.modules
.erase(module
);
952 ss
<< "Command '" << prefix
<< "' not implemented!";
957 dout(4) << __func__
<< " done, r=" << r
<< dendl
;
958 /* Compose response */
963 // success.. delay reply
964 wait_for_finished_proposal(op
, new Monitor::C_Command(mon
, op
, r
, rs
,
965 get_last_committed() + 1));
969 mon
->reply_command(op
, r
, rs
, rdata
, get_last_committed());
974 void MgrMonitor::init()
976 if (digest_event
== nullptr) {
977 send_digests(); // To get it to schedule its own event
981 void MgrMonitor::on_shutdown()
986 int MgrMonitor::load_metadata(const string
& name
, std::map
<string
, string
>& m
,
990 int r
= mon
->store
->get(MGR_METADATA_PREFIX
, name
, bl
);
994 bufferlist::iterator p
= bl
.begin();
997 catch (buffer::error
& e
) {
999 *err
<< "mgr." << name
<< " metadata is corrupt";
1005 void MgrMonitor::count_metadata(const string
& field
, std::map
<string
,int> *out
)
1007 std::set
<string
> ls
= map
.get_all_names();
1008 for (auto& name
: ls
) {
1009 std::map
<string
,string
> meta
;
1010 load_metadata(name
, meta
, nullptr);
1011 auto p
= meta
.find(field
);
1012 if (p
== meta
.end()) {
1013 (*out
)["unknown"]++;
1015 (*out
)[p
->second
]++;
1020 void MgrMonitor::count_metadata(const string
& field
, Formatter
*f
)
1022 std::map
<string
,int> by_val
;
1023 count_metadata(field
, &by_val
);
1024 f
->open_object_section(field
.c_str());
1025 for (auto& p
: by_val
) {
1026 f
->dump_int(p
.first
.c_str(), p
.second
);
1031 int MgrMonitor::dump_metadata(const string
& name
, Formatter
*f
, ostream
*err
)
1033 std::map
<string
,string
> m
;
1034 if (int r
= load_metadata(name
, m
, err
))
1037 f
->dump_string(p
.first
.c_str(), p
.second
);
1042 const std::vector
<MonCommand
> &MgrMonitor::get_command_descs() const
1044 if (command_descs
.empty()) {
1045 // must have just upgraded; fallback to static commands
1046 return mgr_commands
;
1048 return command_descs
;