]>
git.proxmox.com Git - ceph.git/blob - ceph/src/mon/ConfigMonitor.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include <boost/algorithm/string/predicate.hpp>
6 #include "mon/Monitor.h"
7 #include "mon/ConfigMonitor.h"
8 #include "mon/MgrMonitor.h"
9 #include "mon/OSDMonitor.h"
10 #include "messages/MConfig.h"
11 #include "messages/MGetConfig.h"
12 #include "messages/MMonCommand.h"
13 #include "common/Formatter.h"
14 #include "common/TextTable.h"
15 #include "common/cmdparse.h"
16 #include "include/stringify.h"
18 #define dout_subsys ceph_subsys_mon
20 #define dout_prefix _prefix(_dout, mon, this)
21 using namespace TOPNSPC::common
;
22 static ostream
& _prefix(std::ostream
*_dout
, const Monitor
*mon
,
23 const ConfigMonitor
*hmon
) {
24 return *_dout
<< "mon." << mon
->name
<< "@" << mon
->rank
25 << "(" << mon
->get_state_name() << ").config ";
28 const string
KEY_PREFIX("config/");
29 const string
HISTORY_PREFIX("config-history/");
31 ConfigMonitor::ConfigMonitor(Monitor
*m
, Paxos
*p
, const string
& service_name
)
32 : PaxosService(m
, p
, service_name
) {
35 void ConfigMonitor::init()
37 dout(10) << __func__
<< dendl
;
40 void ConfigMonitor::create_initial()
42 dout(10) << __func__
<< dendl
;
47 void ConfigMonitor::update_from_paxos(bool *need_bootstrap
)
49 if (version
== get_last_committed()) {
52 version
= get_last_committed();
53 dout(10) << __func__
<< " " << version
<< dendl
;
58 void ConfigMonitor::create_pending()
60 dout(10) << " " << version
<< dendl
;
62 pending_description
.clear();
65 void ConfigMonitor::encode_pending(MonitorDBStore::TransactionRef t
)
67 dout(10) << " " << (version
+1) << dendl
;
68 put_last_committed(t
, version
+1);
70 for (auto& [key
, value
] : pending_cleanup
) {
71 if (pending
.count(key
) == 0) {
72 derr
<< __func__
<< " repair: adjusting config key '" << key
<< "'"
77 pending_cleanup
.clear();
79 // TODO: record changed sections (osd, mds.foo, rack:bar, ...)
81 string history
= HISTORY_PREFIX
+ stringify(version
+1) + "/";
84 ::encode(ceph_clock_now(), metabl
);
85 ::encode(pending_description
, metabl
);
86 t
->put(CONFIG_PREFIX
, history
, metabl
);
88 for (auto& p
: pending
) {
89 string key
= KEY_PREFIX
+ p
.first
;
90 auto q
= current
.find(p
.first
);
91 if (q
!= current
.end()) {
92 if (p
.second
&& *p
.second
== q
->second
) {
95 t
->put(CONFIG_PREFIX
, history
+ "-" + p
.first
, q
->second
);
96 } else if (!p
.second
) {
100 dout(20) << __func__
<< " set " << key
<< dendl
;
101 t
->put(CONFIG_PREFIX
, key
, *p
.second
);
102 t
->put(CONFIG_PREFIX
, history
+ "+" + p
.first
, *p
.second
);
104 dout(20) << __func__
<< " rm " << key
<< dendl
;
105 t
->erase(CONFIG_PREFIX
, key
);
110 version_t
ConfigMonitor::get_trim_to() const
112 // we don't actually need *any* old states, but keep a few.
119 bool ConfigMonitor::preprocess_query(MonOpRequestRef op
)
121 switch (op
->get_req()->get_type()) {
122 case MSG_MON_COMMAND
:
124 return preprocess_command(op
);
125 } catch (const bad_cmd_get
& e
) {
127 mon
->reply_command(op
, -EINVAL
, e
.what(), bl
, get_last_committed());
134 static string
indent_who(const string
& who
)
136 if (who
== "global") {
139 if (who
.find('.') == string::npos
) {
145 bool ConfigMonitor::preprocess_command(MonOpRequestRef op
)
147 auto m
= op
->get_req
<MMonCommand
>();
148 std::stringstream ss
;
152 if (!cmdmap_from_json(m
->cmd
, &cmdmap
, ss
)) {
153 string rs
= ss
.str();
154 mon
->reply_command(op
, -EINVAL
, rs
, get_last_committed());
158 cmd_getval(cmdmap
, "format", format
, string("plain"));
159 boost::scoped_ptr
<Formatter
> f(Formatter::create(format
));
162 cmd_getval(cmdmap
, "prefix", prefix
);
165 if (prefix
== "config help") {
168 cmd_getval(cmdmap
, "key", name
);
169 const Option
*opt
= g_conf().find_option(name
);
171 opt
= mon
->mgrmon()->find_module_option(name
);
175 f
->dump_object("option", *opt
);
180 ss
<< "configuration option '" << name
<< "' not recognized";
187 odata
.append(ss
.str());
189 } else if (prefix
== "config ls") {
192 f
->open_array_section("options");
194 for (auto& i
: ceph_options
) {
196 f
->dump_string("option", i
.name
);
198 ss
<< i
.name
<< "\n";
201 for (auto& i
: mon
->mgrmon()->get_mgr_module_options()) {
203 f
->dump_string("option", i
.first
);
205 ss
<< i
.first
<< "\n";
212 odata
.append(ss
.str());
214 } else if (prefix
== "config dump") {
215 list
<pair
<string
,Section
*>> sections
= {
216 make_pair("global", &config_map
.global
)
218 for (string type
: { "mon", "mgr", "osd", "mds", "client" }) {
219 auto i
= config_map
.by_type
.find(type
);
220 if (i
!= config_map
.by_type
.end()) {
221 sections
.push_back(make_pair(i
->first
, &i
->second
));
223 auto j
= config_map
.by_id
.lower_bound(type
);
224 while (j
!= config_map
.by_id
.end() &&
225 j
->first
.find(type
) == 0) {
226 sections
.push_back(make_pair(j
->first
, &j
->second
));
232 tbl
.define_column("WHO", TextTable::LEFT
, TextTable::LEFT
);
233 tbl
.define_column("MASK", TextTable::LEFT
, TextTable::LEFT
);
234 tbl
.define_column("LEVEL", TextTable::LEFT
, TextTable::LEFT
);
235 tbl
.define_column("OPTION", TextTable::LEFT
, TextTable::LEFT
);
236 tbl
.define_column("VALUE", TextTable::LEFT
, TextTable::LEFT
);
237 tbl
.define_column("RO", TextTable::LEFT
, TextTable::LEFT
);
239 f
->open_array_section("config");
241 for (auto s
: sections
) {
242 for (auto& i
: s
.second
->options
) {
244 tbl
<< indent_who(s
.first
);
245 tbl
<< i
.second
.mask
.to_str();
246 tbl
<< Option::level_to_str(i
.second
.opt
->level
);
248 tbl
<< i
.second
.raw_value
;
249 tbl
<< (i
.second
.opt
->can_update_at_runtime() ? "" : "*");
250 tbl
<< TextTable::endrow
;
252 f
->open_object_section("option");
253 f
->dump_string("section", s
.first
);
254 i
.second
.dump(f
.get());
260 odata
.append(stringify(tbl
));
265 } else if (prefix
== "config get") {
267 cmd_getval(cmdmap
, "who", who
);
270 if (!entity
.from_str(who
) &&
271 !entity
.from_str(who
+ ".")) {
272 ss
<< "unrecognized entity '" << who
<< "'";
277 map
<string
,string
> crush_location
;
279 if (entity
.is_osd()) {
280 mon
->osdmon()->osdmap
.crush
->get_full_location(who
, &crush_location
);
281 int id
= atoi(entity
.get_id().c_str());
282 const char *c
= mon
->osdmon()->osdmap
.crush
->get_item_class(id
);
286 dout(10) << __func__
<< " crush_location " << crush_location
287 << " class " << device_class
<< dendl
;
290 std::map
<std::string
,pair
<std::string
,const MaskedOption
*>> src
;
291 auto config
= config_map
.generate_entity_map(
294 mon
->osdmon()->osdmap
.crush
.get(),
298 if (cmd_getval(cmdmap
, "key", name
)) {
299 const Option
*opt
= g_conf().find_option(name
);
301 opt
= mon
->mgrmon()->find_module_option(name
);
307 if (opt
->has_flag(Option::FLAG_NO_MON_UPDATE
)) {
308 // handle special options
309 if (name
== "fsid") {
310 odata
.append(stringify(mon
->monmap
->get_fsid()));
315 ss
<< name
<< " is special and cannot be stored by the mon";
318 // get a single value
319 auto p
= config
.find(name
);
320 if (p
!= config
.end()) {
321 odata
.append(p
->second
);
325 if (!entity
.is_client() &&
326 !boost::get
<boost::blank
>(&opt
->daemon_value
)) {
327 odata
.append(Option::to_str(opt
->daemon_value
));
329 odata
.append(Option::to_str(opt
->value
));
333 // dump all (non-default) values for this entity
336 tbl
.define_column("WHO", TextTable::LEFT
, TextTable::LEFT
);
337 tbl
.define_column("MASK", TextTable::LEFT
, TextTable::LEFT
);
338 tbl
.define_column("LEVEL", TextTable::LEFT
, TextTable::LEFT
);
339 tbl
.define_column("OPTION", TextTable::LEFT
, TextTable::LEFT
);
340 tbl
.define_column("VALUE", TextTable::LEFT
, TextTable::LEFT
);
341 tbl
.define_column("RO", TextTable::LEFT
, TextTable::LEFT
);
343 f
->open_object_section("config");
345 auto p
= config
.begin();
346 auto q
= src
.begin();
347 for (; p
!= config
.end(); ++p
, ++q
) {
348 if (name
.size() && p
->first
!= name
) {
352 tbl
<< q
->second
.first
;
353 tbl
<< q
->second
.second
->mask
.to_str();
354 tbl
<< Option::level_to_str(q
->second
.second
->opt
->level
);
357 tbl
<< (q
->second
.second
->opt
->can_update_at_runtime() ? "" : "*");
358 tbl
<< TextTable::endrow
;
360 f
->open_object_section(p
->first
.c_str());
361 f
->dump_string("value", p
->second
);
362 f
->dump_string("section", q
->second
.first
);
363 f
->dump_object("mask", q
->second
.second
->mask
);
364 f
->dump_bool("can_update_at_runtime",
365 q
->second
.second
->opt
->can_update_at_runtime());
370 odata
.append(stringify(tbl
));
376 } else if (prefix
== "config log") {
378 cmd_getval(cmdmap
, "num", num
);
381 f
->open_array_section("changesets");
383 for (version_t v
= version
; v
> version
- std::min(version
, (version_t
)num
); --v
) {
385 load_changeset(v
, &ch
);
387 f
->dump_object("changeset", ch
);
396 odata
.append(ds
.str());
398 } else if (prefix
== "config generate-minimal-conf") {
400 conf
<< "# minimal ceph.conf for " << mon
->monmap
->get_fsid() << "\n";
403 conf
<< "[global]\n";
404 conf
<< "\tfsid = " << mon
->monmap
->get_fsid() << "\n";
405 conf
<< "\tmon_host = ";
406 for (auto i
= mon
->monmap
->mon_info
.begin();
407 i
!= mon
->monmap
->mon_info
.end();
409 if (i
!= mon
->monmap
->mon_info
.begin()) {
412 if (i
->second
.public_addrs
.size() == 1 &&
413 i
->second
.public_addrs
.front().is_legacy() &&
414 i
->second
.public_addrs
.front().get_port() == CEPH_MON_PORT_LEGACY
) {
415 // if this is a legacy addr on the legacy default port, then
416 // use the legacy-compatible formatting so that old clients
417 // can use this config. new code will see the :6789 and correctly
418 // interpret this as a v1 address.
419 conf
<< i
->second
.public_addrs
.get_legacy_str();
421 conf
<< i
->second
.public_addrs
;
425 conf
<< config_map
.global
.get_minimal_conf();
426 for (auto m
: { &config_map
.by_type
, &config_map
.by_id
}) {
428 auto s
= i
.second
.get_minimal_conf();
430 conf
<< "\n[" << i
.first
<< "]\n" << s
;
434 odata
.append(conf
.str());
441 mon
->reply_command(op
, err
, ss
.str(), odata
, get_last_committed());
445 void ConfigMonitor::handle_get_config(MonOpRequestRef op
)
447 auto m
= op
->get_req
<MGetConfig
>();
448 dout(10) << __func__
<< " " << m
->name
<< " host " << m
->host
<< dendl
;
450 const OSDMap
& osdmap
= mon
->osdmon()->osdmap
;
451 map
<string
,string
> crush_location
;
452 osdmap
.crush
->get_full_location(m
->host
, &crush_location
);
453 auto out
= config_map
.generate_entity_map(
458 dout(20) << " config is " << out
<< dendl
;
459 m
->get_connection()->send_message(new MConfig
{std::move(out
)});
462 bool ConfigMonitor::prepare_update(MonOpRequestRef op
)
464 Message
*m
= op
->get_req();
465 dout(7) << "prepare_update " << *m
466 << " from " << m
->get_orig_source_inst() << dendl
;
467 switch (m
->get_type()) {
468 case MSG_MON_COMMAND
:
470 return prepare_command(op
);
471 } catch (const bad_cmd_get
& e
) {
473 mon
->reply_command(op
, -EINVAL
, e
.what(), bl
, get_last_committed());
480 bool ConfigMonitor::prepare_command(MonOpRequestRef op
)
482 auto m
= op
->get_req
<MMonCommand
>();
483 std::stringstream ss
;
487 if (!cmdmap_from_json(m
->cmd
, &cmdmap
, ss
)) {
488 string rs
= ss
.str();
489 mon
->reply_command(op
, -EINVAL
, rs
, get_last_committed());
494 cmd_getval(cmdmap
, "prefix", prefix
);
497 if (prefix
== "config set" ||
498 prefix
== "config rm") {
502 cmd_getval(cmdmap
, "who", who
);
503 cmd_getval(cmdmap
, "name", name
);
504 cmd_getval(cmdmap
, "value", value
);
505 cmd_getval(cmdmap
, "force", force
);
507 if (prefix
== "config set" && !force
) {
508 const Option
*opt
= g_conf().find_option(name
);
510 opt
= mon
->mgrmon()->find_module_option(name
);
513 ss
<< "unrecognized config option '" << name
<< "'";
518 Option::value_t real_value
;
520 err
= opt
->parse_value(value
, &real_value
, &errstr
, &value
);
522 ss
<< "error parsing value: " << errstr
;
526 if (opt
->has_flag(Option::FLAG_NO_MON_UPDATE
)) {
528 ss
<< name
<< " is special and cannot be stored by the mon";
535 if (!ConfigMap::parse_mask(who
, §ion
, &mask
)) {
536 ss
<< "unrecognized config target '" << who
<< "'";
542 if (section
.size()) {
543 key
+= section
+ "/";
547 string mask_str
= mask
.to_str();
548 if (mask_str
.size()) {
549 key
+= mask_str
+ "/";
553 if (prefix
== "config set") {
558 pending
[key
] = boost::none
;
561 } else if (prefix
== "config reset") {
562 int64_t revert_to
= -1;
563 cmd_getval(cmdmap
, "num", revert_to
);
565 revert_to
> (int64_t)version
) {
567 ss
<< "must specify a valid historical version to revert to; "
568 << "see 'ceph config log' for a list of avialable configuration "
569 << "historical versions";
572 if (revert_to
== (int64_t)version
) {
576 for (int64_t v
= version
; v
> revert_to
; --v
) {
578 load_changeset(v
, &ch
);
579 for (auto& i
: ch
.diff
) {
580 if (i
.second
.first
) {
582 bl
.append(*i
.second
.first
);
583 pending
[i
.first
] = bl
;
584 } else if (i
.second
.second
) {
585 pending
[i
.first
] = boost::none
;
589 pending_description
= string("reset to ") + stringify(revert_to
);
591 } else if (prefix
== "config assimilate-conf") {
593 bufferlist bl
= m
->get_data();
594 err
= cf
.parse_bufferlist(&bl
, &ss
);
598 bool updated
= false;
599 ostringstream newconf
;
600 for (auto& [section
, s
] : cf
) {
601 dout(20) << __func__
<< " [" << section
<< "]" << dendl
;
602 bool did_section
= false;
603 for (auto& [key
, val
] : s
) {
604 Option::value_t real_value
;
610 // a known and worthy option?
611 const Option
*o
= g_conf().find_option(key
);
613 o
= mon
->mgrmon()->find_module_option(key
);
616 (o
->flags
& Option::FLAG_NO_MON_UPDATE
) ||
617 (o
->flags
& Option::FLAG_CLUSTER_CREATE
)) {
621 err
= o
->parse_value(val
, &real_value
, &errstr
, &value
);
623 dout(20) << __func__
<< " failed to parse " << key
<< " = '"
624 << val
<< "'" << dendl
;
627 // does it conflict with an existing value?
629 const Section
*s
= config_map
.find_section(section
);
631 auto k
= s
->options
.find(key
);
632 if (k
!= s
->options
.end()) {
633 if (value
!= k
->second
.raw_value
) {
634 dout(20) << __func__
<< " have " << key
635 << " = " << k
->second
.raw_value
636 << " (not " << value
<< ")" << dendl
;
639 dout(20) << __func__
<< " already have " << key
640 << " = " << k
->second
.raw_value
<< dendl
;
645 dout(20) << __func__
<< " add " << key
<< " = " << value
646 << " (" << val
<< ")" << dendl
;
650 pending
[section
+ "/" + key
] = bl
;
656 dout(20) << __func__
<< " skip " << key
<< " = " << value
657 << " (" << val
<< ")" << dendl
;
659 newconf
<< "\n[" << section
<< "]\n";
662 newconf
<< "\t" << key
<< " = " << val
<< "\n";
665 odata
.append(newconf
.str());
670 ss
<< "unknown command " << prefix
;
675 mon
->reply_command(op
, err
, ss
.str(), odata
, get_last_committed());
679 // see if there is an actual change
680 auto p
= pending
.begin();
681 while (p
!= pending
.end()) {
682 auto q
= current
.find(p
->first
);
683 if (p
->second
&& q
!= current
.end() && *p
->second
== q
->second
) {
685 p
= pending
.erase(p
);
686 } else if (!p
->second
&& q
== current
.end()) {
687 // erasing non-existent value
688 p
= pending
.erase(p
);
693 if (pending
.empty()) {
697 force_immediate_propose(); // faster response
698 wait_for_finished_proposal(
700 new Monitor::C_Command(
701 mon
, op
, 0, ss
.str(), odata
,
702 get_last_committed() + 1));
706 void ConfigMonitor::tick()
708 if (!is_active() || !mon
->is_leader()) {
711 dout(10) << __func__
<< dendl
;
712 bool changed
= false;
713 if (!pending_cleanup
.empty()) {
721 void ConfigMonitor::on_active()
725 void ConfigMonitor::load_config()
728 KeyValueDB::Iterator it
= mon
->store
->get_iterator(CONFIG_PREFIX
);
729 it
->lower_bound(KEY_PREFIX
);
732 pending_cleanup
.clear();
733 while (it
->valid() &&
734 it
->key().compare(0, KEY_PREFIX
.size(), KEY_PREFIX
) == 0) {
735 string key
= it
->key().substr(KEY_PREFIX
.size());
736 string value
= it
->value().to_str();
738 current
[key
] = it
->value();
740 auto last_slash
= key
.rfind('/');
743 if (last_slash
== std::string::npos
) {
745 } else if (auto mgrpos
= key
.find("/mgr/"); mgrpos
!= std::string::npos
) {
746 name
= key
.substr(mgrpos
+ 1);
747 who
= key
.substr(0, mgrpos
);
749 name
= key
.substr(last_slash
+ 1);
750 who
= key
.substr(0, last_slash
);
753 const Option
*opt
= g_conf().find_option(name
);
755 opt
= mon
->mgrmon()->find_module_option(name
);
758 dout(10) << __func__
<< " unrecognized option '" << name
<< "'" << dendl
;
759 opt
= new Option(name
, Option::TYPE_STR
, Option::LEVEL_UNKNOWN
);
760 // FIXME: this will be leaked!
764 int r
= opt
->pre_validate(&value
, &err
);
766 dout(10) << __func__
<< " pre-validate failed on '" << name
<< "' = '"
767 << value
<< "' for " << name
<< dendl
;
770 MaskedOption
mopt(opt
);
771 mopt
.raw_value
= value
;
774 !ConfigMap::parse_mask(who
, §ion_name
, &mopt
.mask
)) {
775 derr
<< __func__
<< " invalid mask for key " << key
<< dendl
;
776 pending_cleanup
[key
] = boost::none
;
777 } else if (opt
->has_flag(Option::FLAG_NO_MON_UPDATE
)) {
778 dout(10) << __func__
<< " NO_MON_UPDATE option '"
779 << name
<< "' = '" << value
<< "' for " << name
781 pending_cleanup
[key
] = boost::none
;
783 if (section_name
.empty()) {
784 // we prefer global/$option instead of just $option
785 derr
<< __func__
<< " adding global/ prefix to key '" << key
<< "'"
787 pending_cleanup
[key
] = boost::none
;
788 pending_cleanup
["global/"s
+ key
] = it
->value();
790 Section
*section
= &config_map
.global
;;
791 if (section_name
.size() && section_name
!= "global") {
792 if (section_name
.find('.') != std::string::npos
) {
793 section
= &config_map
.by_id
[section_name
];
795 section
= &config_map
.by_type
[section_name
];
798 section
->options
.insert(make_pair(name
, std::move(mopt
)));
803 dout(10) << __func__
<< " got " << num
<< " keys" << dendl
;
805 // refresh our own config
807 const OSDMap
& osdmap
= mon
->osdmon()->osdmap
;
808 map
<string
,string
> crush_location
;
809 osdmap
.crush
->get_full_location(g_conf()->host
, &crush_location
);
810 auto out
= config_map
.generate_entity_map(
814 string
{}); // no device class
815 g_conf().set_mon_vals(g_ceph_context
, out
, nullptr);
819 void ConfigMonitor::load_changeset(version_t v
, ConfigChangeSet
*ch
)
822 string prefix
= HISTORY_PREFIX
+ stringify(v
) + "/";
823 KeyValueDB::Iterator it
= mon
->store
->get_iterator(CONFIG_PREFIX
);
824 it
->lower_bound(prefix
);
825 while (it
->valid() && it
->key().find(prefix
) == 0) {
826 if (it
->key() == prefix
) {
827 bufferlist bl
= it
->value();
828 auto p
= bl
.cbegin();
830 decode(ch
->stamp
, p
);
833 catch (buffer::error
& e
) {
834 derr
<< __func__
<< " failure decoding changeset " << v
<< dendl
;
837 char op
= it
->key()[prefix
.length()];
838 string key
= it
->key().substr(prefix
.length() + 1);
840 ch
->diff
[key
].first
= it
->value().to_str();
841 } else if (op
== '+') {
842 ch
->diff
[key
].second
= it
->value().to_str();
849 bool ConfigMonitor::refresh_config(MonSession
*s
)
851 const OSDMap
& osdmap
= mon
->osdmon()->osdmap
;
852 map
<string
,string
> crush_location
;
853 if (s
->remote_host
.size()) {
854 osdmap
.crush
->get_full_location(s
->remote_host
, &crush_location
);
855 dout(10) << __func__
<< " crush_location for remote_host " << s
->remote_host
856 << " is " << crush_location
<< dendl
;
860 if (s
->name
.is_osd()) {
861 const char *c
= osdmap
.crush
->get_item_class(s
->name
.num());
864 dout(10) << __func__
<< " device_class " << device_class
<< dendl
;
868 dout(20) << __func__
<< " " << s
->entity_name
<< " crush " << crush_location
869 << " device_class " << device_class
<< dendl
;
870 auto out
= config_map
.generate_entity_map(
876 if (out
== s
->last_config
&& s
->any_config
) {
877 dout(20) << __func__
<< " no change, " << out
<< dendl
;
880 // removing this to hide sensitive data going into logs
881 // leaving this for debugging purposes
882 // dout(20) << __func__ << " " << out << dendl;
883 s
->last_config
= std::move(out
);
884 s
->any_config
= true;
888 bool ConfigMonitor::maybe_send_config(MonSession
*s
)
890 bool changed
= refresh_config(s
);
891 dout(10) << __func__
<< " to " << s
->name
<< " "
892 << (changed
? "(changed)" : "(unchanged)")
900 void ConfigMonitor::send_config(MonSession
*s
)
902 dout(10) << __func__
<< " to " << s
->name
<< dendl
;
903 auto m
= new MConfig(s
->last_config
);
904 s
->con
->send_message(m
);
907 void ConfigMonitor::check_sub(MonSession
*s
)
909 if (!s
->authenticated
) {
910 dout(20) << __func__
<< " not authenticated " << s
->entity_name
<< dendl
;
913 auto p
= s
->sub_map
.find("config");
914 if (p
!= s
->sub_map
.end()) {
915 check_sub(p
->second
);
919 void ConfigMonitor::check_sub(Subscription
*sub
)
922 << " next " << sub
->next
923 << " have " << version
<< dendl
;
924 if (sub
->next
<= version
) {
925 maybe_send_config(sub
->session
);
927 mon
->with_session_map([sub
](MonSessionMap
& session_map
) {
928 session_map
.remove_sub(sub
);
931 sub
->next
= version
+ 1;
936 void ConfigMonitor::check_all_subs()
938 dout(10) << __func__
<< dendl
;
939 auto subs
= mon
->session_map
.subs
.find("config");
940 if (subs
== mon
->session_map
.subs
.end()) {
943 int updated
= 0, total
= 0;
944 auto p
= subs
->second
->begin();
949 if (maybe_send_config(sub
->session
)) {
953 dout(10) << __func__
<< " updated " << updated
<< " / " << total
<< dendl
;