ceph osd unpause
ceph osd tree
+ ceph osd tree up
+ ceph osd tree down
+ ceph osd tree in
+ ceph osd tree out
+ ceph osd tree up in
+ ceph osd tree up out
+ ceph osd tree down in
+ ceph osd tree down out
+ ceph osd tree out down
+ expect_false ceph osd tree up down
+ expect_false ceph osd tree in out
+ expect_false ceph osd tree up foo
+
ceph osd perf
ceph osd blocked-by
clear();
}
- virtual bool should_dump_leaf(int i) {
+ virtual bool should_dump_leaf(int i) const {
return true;
}
- virtual bool should_dump_empty_bucket() {
+ virtual bool should_dump_empty_bucket() const {
return true;
}
"name=epoch,type=CephInt,range=0,req=false",
"print summary of OSD map", "osd", "r", "cli,rest")
COMMAND("osd tree " \
- "name=epoch,type=CephInt,range=0,req=false", \
+ "name=epoch,type=CephInt,range=0,req=false " \
+ "name=states,type=CephChoices,strings=up|down|in|out,n=N,req=false", \
"print OSD tree", "osd", "r", "cli,rest")
COMMAND("osd ls " \
"name=epoch,type=CephInt,range=0,req=false", \
}
rdata.append(ds);
} else if (prefix == "osd tree") {
+ vector<string> states;
+ cmd_getval(g_ceph_context, cmdmap, "states", states);
+ unsigned filter = 0;
+ for (auto& s : states) {
+ if (s == "up") {
+ filter |= OSDMap::DUMP_UP;
+ } else if (s == "down") {
+ filter |= OSDMap::DUMP_DOWN;
+ } else if (s == "in") {
+ filter |= OSDMap::DUMP_IN;
+ } else if (s == "out") {
+ filter |= OSDMap::DUMP_OUT;
+ } else {
+ ss << "unrecognized state '" << s << "'";
+ r = -EINVAL;
+ goto reply;
+ }
+ }
+ if ((filter & (OSDMap::DUMP_IN|OSDMap::DUMP_OUT)) ==
+ (OSDMap::DUMP_IN|OSDMap::DUMP_OUT) ||
+ (filter & (OSDMap::DUMP_UP|OSDMap::DUMP_DOWN)) ==
+ (OSDMap::DUMP_UP|OSDMap::DUMP_DOWN)) {
+ ss << "cannot specify both up and down or both in and out";
+ r = -EINVAL;
+ goto reply;
+ }
if (f) {
f->open_object_section("tree");
- p->print_tree(f.get(), NULL);
+ p->print_tree(f.get(), NULL, filter);
f->close_section();
f->flush(ds);
} else {
- p->print_tree(NULL, &ds);
+ p->print_tree(NULL, &ds, filter);
}
rdata.append(ds);
} else if (prefix == "osd getmap") {
class OSDTreePlainDumper : public CrushTreeDumper::Dumper<TextTable> {
public:
typedef CrushTreeDumper::Dumper<TextTable> Parent;
- OSDTreePlainDumper(const CrushWrapper *crush, const OSDMap *osdmap_)
- : Parent(crush), osdmap(osdmap_) {}
+
+ OSDTreePlainDumper(const CrushWrapper *crush, const OSDMap *osdmap_,
+ unsigned f)
+ : Parent(crush), osdmap(osdmap_), filter(f) { }
+
+ bool should_dump_leaf(int i) const override {
+ if (((filter & OSDMap::DUMP_UP) && !osdmap->is_up(i)) ||
+ ((filter & OSDMap::DUMP_DOWN) && !osdmap->is_down(i)) ||
+ ((filter & OSDMap::DUMP_IN) && !osdmap->is_in(i)) ||
+ ((filter & OSDMap::DUMP_OUT) && !osdmap->is_out(i))) {
+ return false;
+ }
+ return true;
+ }
+
+ bool should_dump_empty_bucket() const override {
+ return !filter;
+ }
void dump(TextTable *tbl) {
tbl->define_column("ID", TextTable::LEFT, TextTable::RIGHT);
Parent::dump(tbl);
for (int i = 0; i < osdmap->get_max_osd(); i++) {
- if (osdmap->exists(i) && !is_touched(i))
+ if (osdmap->exists(i) && !is_touched(i) && should_dump_leaf(i)) {
dump_item(CrushTreeDumper::Item(i, 0, 0), tbl);
+ }
}
}
private:
const OSDMap *osdmap;
+ const unsigned filter;
};
class OSDTreeFormattingDumper : public CrushTreeDumper::FormattingDumper {
public:
typedef CrushTreeDumper::FormattingDumper Parent;
- OSDTreeFormattingDumper(const CrushWrapper *crush, const OSDMap *osdmap_)
- : Parent(crush), osdmap(osdmap_) {}
+ OSDTreeFormattingDumper(const CrushWrapper *crush, const OSDMap *osdmap_,
+ unsigned f)
+ : Parent(crush), osdmap(osdmap_), filter(f) { }
+
+ bool should_dump_leaf(int i) const override {
+ if (((filter & OSDMap::DUMP_UP) && !osdmap->is_up(i)) ||
+ ((filter & OSDMap::DUMP_DOWN) && !osdmap->is_down(i)) ||
+ ((filter & OSDMap::DUMP_IN) && !osdmap->is_in(i)) ||
+ ((filter & OSDMap::DUMP_OUT) && !osdmap->is_out(i))) {
+ return false;
+ }
+ return true;
+ }
+
+ bool should_dump_empty_bucket() const override {
+ return !filter;
+ }
void dump(Formatter *f) {
f->open_array_section("nodes");
f->close_section();
f->open_array_section("stray");
for (int i = 0; i < osdmap->get_max_osd(); i++) {
- if (osdmap->exists(i) && !is_touched(i))
+ if (osdmap->exists(i) && !is_touched(i) && should_dump_leaf(i))
dump_item(CrushTreeDumper::Item(i, 0, 0), f);
}
f->close_section();
private:
const OSDMap *osdmap;
+ const unsigned filter;
};
-void OSDMap::print_tree(Formatter *f, ostream *out) const
+void OSDMap::print_tree(Formatter *f, ostream *out, unsigned filter) const
{
- if (f)
- OSDTreeFormattingDumper(crush.get(), this).dump(f);
- else {
+ if (f) {
+ OSDTreeFormattingDumper(crush.get(), this, filter).dump(f);
+ } else {
assert(out);
TextTable tbl;
- OSDTreePlainDumper(crush.get(), this).dump(&tbl);
+ OSDTreePlainDumper(crush.get(), this, filter).dump(&tbl);
*out << tbl;
}
}
void print_pools(ostream& out) const;
void print_summary(Formatter *f, ostream& out) const;
void print_oneline_summary(ostream& out) const;
- void print_tree(Formatter *f, ostream *out) const;
+
+ enum {
+ DUMP_IN = 1, // only 'in' osds
+ DUMP_OUT = 2, // only 'out' osds
+ DUMP_UP = 4, // only 'up' osds
+ DUMP_DOWN = 8, // only 'down' osds
+ };
+ void print_tree(Formatter *f, ostream *out, unsigned dump_flags=0) const;
int summarize_mapping_stats(
OSDMap *newmap,
run_mon $dir a || return 1
ceph osd crush add-bucket host1 host
+ ceph osd tree
! ceph osd tree | grep host2 || return 1
ceph osd crush rename-bucket host1 host2 || return 1
+ ceph osd tree
ceph osd tree | grep host2 || return 1
ceph osd crush rename-bucket host1 host2 || return 1 # idempotency
ceph osd crush rename-bucket nonexistent something 2>&1 | grep "Error ENOENT" || return 1