"as the tiebreaker and setting <dividing_bucket> locations "
"as the units for stretching across",
"mon", "rw")
+COMMAND("mon disable_stretch_mode " \
+ "name=crush_rule,type=CephString,req=false, "
+ "name=yes_i_really_mean_it,type=CephBool,req=false, ",
+ "disable stretch mode, reverting to normal peering rules",
+ "mon", "rw")
COMMAND("mon set_new_tiebreaker " \
"name=name,type=CephString "
"name=yes_i_really_mean_it,type=CephBool,req=false",
if (monmap->stretch_mode_enabled) {
try_engage_stretch_mode();
+ } else {
+ try_disable_stretch_mode();
}
if (is_stretch_mode()) {
disconnect_disallowed_stretch_sessions();
}
}
+struct CMonDisableStretchMode : public Context {
+ Monitor *m;
+ CMonDisableStretchMode(Monitor *mon) : m(mon) {}
+ void finish(int r) {
+ m->try_disable_stretch_mode();
+ }
+};
+void Monitor::try_disable_stretch_mode()
+{
+ dout(20) << __func__ << dendl;
+ if (!stretch_mode_engaged) return;
+ if (!osdmon()->is_readable()) {
+ dout(20) << "osdmon is not readable" << dendl;
+ osdmon()->wait_for_readable_ctx(new CMonDisableStretchMode(this));
+ return;
+ }
+ if (!osdmon()->osdmap.stretch_mode_enabled &&
+ !monmap->stretch_mode_enabled) {
+ dout(10) << "Disabling stretch mode!" << dendl;
+ stretch_mode_engaged = false;
+ stretch_bucket_divider.clear();
+ degraded_stretch_mode = false;
+ recovering_stretch_mode = false;
+ }
+
+}
void Monitor::do_stretch_mode_election_work()
{
void Monitor::go_recovery_stretch_mode()
{
dout(20) << __func__ << dendl;
+ if (!is_stretch_mode()) return;
dout(20) << "is_leader(): " << is_leader() << dendl;
if (!is_leader()) return;
dout(20) << "is_degraded_stretch_mode(): " << is_degraded_stretch_mode() << dendl;
void Monitor::set_recovery_stretch_mode()
{
+ if (!is_stretch_mode()) return;
degraded_stretch_mode = true;
recovering_stretch_mode = true;
osdmon()->set_recovery_stretch_mode();
void Monitor::maybe_go_degraded_stretch_mode()
{
dout(20) << __func__ << dendl;
+ if (!is_stretch_mode()) return;
if (is_degraded_stretch_mode()) return;
if (!is_leader()) return;
if (dead_mon_buckets.empty()) return;
const set<int>& dead_buckets)
{
dout(20) << __func__ << dendl;
+ if (!is_stretch_mode()) return;
ceph_assert(osdmon()->is_writeable());
ceph_assert(monmon()->is_writeable());
void Monitor::set_degraded_stretch_mode()
{
dout(20) << __func__ << dendl;
+ if (!is_stretch_mode()) return;
degraded_stretch_mode = true;
recovering_stretch_mode = false;
osdmon()->set_degraded_stretch_mode();
void Monitor::trigger_healthy_stretch_mode()
{
dout(20) << __func__ << dendl;
+ if (!is_stretch_mode()) return;
if (!is_degraded_stretch_mode()) return;
if (!is_leader()) return;
if (!osdmon()->is_writeable()) {
void Monitor::set_healthy_stretch_mode()
{
+ if (!is_stretch_mode()) return;
degraded_stretch_mode = false;
recovering_stretch_mode = false;
osdmon()->set_healthy_stretch_mode();
* updates across the entire cluster.
*/
void try_engage_stretch_mode();
+ void try_disable_stretch_mode();
void maybe_go_degraded_stretch_mode();
void trigger_degraded_stretch_mode(const std::set<std::string>& dead_mons,
const std::set<int>& dead_buckets);
ceph_assert(okay == true);
}
request_proposal(mon.osdmon());
+ } else if (prefix == "mon disable_stretch_mode") {
+ if (!mon.osdmon()->is_writeable()) {
+ dout(10) << __func__
+ << ": waiting for osdmon writeable for stretch mode" << dendl;
+ mon.osdmon()->wait_for_writeable(op, new Monitor::C_RetryMessage(&mon, op));
+ return false; /* do not propose, yet */
+ }
+ bool sure = false;
+ bool okay = false;
+ int errcode = 0;
+ if (!pending_map.stretch_mode_enabled) {
+ ss << "stretch mode is already disabled";
+ err = -EINVAL;
+ goto reply_no_propose;
+ }
+ cmd_getval(cmdmap, "yes_i_really_mean_it", sure);
+ if (!sure) {
+ ss << " This command will disable stretch mode, "
+ "which means all your pools will be reverted back "
+ "to the default size, min_size and crush_rule. "
+ "Pass --yes-i-really-mean-it to proceed.";
+ err = -EPERM;
+ goto reply_no_propose;
+ }
+ string crush_rule = cmd_getval_or<string>(cmdmap, "crush_rule", string{});
+ mon.osdmon()->try_disable_stretch_mode(ss, &okay, &errcode, crush_rule);
+ if (!okay) {
+ err = errcode;
+ goto reply_no_propose;
+ }
+ pending_map.stretch_mode_enabled = false;
+ pending_map.tiebreaker_mon = "";
+ pending_map.disallowed_leaders.clear();
+ pending_map.stretch_marked_down_mons.clear();
+ pending_map.last_changed = ceph_clock_now();
+ request_proposal(mon.osdmon());
} else {
ss << "unknown command " << prefix;
err = -EINVAL;
dout(20) << "Checking degraded stretch mode due to osd changes" << dendl;
mon.maybe_go_degraded_stretch_mode();
}
+ } else {
+ mon.try_disable_stretch_mode();
}
}
}
}
+void OSDMonitor::try_disable_stretch_mode(stringstream& ss,
+ bool *okay,
+ int *errcode,
+ const string& crush_rule)
+{
+ dout(20) << __func__ << dendl;
+ *okay = false;
+ if (!osdmap.stretch_mode_enabled) {
+ ss << "stretch mode is already disabled";
+ *errcode = -EINVAL;
+ return;
+ }
+ if (osdmap.recovering_stretch_mode) {
+ ss << "stretch mode is currently recovering and cannot be disabled";
+ *errcode = -EBUSY;
+ return;
+ }
+ for (const auto& pi : osdmap.get_pools()) {
+ pg_pool_t *pool = pending_inc.get_new_pool(pi.first, &pi.second);
+ pool->peering_crush_bucket_count = 0;
+ pool->peering_crush_bucket_target = 0;
+ pool->peering_crush_bucket_barrier = 0;
+ pool->peering_crush_mandatory_member = CRUSH_ITEM_NONE;
+ pool->size = g_conf().get_val<uint64_t>("osd_pool_default_size");
+ pool->min_size = g_conf().get_osd_pool_default_min_size(pool->size);
+ // if crush rule is supplied, use it if it exists in crush map
+ if (!crush_rule.empty()) {
+ int crush_rule_id = osdmap.crush->get_rule_id(crush_rule);
+ if (crush_rule_id < 0) {
+ ss << "unrecognized crush rule " << crush_rule;
+ *errcode = -EINVAL;
+ return;
+ }
+ if (osdmap.crush->get_rule_type(crush_rule_id) != (int)pool->get_type()) {
+ ss << "crush rule " << crush_rule << " type does not match pool type";
+ *errcode = -EINVAL;
+ return;
+ }
+ if (crush_rule_id == pool->crush_rule) {
+ ss << "You can't disable stretch mode with the same crush rule you are using";
+ *errcode = -EINVAL;
+ return;
+ }
+ pool->crush_rule = crush_rule_id;
+ } else {
+ // otherwise, use the default rule
+ pool->crush_rule = osdmap.crush->get_osd_pool_default_crush_replicated_rule(cct);
+ }
+ }
+ pending_inc.change_stretch_mode = true;
+ pending_inc.stretch_mode_enabled = false;
+ pending_inc.new_stretch_bucket_count = 0;
+ pending_inc.new_degraded_stretch_mode = 0;
+ pending_inc.new_stretch_mode_bucket = 0;
+ pending_inc.new_recovering_stretch_mode = 0;
+ *okay = true;
+ return;
+}
+
void OSDMonitor::try_enable_stretch_mode_pools(stringstream& ss, bool *okay,
int *errcode,
set<pg_pool_t*>* pools,
uint32_t bucket_count,
const std::set<pg_pool_t*>& pools,
const std::string& new_crush_rule);
+ /**
+ *
+ * Set all stretch mode values of all pools back to pre-stretch mode values.
+ * Set all stretch mode values of OSDMap back to pre-stretch mode values.
+ * If crush_rule is not empty, set the crush rule to that value, else use
+ * the default replicated crush rule.
+ * @param ss: a stringstream to write errors into
+ * @param errcode: filled with -errno if there's a problem
+ * @param crush_rule: the crush rule that will used after disabling stretch mode
+ */
+ void try_disable_stretch_mode(std::stringstream& ss,
+ bool *okay,
+ int *errcode,
+ const std::string& crush_rule);
/**
* Check the input dead_buckets mapping (buckets->dead monitors) to see
* if the OSDs are also down. If so, fill in really_down_buckets and