Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mon: "ceph osd crush rule rename" support #17029

Merged
merged 2 commits into from
Aug 25, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 14 additions & 0 deletions qa/workunits/mon/crush_ops.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,27 @@ 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
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
Expand Down
58 changes: 58 additions & 0 deletions src/crush/CrushWrapper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<int>& roots) const
{
for (unsigned i=0; i<crush->max_rules; i++) {
Expand Down Expand Up @@ -1990,6 +2017,37 @@ int CrushWrapper::device_class_clone(
return 0;
}

int CrushWrapper::get_rules_by_class(const string &class_name, set<int> *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) {
Expand Down
4 changes: 4 additions & 0 deletions src/crush/CrushWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,9 @@ class CrushWrapper {
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);
Expand Down Expand Up @@ -1217,6 +1220,7 @@ class CrushWrapper {
int rename_class(const string& srcname, const string& dstname);
int populate_classes(
const std::map<int32_t, map<int32_t, int32_t>>& old_class_bucket);
int get_rules_by_class(const string &class_name, set<int> *rules);
bool _class_is_dead(int class_id);
void cleanup_dead_classes();
int rebuild_roots_with_classes();
Expand Down
9 changes: 9 additions & 0 deletions src/mon/MonCommands.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <class>", \
"osd", "r", "cli,rest")
COMMAND("osd crush rule dump " \
"name=name,type=CephString,goodchars=[A-Za-z0-9-_.],req=false", \
"dump crush rule <name> (default all)", \
Expand Down Expand Up @@ -646,6 +650,11 @@ COMMAND("osd crush rule create-erasure " \
COMMAND("osd crush rule rm " \
"name=name,type=CephString,goodchars=[A-Za-z0-9-_.] ", \
"remove crush rule <name>", "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 <srcname> to <dstname>",
"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",
Expand Down
58 changes: 58 additions & 0 deletions src/mon/OSDMonitor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<int> 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);
Expand Down Expand Up @@ -8470,6 +8498,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)) {
Expand Down