From a5075ed253940471b347ba0773f66ea6e61398d0 Mon Sep 17 00:00:00 2001 From: xie xingguo Date: Tue, 15 Aug 2017 16:46:15 +0800 Subject: [PATCH 1/2] mon: "ceph osd crush rule rename" support User may specify a rule with the same name of the pool that it serves. Since a pool can be renamed, so does the rule. Signed-off-by: xie xingguo --- qa/workunits/mon/crush_ops.sh | 10 ++++++++++ src/crush/CrushWrapper.cc | 27 +++++++++++++++++++++++++++ src/crush/CrushWrapper.h | 3 +++ src/mon/MonCommands.h | 5 +++++ src/mon/OSDMonitor.cc | 30 ++++++++++++++++++++++++++++++ 5 files changed, 75 insertions(+) diff --git a/qa/workunits/mon/crush_ops.sh b/qa/workunits/mon/crush_ops.sh index 1ef6e5cc1ed..41e7d10882f 100755 --- a/qa/workunits/mon/crush_ops.sh +++ b/qa/workunits/mon/crush_ops.sh @@ -33,6 +33,16 @@ ceph osd pool rm ec-foo ec-foo --yes-i-really-really-mean-it ceph osd crush rule ls | grep foo +ceph osd crush rule rename foo foo-asdf +ceph osd crush rule rename bar bar-asdf +ceph osd crush rule ls | grep 'foo-asdf' +ceph osd crush rule ls | grep 'bar-asdf' +ceph osd crush rule rm foo 2>&1 | grep 'does not exist' +ceph osd crush rule rm bar 2>&1 | grep 'does not exist' +ceph osd crush rule rename foo-asdf foo +ceph osd crush rule rename bar-asdf bar +ceph osd crush rule ls | expect_false grep 'foo-asdf' +ceph osd crush rule ls | expect_false grep 'bar-asdf' ceph osd crush rule rm foo ceph osd crush rule rm foo # idempotent ceph osd crush rule rm bar diff --git a/src/crush/CrushWrapper.cc b/src/crush/CrushWrapper.cc index 76c6afe60a5..d65ec10619d 100644 --- a/src/crush/CrushWrapper.cc +++ b/src/crush/CrushWrapper.cc @@ -291,6 +291,33 @@ int CrushWrapper::rename_bucket(const string& srcname, return set_item_name(oldid, dstname); } +int CrushWrapper::rename_rule(const string& srcname, + const string& dstname, + ostream *ss) +{ + if (!rule_exists(srcname)) { + if (ss) { + *ss << "source rule name '" << srcname << "' does not exist"; + } + return -ENOENT; + } + if (rule_exists(dstname)) { + if (ss) { + *ss << "destination rule name '" << dstname << "' already exists"; + } + return -EEXIST; + } + int rule_id = get_rule_id(srcname); + auto it = rule_name_map.find(rule_id); + assert(it != rule_name_map.end()); + it->second = dstname; + if (have_rmaps) { + rule_name_rmap.erase(srcname); + rule_name_rmap[dstname] = rule_id; + } + return 0; +} + void CrushWrapper::find_takes(set& roots) const { for (unsigned i=0; imax_rules; i++) { diff --git a/src/crush/CrushWrapper.h b/src/crush/CrushWrapper.h index 9ef12f9b662..5271e144112 100644 --- a/src/crush/CrushWrapper.h +++ b/src/crush/CrushWrapper.h @@ -539,6 +539,9 @@ public: ostream *ss); // rule names + int rename_rule(const string& srcname, + const string& dstname, + ostream *ss); bool rule_exists(string name) const { build_rmaps(); return rule_name_rmap.count(name); diff --git a/src/mon/MonCommands.h b/src/mon/MonCommands.h index 57845ab3d27..5756f967769 100644 --- a/src/mon/MonCommands.h +++ b/src/mon/MonCommands.h @@ -646,6 +646,11 @@ COMMAND("osd crush rule create-erasure " \ COMMAND("osd crush rule rm " \ "name=name,type=CephString,goodchars=[A-Za-z0-9-_.] ", \ "remove crush rule ", "osd", "rw", "cli,rest") +COMMAND("osd crush rule rename " \ + "name=srcname,type=CephString,goodchars=[A-Za-z0-9-_.] " \ + "name=dstname,type=CephString,goodchars=[A-Za-z0-9-_.]", \ + "rename crush rule to ", + "osd", "rw", "cli,rest") COMMAND("osd crush tree " "name=shadow,type=CephChoices,strings=--show-shadow,req=false", \ "dump crush buckets and items in a tree view", diff --git a/src/mon/OSDMonitor.cc b/src/mon/OSDMonitor.cc index be6712caa77..987f9440adc 100644 --- a/src/mon/OSDMonitor.cc +++ b/src/mon/OSDMonitor.cc @@ -8470,6 +8470,36 @@ bool OSDMonitor::prepare_command_impl(MonOpRequestRef op, get_last_committed() + 1)); return true; + } else if (prefix == "osd crush rule rename") { + string srcname; + string dstname; + cmd_getval(g_ceph_context, cmdmap, "srcname", srcname); + cmd_getval(g_ceph_context, cmdmap, "dstname", dstname); + if (srcname.empty() || dstname.empty()) { + ss << "must specify both source rule name and destination rule name"; + err = -EINVAL; + goto reply; + } + if (srcname == dstname) { + ss << "destination rule name is equal to source rule name"; + err = 0; + goto reply; + } + + CrushWrapper newcrush; + _get_pending_crush(newcrush); + err = newcrush.rename_rule(srcname, dstname, &ss); + if (err < 0) { + // ss has reason for failure + goto reply; + } + pending_inc.crush.clear(); + newcrush.encode(pending_inc.crush, mon->get_quorum_con_features()); + getline(ss, rs); + wait_for_finished_proposal(op, new Monitor::C_Command(mon, op, 0, rs, + get_last_committed() + 1)); + return true; + } else if (prefix == "osd setmaxosd") { int64_t newmax; if (!cmd_getval(g_ceph_context, cmdmap, "newmax", newmax)) { From 7c67f95201316a240c7cdf1d8619b7642ff8fc33 Mon Sep 17 00:00:00 2001 From: xie xingguo Date: Thu, 17 Aug 2017 10:34:26 +0800 Subject: [PATCH 2/2] crush, mon: "ceph osd crush rule ls-by-class" support This command returns all crush rules that are currently referencing the device class specified by user. Signed-off-by: xie xingguo --- qa/workunits/mon/crush_ops.sh | 4 ++++ src/crush/CrushWrapper.cc | 31 +++++++++++++++++++++++++++++++ src/crush/CrushWrapper.h | 1 + src/mon/MonCommands.h | 4 ++++ src/mon/OSDMonitor.cc | 28 ++++++++++++++++++++++++++++ 5 files changed, 68 insertions(+) diff --git a/qa/workunits/mon/crush_ops.sh b/qa/workunits/mon/crush_ops.sh index 41e7d10882f..44bc70f4e92 100755 --- a/qa/workunits/mon/crush_ops.sh +++ b/qa/workunits/mon/crush_ops.sh @@ -26,6 +26,10 @@ ceph osd crush set-device-class ssd osd.0 ceph osd crush set-device-class hdd osd.1 ceph osd crush rule create-replicated foo-ssd default host ssd ceph osd crush rule create-replicated foo-hdd default host hdd +ceph osd crush rule ls-by-class ssd | grep 'foo-ssd' +ceph osd crush rule ls-by-class ssd | expect_false grep 'foo-hdd' +ceph osd crush rule ls-by-class hdd | grep 'foo-hdd' +ceph osd crush rule ls-by-class hdd | expect_false grep 'foo-ssd' ceph osd erasure-code-profile set ec-foo-ssd crush-device-class=ssd m=2 k=2 ceph osd pool create ec-foo 2 erasure ec-foo-ssd diff --git a/src/crush/CrushWrapper.cc b/src/crush/CrushWrapper.cc index d65ec10619d..d681b6b4e00 100644 --- a/src/crush/CrushWrapper.cc +++ b/src/crush/CrushWrapper.cc @@ -2017,6 +2017,37 @@ int CrushWrapper::device_class_clone( return 0; } +int CrushWrapper::get_rules_by_class(const string &class_name, set *rules) +{ + assert(rules); + rules->clear(); + if (!class_exists(class_name)) { + return -ENOENT; + } + int class_id = get_class_id(class_name); + for (unsigned i = 0; i < crush->max_rules; ++i) { + crush_rule *r = crush->rules[i]; + if (!r) + continue; + for (unsigned j = 0; j < r->len; ++j) { + if (r->steps[j].op == CRUSH_RULE_TAKE) { + int step_item = r->steps[j].arg1; + int original_item; + int c; + int res = split_id_class(step_item, &original_item, &c); + if (res < 0) { + return res; + } + if (c != -1 && c == class_id) { + rules->insert(i); + break; + } + } + } + } + return 0; +} + bool CrushWrapper::_class_is_dead(int class_id) { for (auto &p: class_map) { diff --git a/src/crush/CrushWrapper.h b/src/crush/CrushWrapper.h index 5271e144112..3737d573002 100644 --- a/src/crush/CrushWrapper.h +++ b/src/crush/CrushWrapper.h @@ -1220,6 +1220,7 @@ public: int rename_class(const string& srcname, const string& dstname); int populate_classes( const std::map>& old_class_bucket); + int get_rules_by_class(const string &class_name, set *rules); bool _class_is_dead(int class_id); void cleanup_dead_classes(); int rebuild_roots_with_classes(); diff --git a/src/mon/MonCommands.h b/src/mon/MonCommands.h index 5756f967769..e463986bc87 100644 --- a/src/mon/MonCommands.h +++ b/src/mon/MonCommands.h @@ -509,6 +509,10 @@ COMMAND("osd lspools " \ COMMAND_WITH_FLAG("osd crush rule list", "list crush rules", "osd", "r", "cli,rest", FLAG(DEPRECATED)) COMMAND("osd crush rule ls", "list crush rules", "osd", "r", "cli,rest") +COMMAND("osd crush rule ls-by-class " \ + "name=class,type=CephString,goodchars=[A-Za-z0-9-_.],req=false", \ + "list all crush rules that reference the same ", \ + "osd", "r", "cli,rest") COMMAND("osd crush rule dump " \ "name=name,type=CephString,goodchars=[A-Za-z0-9-_.],req=false", \ "dump crush rule (default all)", \ diff --git a/src/mon/OSDMonitor.cc b/src/mon/OSDMonitor.cc index 987f9440adc..0559adead61 100644 --- a/src/mon/OSDMonitor.cc +++ b/src/mon/OSDMonitor.cc @@ -4923,6 +4923,34 @@ bool OSDMonitor::preprocess_command(MonOpRequestRef op) osdmap.crush->list_rules(&ss); rdata.append(ss.str()); } + } else if (prefix == "osd crush rule ls-by-class") { + string class_name; + cmd_getval(g_ceph_context, cmdmap, "class", class_name); + if (class_name.empty()) { + ss << "no class specified"; + r = -EINVAL; + goto reply; + } + set rules; + r = osdmap.crush->get_rules_by_class(class_name, &rules); + if (r < 0) { + ss << "failed to get rules by class '" << class_name << "'"; + goto reply; + } + if (f) { + f->open_array_section("rules"); + for (auto &rule: rules) { + f->dump_string("name", osdmap.crush->get_rule_name(rule)); + } + f->close_section(); + f->flush(rdata); + } else { + ostringstream rs; + for (auto &rule: rules) { + rs << osdmap.crush->get_rule_name(rule) << "\n"; + } + rdata.append(rs.str()); + } } else if (prefix == "osd crush rule dump") { string name; cmd_getval(g_ceph_context, cmdmap, "name", name);