// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2004-2006 Sage Weil * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #include #include #include #include #include #include #include using namespace std; #include "config.h" #include "osd/OSDMap.h" #include "mon/MonMap.h" #include "common/common_init.h" void usage() { cout << " usage: [--print] [--createsimple [--clobber] [--pg_bits ]] " << std::endl; cout << " --export-crush write osdmap's crush map to " << std::endl; cout << " --import-crush replace osdmap's crush map with " << std::endl; cout << " --test-map-pg map a pgid to osds" << std::endl; exit(1); } int main(int argc, const char **argv) { vector args; argv_to_vec(argc, argv, args); env_to_vec(args); DEFINE_CONF_VARS(usage); common_set_defaults(false); common_init(args, "osdmaptool", false); const char *me = argv[0]; const char *fn = 0; bool print = false; bool createsimple = false; int num_osd = 0, num_dom = 0; int pg_bits = g_conf.osd_pg_bits; int lpg_bits = g_conf.osd_lpg_bits; bool clobber = false; bool modified = false; const char *export_crush = 0; const char *import_crush = 0; list add, rm; const char *test_map_pg = 0; const char *test_map_object = 0; bool test_crush = false; FOR_EACH_ARG(args) { if (CONF_ARG_EQ("help", 'h')) { usage(); } else if (CONF_ARG_EQ("print", 'p')) { CONF_SAFE_SET_ARG_VAL(&print, OPT_BOOL); } else if (CONF_ARG_EQ("createsimple", '\0')) { createsimple = true; CONF_SAFE_SET_ARG_VAL(&num_osd, OPT_INT); } else if (CONF_ARG_EQ("clobber", '\0')) { CONF_SAFE_SET_ARG_VAL(&clobber, OPT_BOOL); } else if (CONF_ARG_EQ("pg_bits", '\0')) { CONF_SAFE_SET_ARG_VAL(&pg_bits, OPT_INT); } else if (CONF_ARG_EQ("lpg_bits", '\0')) { CONF_SAFE_SET_ARG_VAL(&lpg_bits, OPT_INT); } else if (CONF_ARG_EQ("num_dom", '\0')) { CONF_SAFE_SET_ARG_VAL(&num_dom, OPT_INT); } else if (CONF_ARG_EQ("export_crush", '\0')) { CONF_SAFE_SET_ARG_VAL(&export_crush, OPT_STR); } else if (CONF_ARG_EQ("import_crush", '\0')) { CONF_SAFE_SET_ARG_VAL(&import_crush, OPT_STR); } else if (CONF_ARG_EQ("test_map_pg", '\0')) { CONF_SAFE_SET_ARG_VAL(&test_map_pg, OPT_STR); } else if (CONF_ARG_EQ("test_map_object", '\0')) { CONF_SAFE_SET_ARG_VAL(&test_map_object, OPT_STR); } else if (CONF_ARG_EQ("test_crush", '\0')) { CONF_SAFE_SET_ARG_VAL(&test_crush, OPT_BOOL); } else if (!fn) fn = args[i]; else usage(); } if (!fn) { cerr << me << ": must specify osdmap filename" << std::endl; usage(); } OSDMap osdmap; bufferlist bl; cout << me << ": osdmap file '" << fn << "'" << std::endl; int r = 0; if (!(createsimple && clobber)) { r = bl.read_file(fn); if (r >= 0) { try { osdmap.decode(bl); } catch (const buffer::error &e) { cerr << me << ": error decoding osdmap '" << fn << "'" << std::endl; return -1; } } } char buf[80]; if (!createsimple && r < 0) { cerr << me << ": couldn't open " << fn << ": " << strerror_r(errno, buf, sizeof(buf)) << std::endl; return -1; } else if (createsimple && !clobber && r == 0) { cerr << me << ": " << fn << " exists, --clobber to overwrite" << std::endl; return -1; } if (createsimple) { if (num_osd < 1) { cerr << me << ": osd count must be > 0" << std::endl; exit(1); } ceph_fsid_t fsid; memset(&fsid, 0, sizeof(ceph_fsid_t)); osdmap.build_simple(0, fsid, num_osd, num_dom, pg_bits, lpg_bits, 0); modified = true; } if (import_crush) { bufferlist cbl; r = cbl.read_file(import_crush); if (r < 0) { cerr << me << ": error reading crush map from " << import_crush << std::endl; exit(1); } // validate CrushWrapper cw; bufferlist::iterator p = cbl.begin(); cw.decode(p); // apply OSDMap::Incremental inc; inc.fsid = osdmap.get_fsid(); inc.epoch = osdmap.get_epoch()+1; inc.crush = cbl; osdmap.apply_incremental(inc); cout << me << ": imported " << cbl.length() << " byte crush map from " << import_crush << std::endl; modified = true; } if (export_crush) { bufferlist cbl; osdmap.crush.encode(cbl); r = cbl.write_file(export_crush); if (r < 0) { cerr << me << ": error writing crush map to " << import_crush << std::endl; exit(1); } cout << me << ": exported crush map to " << export_crush << std::endl; } if (test_map_object) { object_t oid(test_map_object); ceph_object_layout ol = osdmap.make_object_layout(oid, 0); pg_t pgid; pgid.v = ol.ol_pgid; vector acting; osdmap.pg_to_acting_osds(pgid, acting); cout << " object '" << oid << "' -> " << pgid << " -> " << acting << std::endl; } if (test_map_pg) { pg_t pgid; if (pgid.parse(test_map_pg) < 0) { cerr << me << ": failed to parse pg '" << test_map_pg << "', r = " << r << std::endl; usage(); } cout << " parsed '" << test_map_pg << "' -> " << pgid << std::endl; vector raw, up, acting; osdmap.pg_to_osds(pgid, raw); osdmap.pg_to_up_acting_osds(pgid, up, acting); cout << pgid << " raw " << raw << " up " << up << " acting " << acting << std::endl; } if (test_crush) { int pass = 0; while (1) { cout << "pass " << ++pass << std::endl; hash_map > m; for (map::const_iterator p = osdmap.get_pools().begin(); p != osdmap.get_pools().end(); p++) { const pg_pool_t *pool = osdmap.get_pg_pool(p->first); for (int ps = 0; ps < pool->get_pg_num(); ps++) { pg_t pgid(ps, p->first, -1); for (int i=0; i<100; i++) { cout << pgid << " attempt " << i << std::endl; vector r, s; osdmap.pg_to_acting_osds(pgid, r); //cout << pgid << " " << r << std::endl; if (m.count(pgid)) { if (m[pgid] != r) { cout << pgid << " had " << m[pgid] << " now " << r << std::endl; assert(0); } } else m[pgid] = r; } } } } } if (!print && !modified && !export_crush && !import_crush && !test_map_pg && !test_map_object) { cerr << me << ": no action specified?" << std::endl; usage(); } if (modified) osdmap.inc_epoch(); if (print) osdmap.print(cout); if (modified) { bl.clear(); osdmap.encode(bl); // write it out cout << me << ": writing epoch " << osdmap.get_epoch() << " to " << fn << std::endl; int r = bl.write_file(fn); if (r < 0) { cerr << "osdmaptool: error writing to '" << fn << "': " << strerror_r(-r, buf, sizeof(buf)) << std::endl; return 1; } } return 0; }