]> git.proxmox.com Git - ceph.git/blame - ceph/src/mon/MgrMonitor.cc
update sources to v12.1.3
[ceph.git] / ceph / src / mon / MgrMonitor.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2016 John Spray <john.spray@redhat.com>
7 *
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.
12 */
13
224ce89b
WB
14#include <boost/tokenizer.hpp>
15
7c673cae
FG
16#include "messages/MMgrBeacon.h"
17#include "messages/MMgrMap.h"
18#include "messages/MMgrDigest.h"
19
31f18b77 20#include "PGStatService.h"
7c673cae
FG
21#include "include/stringify.h"
22#include "mgr/MgrContext.h"
c07f9fc5 23#include "mgr/mgr_commands.h"
7c673cae
FG
24#include "OSDMonitor.h"
25
26#include "MgrMonitor.h"
27
c07f9fc5
FG
28#define MGR_METADATA_PREFIX "mgr_metadata"
29
7c673cae
FG
30#define dout_subsys ceph_subsys_mon
31#undef dout_prefix
32#define dout_prefix _prefix(_dout, mon, map)
33static 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() << " ";
38}
39
c07f9fc5
FG
40// Prefix for mon store of active mgr's command descriptions
41const static std::string command_descs_prefix = "mgr_command_descs";
42
31f18b77 43
7c673cae
FG
44void MgrMonitor::create_initial()
45{
224ce89b
WB
46 boost::tokenizer<> tok(g_conf->mgr_initial_modules);
47 for (auto& m : tok) {
48 pending_map.modules.insert(m);
49 }
c07f9fc5
FG
50 pending_command_descs = mgr_commands;
51 dout(10) << __func__ << " initial modules " << pending_map.modules
52 << ", " << pending_command_descs.size() << " commands"
53 << dendl;
7c673cae
FG
54}
55
56void MgrMonitor::update_from_paxos(bool *need_bootstrap)
57{
58 version_t version = get_last_committed();
59 if (version != map.epoch) {
60 dout(4) << "loading version " << version << dendl;
61
62 bufferlist bl;
63 int err = get_version(version, bl);
64 assert(err == 0);
65
c07f9fc5
FG
66 bool old_available = map.get_available();
67 uint64_t old_gid = map.get_active_gid();
68
7c673cae
FG
69 bufferlist::iterator p = bl.begin();
70 map.decode(p);
71
72 dout(4) << "active server: " << map.active_addr
73 << "(" << map.active_gid << ")" << dendl;
74
224ce89b
WB
75 ever_had_active_mgr = get_value("ever_had_active_mgr");
76
77 load_health();
78
7c673cae
FG
79 if (map.available) {
80 first_seen_inactive = utime_t();
81 } else {
82 first_seen_inactive = ceph_clock_now();
83 }
84
85 check_subs();
c07f9fc5
FG
86
87 if (version == 1
88 || (map.get_available()
89 && (!old_available || old_gid != map.get_active_gid()))) {
90 dout(4) << "mkfs or daemon transitioned to available, loading commands"
91 << dendl;
92 bufferlist loaded_commands;
93 int r = mon->store->get(command_descs_prefix, "", loaded_commands);
94 if (r < 0) {
95 derr << "Failed to load mgr commands: " << cpp_strerror(r) << dendl;
96 } else {
97 auto p = loaded_commands.begin();
98 ::decode(command_descs, p);
99 }
100 }
7c673cae
FG
101 }
102
103 // feed our pet MgrClient
104 mon->mgr_client.ms_dispatch(new MMgrMap(map));
105}
106
107void MgrMonitor::create_pending()
108{
109 pending_map = map;
110 pending_map.epoch++;
111}
112
224ce89b
WB
113health_status_t MgrMonitor::should_warn_about_mgr_down()
114{
115 utime_t now = ceph_clock_now();
116 // we warn if
117 // - we've ever had an active mgr, or
118 // - we have osds AND we've exceeded the grace period
119 // which means a new mon cluster and be HEALTH_OK indefinitely as long as
120 // no OSDs are ever created.
121 if (ever_had_active_mgr ||
122 (mon->osdmon()->osdmap.get_num_osds() > 0 &&
123 now > mon->monmap->created + g_conf->mon_mgr_mkfs_grace)) {
124 health_status_t level = HEALTH_WARN;
125 if (first_seen_inactive != utime_t() &&
126 now - first_seen_inactive > g_conf->mon_mgr_inactive_grace) {
127 level = HEALTH_ERR;
128 }
129 return level;
130 }
131 return HEALTH_OK;
132}
133
7c673cae
FG
134void MgrMonitor::encode_pending(MonitorDBStore::TransactionRef t)
135{
136 dout(10) << __func__ << " " << pending_map << dendl;
137 bufferlist bl;
138 pending_map.encode(bl, mon->get_quorum_con_features());
139 put_version(t, pending_map.epoch, bl);
140 put_last_committed(t, pending_map.epoch);
224ce89b 141
c07f9fc5
FG
142 for (auto& p : pending_metadata) {
143 dout(10) << __func__ << " set metadata for " << p.first << dendl;
144 t->put(MGR_METADATA_PREFIX, p.first, p.second);
145 }
146 for (auto& name : pending_metadata_rm) {
147 dout(10) << __func__ << " rm metadata for " << name << dendl;
148 t->erase(MGR_METADATA_PREFIX, name);
149 }
150 pending_metadata.clear();
151 pending_metadata_rm.clear();
152
224ce89b
WB
153 health_check_map_t next;
154 if (pending_map.active_gid == 0) {
155 auto level = should_warn_about_mgr_down();
156 if (level != HEALTH_OK) {
157 next.add("MGR_DOWN", level, "no active mgr");
158 } else {
159 dout(10) << __func__ << " no health warning (never active and new cluster)"
160 << dendl;
161 }
162 } else {
163 put_value(t, "ever_had_active_mgr", 1);
164 }
165 encode_health(next, t);
c07f9fc5
FG
166
167 if (pending_command_descs.size()) {
168 dout(4) << __func__ << " encoding " << pending_command_descs.size()
169 << " command_descs" << dendl;
170 for (auto& p : pending_command_descs) {
171 p.set_flag(MonCommand::FLAG_MGR);
172 }
173 bufferlist bl;
174 ::encode(pending_command_descs, bl);
175 t->put(command_descs_prefix, "", bl);
176 pending_command_descs.clear();
177 }
7c673cae
FG
178}
179
180bool MgrMonitor::check_caps(MonOpRequestRef op, const uuid_d& fsid)
181{
182 // check permissions
183 MonSession *session = op->get_session();
184 if (!session)
185 return false;
186 if (!session->is_capable("mgr", MON_CAP_X)) {
187 dout(1) << __func__ << " insufficient caps " << session->caps << dendl;
188 return false;
189 }
190 if (fsid != mon->monmap->fsid) {
191 dout(1) << __func__ << " op fsid " << fsid
192 << " != " << mon->monmap->fsid << dendl;
193 return false;
194 }
195 return true;
196}
197
198bool MgrMonitor::preprocess_query(MonOpRequestRef op)
199{
200 PaxosServiceMessage *m = static_cast<PaxosServiceMessage*>(op->get_req());
201 switch (m->get_type()) {
202 case MSG_MGR_BEACON:
203 return preprocess_beacon(op);
204 case MSG_MON_COMMAND:
205 return preprocess_command(op);
206 default:
207 mon->no_reply(op);
208 derr << "Unhandled message type " << m->get_type() << dendl;
209 return true;
210 }
211}
212
213bool MgrMonitor::prepare_update(MonOpRequestRef op)
214{
215 PaxosServiceMessage *m = static_cast<PaxosServiceMessage*>(op->get_req());
216 switch (m->get_type()) {
217 case MSG_MGR_BEACON:
218 return prepare_beacon(op);
219
220 case MSG_MON_COMMAND:
221 return prepare_command(op);
222
223 default:
224 mon->no_reply(op);
225 derr << "Unhandled message type " << m->get_type() << dendl;
226 return true;
227 }
228}
229
230
231
232class C_Updated : public Context {
233 MgrMonitor *mm;
234 MonOpRequestRef op;
235public:
236 C_Updated(MgrMonitor *a, MonOpRequestRef c) :
237 mm(a), op(c) {}
238 void finish(int r) override {
239 if (r >= 0) {
240 // Success
241 } else if (r == -ECANCELED) {
242 mm->mon->no_reply(op);
243 } else {
244 mm->dispatch(op); // try again
245 }
246 }
247};
248
249bool MgrMonitor::preprocess_beacon(MonOpRequestRef op)
250{
251 MMgrBeacon *m = static_cast<MMgrBeacon*>(op->get_req());
252 dout(4) << "beacon from " << m->get_gid() << dendl;
253
254 if (!check_caps(op, m->get_fsid())) {
255 // drop it on the floor
256 return true;
257 }
258
259 // always send this to the leader's prepare_beacon()
260 return false;
261}
262
263bool MgrMonitor::prepare_beacon(MonOpRequestRef op)
264{
265 MMgrBeacon *m = static_cast<MMgrBeacon*>(op->get_req());
266 dout(4) << "beacon from " << m->get_gid() << dendl;
267
268 // See if we are seeing same name, new GID for the active daemon
269 if (m->get_name() == pending_map.active_name
270 && m->get_gid() != pending_map.active_gid)
271 {
272 dout(4) << "Active daemon restart (mgr." << m->get_name() << ")" << dendl;
224ce89b
WB
273 mon->clog->info() << "Active manager daemon " << m->get_name()
274 << " restarted";
7c673cae
FG
275 drop_active();
276 }
277
278 // See if we are seeing same name, new GID for any standbys
279 for (const auto &i : pending_map.standbys) {
280 const StandbyInfo &s = i.second;
281 if (s.name == m->get_name() && s.gid != m->get_gid()) {
282 dout(4) << "Standby daemon restart (mgr." << m->get_name() << ")" << dendl;
224ce89b
WB
283 mon->clog->debug() << "Standby manager daemon " << m->get_name()
284 << " restarted";
7c673cae
FG
285 drop_standby(i.first);
286 break;
287 }
288 }
289
31f18b77 290 last_beacon[m->get_gid()] = ceph::coarse_mono_clock::now();
7c673cae
FG
291
292 // Track whether we modified pending_map
293 bool updated = false;
294
295 if (pending_map.active_gid == m->get_gid()) {
296 // A beacon from the currently active daemon
297 if (pending_map.active_addr != m->get_server_addr()) {
298 dout(4) << "learned address " << m->get_server_addr()
299 << " (was " << pending_map.active_addr << ")" << dendl;
300 pending_map.active_addr = m->get_server_addr();
301 updated = true;
302 }
303
304 if (pending_map.get_available() != m->get_available()) {
305 dout(4) << "available " << m->get_gid() << dendl;
224ce89b
WB
306 mon->clog->info() << "Manager daemon " << pending_map.active_name
307 << " is now available";
c07f9fc5
FG
308
309 // This beacon should include command descriptions
310 pending_command_descs = m->get_command_descs();
311 if (pending_command_descs.empty()) {
312 // This should not happen, but it also isn't fatal: we just
313 // won't successfully update our list of commands.
314 dout(4) << "First available beacon from " << pending_map.active_name
315 << "(" << m->get_gid() << ") does not include command descs"
316 << dendl;
317 } else {
318 dout(4) << "First available beacon from " << pending_map.active_name
319 << "(" << m->get_gid() << ") includes "
320 << pending_command_descs.size() << " command descs" << dendl;
321 }
322
7c673cae
FG
323 pending_map.available = m->get_available();
324 updated = true;
325 }
224ce89b
WB
326 if (pending_map.available_modules != m->get_available_modules()) {
327 dout(4) << "available_modules " << m->get_available_modules()
328 << " (was " << pending_map.available_modules << ")" << dendl;
329 pending_map.available_modules = m->get_available_modules();
330 updated = true;
331 }
7c673cae
FG
332 } else if (pending_map.active_gid == 0) {
333 // There is no currently active daemon, select this one.
334 if (pending_map.standbys.count(m->get_gid())) {
335 drop_standby(m->get_gid());
336 }
337 dout(4) << "selecting new active " << m->get_gid()
338 << " " << m->get_name()
339 << " (was " << pending_map.active_gid << " "
340 << pending_map.active_name << ")" << dendl;
341 pending_map.active_gid = m->get_gid();
342 pending_map.active_name = m->get_name();
224ce89b 343 pending_map.available_modules = m->get_available_modules();
c07f9fc5
FG
344 ::encode(m->get_metadata(), pending_metadata[m->get_name()]);
345 pending_metadata_rm.erase(m->get_name());
224ce89b
WB
346
347 mon->clog->info() << "Activating manager daemon "
348 << pending_map.active_name;
7c673cae
FG
349
350 updated = true;
351 } else {
352 if (pending_map.standbys.count(m->get_gid()) > 0) {
353 dout(10) << "from existing standby " << m->get_gid() << dendl;
224ce89b
WB
354 if (pending_map.standbys[m->get_gid()].available_modules !=
355 m->get_available_modules()) {
356 dout(10) << "existing standby " << m->get_gid() << " available_modules "
357 << m->get_available_modules() << " (was "
358 << pending_map.standbys[m->get_gid()].available_modules << ")"
359 << dendl;
360 pending_map.standbys[m->get_gid()].available_modules =
361 m->get_available_modules();
362 updated = true;
363 }
7c673cae
FG
364 } else {
365 dout(10) << "new standby " << m->get_gid() << dendl;
224ce89b
WB
366 mon->clog->debug() << "Standby manager daemon " << m->get_name()
367 << " started";
c07f9fc5
FG
368 pending_map.standbys[m->get_gid()] = {m->get_gid(), m->get_name(),
369 m->get_available_modules()};
370 ::encode(m->get_metadata(), pending_metadata[m->get_name()]);
371 pending_metadata_rm.erase(m->get_name());
7c673cae
FG
372 updated = true;
373 }
374 }
375
376 if (updated) {
377 dout(4) << "updating map" << dendl;
378 wait_for_finished_proposal(op, new C_Updated(this, op));
379 } else {
380 dout(10) << "no change" << dendl;
381 }
382
383 return updated;
384}
385
386void MgrMonitor::check_subs()
387{
388 const std::string type = "mgrmap";
389 if (mon->session_map.subs.count(type) == 0)
390 return;
391 for (auto sub : *(mon->session_map.subs[type])) {
392 check_sub(sub);
393 }
394}
395
396void MgrMonitor::check_sub(Subscription *sub)
397{
398 if (sub->type == "mgrmap") {
399 if (sub->next <= map.get_epoch()) {
224ce89b
WB
400 dout(20) << "Sending map to subscriber " << sub->session->con
401 << " " << sub->session->con->get_peer_addr() << dendl;
7c673cae
FG
402 sub->session->con->send_message(new MMgrMap(map));
403 if (sub->onetime) {
404 mon->session_map.remove_sub(sub);
405 } else {
406 sub->next = map.get_epoch() + 1;
407 }
408 }
409 } else {
410 assert(sub->type == "mgrdigest");
c07f9fc5
FG
411 if (sub->next == 0) {
412 // new registration; cancel previous timer
413 cancel_timer();
414 }
31f18b77 415 if (digest_event == nullptr) {
7c673cae
FG
416 send_digests();
417 }
418 }
419}
420
421/**
422 * Handle digest subscriptions separately (outside of check_sub) because
423 * they are going to be periodic rather than version-driven.
424 */
425void MgrMonitor::send_digests()
426{
31f18b77
FG
427 cancel_timer();
428
429 if (!is_active()) {
430 return;
431 }
224ce89b 432 dout(10) << __func__ << dendl;
7c673cae
FG
433
434 const std::string type = "mgrdigest";
435 if (mon->session_map.subs.count(type) == 0)
436 return;
437
438 for (auto sub : *(mon->session_map.subs[type])) {
224ce89b
WB
439 dout(10) << __func__ << " sending digest to subscriber " << sub->session->con
440 << " " << sub->session->con->get_peer_addr() << dendl;
7c673cae
FG
441 MMgrDigest *mdigest = new MMgrDigest;
442
443 JSONFormatter f;
224ce89b 444 mon->get_health_status(true, &f, nullptr, nullptr, nullptr);
7c673cae
FG
445 f.flush(mdigest->health_json);
446 f.reset();
447
448 std::ostringstream ss;
449 mon->get_mon_status(&f, ss);
450 f.flush(mdigest->mon_status_json);
451 f.reset();
452
453 sub->session->con->send_message(mdigest);
454 }
455
31f18b77 456 digest_event = new C_MonContext(mon, [this](int){
7c673cae
FG
457 send_digests();
458 });
31f18b77
FG
459 mon->timer.add_event_after(g_conf->mon_mgr_digest_period, digest_event);
460}
461
462void MgrMonitor::cancel_timer()
463{
464 if (digest_event) {
465 mon->timer.cancel_event(digest_event);
466 digest_event = nullptr;
467 }
7c673cae
FG
468}
469
470void MgrMonitor::on_active()
471{
224ce89b
WB
472 if (mon->is_leader()) {
473 mon->clog->debug() << "mgrmap e" << map.epoch << ": " << map;
474 }
7c673cae
FG
475}
476
477void MgrMonitor::get_health(
478 list<pair<health_status_t,string> >& summary,
479 list<pair<health_status_t,string> > *detail,
480 CephContext *cct) const
481{
482 // start mgr warnings as soon as the mons and osds are all upgraded,
483 // but before the require_luminous osdmap flag is set. this way the
484 // user gets some warning before the osd flag is set and mgr is
485 // actually *required*.
486 if (!mon->monmap->get_required_features().contains_all(
487 ceph::features::mon::FEATURE_LUMINOUS) ||
488 !HAVE_FEATURE(mon->osdmon()->osdmap.get_up_osd_features(),
489 SERVER_LUMINOUS)) {
490 return;
491 }
492
224ce89b 493 if (map.active_gid == 0) {
7c673cae
FG
494 auto level = HEALTH_WARN;
495 // do not escalate to ERR if they are still upgrading to jewel.
31f18b77 496 if (mon->osdmon()->osdmap.require_osd_release >= CEPH_RELEASE_LUMINOUS) {
7c673cae
FG
497 utime_t now = ceph_clock_now();
498 if (first_seen_inactive != utime_t() &&
499 now - first_seen_inactive > g_conf->mon_mgr_inactive_grace) {
500 level = HEALTH_ERR;
501 }
502 }
503 summary.push_back(make_pair(level, "no active mgr"));
504 }
505}
506
507void MgrMonitor::tick()
508{
509 if (!is_active() || !mon->is_leader())
510 return;
511
31f18b77
FG
512 const auto now = ceph::coarse_mono_clock::now();
513 const auto cutoff = now - std::chrono::seconds(g_conf->mon_mgr_beacon_grace);
7c673cae
FG
514
515 // Populate any missing beacons (i.e. no beacon since MgrMonitor
516 // instantiation) with the current time, so that they will
517 // eventually look laggy if they fail to give us a beacon.
518 if (pending_map.active_gid != 0
519 && last_beacon.count(pending_map.active_gid) == 0) {
520 last_beacon[pending_map.active_gid] = now;
521 }
522 for (auto s : pending_map.standbys) {
523 if (last_beacon.count(s.first) == 0) {
524 last_beacon[s.first] = now;
525 }
526 }
527
528 // Cull standbys first so that any remaining standbys
529 // will be eligible to take over from the active if we cull him.
530 std::list<uint64_t> dead_standbys;
531 for (const auto &i : pending_map.standbys) {
532 auto last_beacon_time = last_beacon.at(i.first);
533 if (last_beacon_time < cutoff) {
534 dead_standbys.push_back(i.first);
535 }
536 }
537
538 bool propose = false;
539
540 for (auto i : dead_standbys) {
541 dout(4) << "Dropping laggy standby " << i << dendl;
542 drop_standby(i);
543 propose = true;
544 }
545
546 if (pending_map.active_gid != 0
547 && last_beacon.at(pending_map.active_gid) < cutoff) {
224ce89b 548 const std::string old_active_name = pending_map.active_name;
7c673cae
FG
549 drop_active();
550 propose = true;
551 dout(4) << "Dropping active" << pending_map.active_gid << dendl;
552 if (promote_standby()) {
553 dout(4) << "Promoted standby " << pending_map.active_gid << dendl;
224ce89b
WB
554 mon->clog->info() << "Manager daemon " << old_active_name
555 << " is unresponsive, replacing it with standby"
556 << " daemon " << pending_map.active_name;
7c673cae
FG
557 } else {
558 dout(4) << "Active is laggy but have no standbys to replace it" << dendl;
224ce89b
WB
559 mon->clog->warn() << "Manager daemon " << old_active_name
560 << " is unresponsive. No standby daemons available.";
7c673cae
FG
561 }
562 } else if (pending_map.active_gid == 0) {
563 if (promote_standby()) {
564 dout(4) << "Promoted standby " << pending_map.active_gid << dendl;
224ce89b
WB
565 mon->clog->info() << "Activating manager daemon "
566 << pending_map.active_name;
7c673cae
FG
567 propose = true;
568 }
569 }
570
224ce89b 571 if (!pending_map.available &&
c07f9fc5 572 !ever_had_active_mgr &&
224ce89b
WB
573 should_warn_about_mgr_down() != HEALTH_OK) {
574 dout(10) << " exceeded mon_mgr_mkfs_grace " << g_conf->mon_mgr_mkfs_grace
575 << " seconds" << dendl;
576 propose = true;
577 }
578
7c673cae
FG
579 if (propose) {
580 propose_pending();
581 }
582}
583
224ce89b
WB
584void MgrMonitor::on_restart()
585{
586 // Clear out the leader-specific state.
587 last_beacon.clear();
588}
589
590
7c673cae
FG
591bool MgrMonitor::promote_standby()
592{
593 assert(pending_map.active_gid == 0);
594 if (pending_map.standbys.size()) {
595 // Promote a replacement (arbitrary choice of standby)
596 auto replacement_gid = pending_map.standbys.begin()->first;
597 pending_map.active_gid = replacement_gid;
598 pending_map.active_name = pending_map.standbys.at(replacement_gid).name;
599 pending_map.available = false;
600 pending_map.active_addr = entity_addr_t();
601
602 drop_standby(replacement_gid);
603 return true;
604 } else {
605 return false;
606 }
607}
608
609void MgrMonitor::drop_active()
610{
611 if (last_beacon.count(pending_map.active_gid) > 0) {
612 last_beacon.erase(pending_map.active_gid);
613 }
614
c07f9fc5
FG
615 pending_metadata_rm.insert(pending_map.active_name);
616 pending_metadata.erase(pending_map.active_name);
7c673cae
FG
617 pending_map.active_name = "";
618 pending_map.active_gid = 0;
619 pending_map.available = false;
620 pending_map.active_addr = entity_addr_t();
224ce89b
WB
621
622 // So that when new active mgr subscribes to mgrdigest, it will
623 // get an immediate response instead of waiting for next timer
624 cancel_timer();
7c673cae
FG
625}
626
627void MgrMonitor::drop_standby(uint64_t gid)
628{
c07f9fc5
FG
629 pending_metadata_rm.insert(pending_map.standbys[gid].name);
630 pending_metadata.erase(pending_map.standbys[gid].name);
7c673cae
FG
631 pending_map.standbys.erase(gid);
632 if (last_beacon.count(gid) > 0) {
633 last_beacon.erase(gid);
634 }
7c673cae
FG
635}
636
637bool MgrMonitor::preprocess_command(MonOpRequestRef op)
638{
31f18b77
FG
639 MMonCommand *m = static_cast<MMonCommand*>(op->get_req());
640 std::stringstream ss;
641 bufferlist rdata;
642
643 std::map<std::string, cmd_vartype> cmdmap;
644 if (!cmdmap_from_json(m->cmd, &cmdmap, ss)) {
645 string rs = ss.str();
646 mon->reply_command(op, -EINVAL, rs, rdata, get_last_committed());
647 return true;
648 }
7c673cae 649
31f18b77
FG
650 MonSession *session = m->get_session();
651 if (!session) {
652 mon->reply_command(op, -EACCES, "access denied", rdata,
653 get_last_committed());
654 return true;
655 }
656
657 string format;
658 cmd_getval(g_ceph_context, cmdmap, "format", format, string("json-pretty"));
659 boost::scoped_ptr<Formatter> f(Formatter::create(format));
660
661 string prefix;
662 cmd_getval(g_ceph_context, cmdmap, "prefix", prefix);
663 int r = 0;
664
665 if (prefix == "mgr dump") {
666 int64_t epoch = 0;
667 cmd_getval(g_ceph_context, cmdmap, "epoch", epoch, (int64_t)map.get_epoch());
668 if (epoch == (int64_t)map.get_epoch()) {
669 f->dump_object("mgrmap", map);
670 } else {
671 bufferlist bl;
672 int err = get_version(epoch, bl);
673 if (err == -ENOENT) {
674 r = -ENOENT;
675 ss << "there is no map for epoch " << epoch;
676 goto reply;
677 }
678 MgrMap m;
679 auto p = bl.begin();
680 m.decode(p);
681 f->dump_object("mgrmap", m);
682 }
683 f->flush(rdata);
224ce89b
WB
684 } else if (prefix == "mgr module ls") {
685 f->open_array_section("modules");
686 for (auto& p : map.modules) {
687 f->dump_string("module", p);
688 }
689 f->close_section();
690 f->flush(rdata);
c07f9fc5
FG
691 } else if (prefix == "mgr metadata") {
692 string name;
693 cmd_getval(g_ceph_context, cmdmap, "id", name);
694 if (name.size() > 0 && !map.have_name(name)) {
695 ss << "mgr." << name << " does not exist";
696 r = -ENOENT;
697 goto reply;
698 }
699 string format;
700 cmd_getval(g_ceph_context, cmdmap, "format", format);
701 boost::scoped_ptr<Formatter> f(Formatter::create(format, "json-pretty", "json-pretty"));
702 if (name.size()) {
703 f->open_object_section("mgr_metadata");
704 f->dump_string("id", name);
705 r = dump_metadata(name, f.get(), &ss);
706 if (r < 0)
707 goto reply;
708 f->close_section();
709 } else {
710 r = 0;
711 f->open_array_section("mgr_metadata");
712 for (auto& i : map.get_all_names()) {
713 f->open_object_section("mgr");
714 f->dump_string("id", i);
715 r = dump_metadata(i, f.get(), NULL);
716 if (r == -EINVAL || r == -ENOENT) {
717 // Drop error, continue to get other daemons' metadata
718 dout(4) << "No metadata for mgr." << i << dendl;
719 r = 0;
720 } else if (r < 0) {
721 // Unexpected error
722 goto reply;
723 }
724 f->close_section();
725 }
726 f->close_section();
727 }
728 f->flush(rdata);
729 } else if (prefix == "mgr versions") {
730 if (!f)
731 f.reset(Formatter::create("json-pretty"));
732 count_metadata("ceph_version", f.get());
733 f->flush(rdata);
734 r = 0;
735 } else if (prefix == "mgr count-metadata") {
736 if (!f)
737 f.reset(Formatter::create("json-pretty"));
738 string field;
739 cmd_getval(g_ceph_context, cmdmap, "property", field);
740 count_metadata(field, f.get());
741 f->flush(rdata);
742 r = 0;
31f18b77
FG
743 } else {
744 return false;
745 }
746
747reply:
748 string rs;
749 getline(ss, rs);
750 mon->reply_command(op, r, rs, rdata, get_last_committed());
751 return true;
7c673cae
FG
752}
753
754bool MgrMonitor::prepare_command(MonOpRequestRef op)
755{
756 MMonCommand *m = static_cast<MMonCommand*>(op->get_req());
757
758 std::stringstream ss;
759 bufferlist rdata;
760
761 std::map<std::string, cmd_vartype> cmdmap;
762 if (!cmdmap_from_json(m->cmd, &cmdmap, ss)) {
763 string rs = ss.str();
764 mon->reply_command(op, -EINVAL, rs, rdata, get_last_committed());
765 return true;
766 }
767
768 MonSession *session = m->get_session();
769 if (!session) {
770 mon->reply_command(op, -EACCES, "access denied", rdata, get_last_committed());
771 return true;
772 }
773
224ce89b
WB
774 string format;
775 cmd_getval(g_ceph_context, cmdmap, "format", format, string("plain"));
776 boost::scoped_ptr<Formatter> f(Formatter::create(format));
777
7c673cae
FG
778 string prefix;
779 cmd_getval(g_ceph_context, cmdmap, "prefix", prefix);
780
781 int r = 0;
782
783 if (prefix == "mgr fail") {
784 string who;
785 cmd_getval(g_ceph_context, cmdmap, "who", who);
786
787 std::string err;
788 uint64_t gid = strict_strtol(who.c_str(), 10, &err);
789 bool changed = false;
790 if (!err.empty()) {
791 // Does not parse as a gid, treat it as a name
792 if (pending_map.active_name == who) {
793 drop_active();
794 changed = true;
795 } else {
796 gid = 0;
797 for (const auto &i : pending_map.standbys) {
798 if (i.second.name == who) {
799 gid = i.first;
800 break;
801 }
802 }
803 if (gid != 0) {
804 drop_standby(gid);
805 changed = true;
806 } else {
807 ss << "Daemon not found '" << who << "', already failed?";
808 }
809 }
810 } else {
811 if (pending_map.active_gid == gid) {
812 drop_active();
813 changed = true;
814 } else if (pending_map.standbys.count(gid) > 0) {
815 drop_standby(gid);
816 changed = true;
817 } else {
818 ss << "Daemon not found '" << gid << "', already failed?";
819 }
820 }
821
822 if (changed && pending_map.active_gid == 0) {
823 promote_standby();
824 }
224ce89b
WB
825 } else if (prefix == "mgr module enable") {
826 string module;
827 cmd_getval(g_ceph_context, cmdmap, "module", module);
828 if (module.empty()) {
829 r = -EINVAL;
830 goto out;
831 }
832 string force;
833 cmd_getval(g_ceph_context, cmdmap, "force", force);
834 if (!pending_map.all_support_module(module) &&
835 force != "--force") {
836 ss << "all mgr daemons do not support module '" << module << "', pass "
837 << "--force to force enablement";
838 r = -ENOENT;
839 goto out;
840 }
841 pending_map.modules.insert(module);
842 } else if (prefix == "mgr module disable") {
843 string module;
844 cmd_getval(g_ceph_context, cmdmap, "module", module);
845 if (module.empty()) {
846 r = -EINVAL;
847 goto out;
848 }
849 pending_map.modules.erase(module);
7c673cae 850 } else {
224ce89b 851 ss << "Command '" << prefix << "' not implemented!";
7c673cae
FG
852 r = -ENOSYS;
853 }
854
224ce89b 855out:
7c673cae
FG
856 dout(4) << __func__ << " done, r=" << r << dendl;
857 /* Compose response */
858 string rs;
859 getline(ss, rs);
860
861 if (r >= 0) {
862 // success.. delay reply
863 wait_for_finished_proposal(op, new Monitor::C_Command(mon, op, r, rs,
864 get_last_committed() + 1));
865 return true;
866 } else {
867 // reply immediately
868 mon->reply_command(op, r, rs, rdata, get_last_committed());
869 return false;
870 }
871}
872
873void MgrMonitor::init()
874{
31f18b77 875 if (digest_event == nullptr) {
7c673cae
FG
876 send_digests(); // To get it to schedule its own event
877 }
878}
879
880void MgrMonitor::on_shutdown()
881{
31f18b77 882 cancel_timer();
7c673cae
FG
883}
884
c07f9fc5
FG
885int MgrMonitor::load_metadata(const string& name, std::map<string, string>& m,
886 ostream *err)
887{
888 bufferlist bl;
889 int r = mon->store->get(MGR_METADATA_PREFIX, name, bl);
890 if (r < 0)
891 return r;
892 try {
893 bufferlist::iterator p = bl.begin();
894 ::decode(m, p);
895 }
896 catch (buffer::error& e) {
897 if (err)
898 *err << "mgr." << name << " metadata is corrupt";
899 return -EIO;
900 }
901 return 0;
902}
903
904void MgrMonitor::count_metadata(const string& field, std::map<string,int> *out)
905{
906 std::set<string> ls = map.get_all_names();
907 for (auto& name : ls) {
908 std::map<string,string> meta;
909 load_metadata(name, meta, nullptr);
910 auto p = meta.find(field);
911 if (p == meta.end()) {
912 (*out)["unknown"]++;
913 } else {
914 (*out)[p->second]++;
915 }
916 }
917}
918
919void MgrMonitor::count_metadata(const string& field, Formatter *f)
920{
921 std::map<string,int> by_val;
922 count_metadata(field, &by_val);
923 f->open_object_section(field.c_str());
924 for (auto& p : by_val) {
925 f->dump_int(p.first.c_str(), p.second);
926 }
927 f->close_section();
928}
929
930int MgrMonitor::dump_metadata(const string& name, Formatter *f, ostream *err)
931{
932 std::map<string,string> m;
933 if (int r = load_metadata(name, m, err))
934 return r;
935 for (auto& p : m) {
936 f->dump_string(p.first.c_str(), p.second);
937 }
938 return 0;
939}
31f18b77 940
d2e6a577
FG
941const std::vector<MonCommand> &MgrMonitor::get_command_descs() const
942{
943 if (command_descs.empty()) {
944 // must have just upgraded; fallback to static commands
945 return mgr_commands;
946 } else {
947 return command_descs;
948 }
949}