From: David Zafman Date: Fri, 1 Jul 2016 06:18:03 +0000 (-0700) Subject: tools: New "removeall" used to remove head with snapshots X-Git-Tag: ses5-milestone5~247^2~1 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=b55e0daeb7c0c86ec7365c7d371cc438a46daa73;p=ceph.git tools: New "removeall" used to remove head with snapshots Use --force to allow remove to only remove head object Adding testing to unit test Signed-off-by: David Zafman --- diff --git a/src/test/ceph_objectstore_tool.py b/src/test/ceph_objectstore_tool.py index 041f7e3d6604..2e2e12d5163f 100755 --- a/src/test/ceph_objectstore_tool.py +++ b/src/test/ceph_objectstore_tool.py @@ -577,6 +577,75 @@ def test_get_set_inc_osdmap(CFSD_PREFIX, osd_path): return errors +def test_removeall(CFSD_PREFIX, db, OBJREPPGS, REP_POOL, CEPH_BIN, OSDDIR, REP_NAME, NUM_CLONED_REP_OBJECTS): + # Test removeall + TMPFILE = r"/tmp/tmp.{pid}".format(pid=os.getpid()) + nullfd = open(os.devnull, "w") + errors=0 + print "Test removeall" + kill_daemons() + for nspace in db.keys(): + for basename in db[nspace].keys(): + JSON = db[nspace][basename]['json'] + for pg in OBJREPPGS: + OSDS = get_osds(pg, OSDDIR) + for osd in OSDS: + DIR = os.path.join(OSDDIR, os.path.join(osd, os.path.join("current", "{pg}_head".format(pg=pg)))) + fnames = [f for f in os.listdir(DIR) if os.path.isfile(os.path.join(DIR, f)) + and f.split("_")[0] == basename and f.split("_")[4] == nspace] + if not fnames: + continue + + if int(basename.split(REP_NAME)[1]) <= int(NUM_CLONED_REP_OBJECTS): + cmd = (CFSD_PREFIX + "'{json}' remove").format(osd=osd, json=JSON) + errors += test_failure(cmd, "Snapshots are present, use removeall to delete everything") + + cmd = (CFSD_PREFIX + " --force --dry-run '{json}' remove").format(osd=osd, json=JSON) + logging.debug(cmd) + ret = call(cmd, shell=True, stdout=nullfd, stderr=nullfd) + if ret != 0: + logging.error("remove with --force failed for {json}".format(json=JSON)) + errors += 1 + + cmd = (CFSD_PREFIX + " --dry-run '{json}' removeall").format(osd=osd, json=JSON) + logging.debug(cmd) + ret = call(cmd, shell=True, stdout=nullfd, stderr=nullfd) + if ret != 0: + logging.error("removeall failed for {json}".format(json=JSON)) + errors += 1 + + cmd = (CFSD_PREFIX + " '{json}' removeall").format(osd=osd, json=JSON) + logging.debug(cmd) + ret = call(cmd, shell=True, stdout=nullfd, stderr=nullfd) + if ret != 0: + logging.error("removeall failed for {json}".format(json=JSON)) + errors += 1 + + tmpfd = open(TMPFILE, "w") + cmd = (CFSD_PREFIX + "--op list --pgid {pg} --namespace {ns} {name}").format(osd=osd, pg=pg, ns=nspace, name=basename) + logging.debug(cmd) + ret = call(cmd, shell=True, stdout=tmpfd) + if ret != 0: + logging.error("Bad exit status {ret} from {cmd}".format(ret=ret, cmd=cmd)) + errors += 1 + tmpfd.close() + lines = get_lines(TMPFILE) + if len(lines) != 0: + logging.error("Removeall didn't remove all objects {ns}/{name} : {lines}".format(ns=nspace, name=basename, lines=lines)) + errors += 1 + vstart(new=False) + wait_for_health() + cmd = "{path}/rados -p {pool} rmsnap snap1".format(pool=REP_POOL, path=CEPH_BIN) + logging.debug(cmd) + ret = call(cmd, shell=True, stdout=nullfd, stderr=nullfd) + if ret != 0: + logging.error("rados rmsnap failed") + errors += 1 + time.sleep(2) + wait_for_health() + return errors + + def main(argv): sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) if len(argv) > 1 and argv[1] == "debug": @@ -1868,6 +1937,8 @@ def main(argv): call("/bin/rm -rf {dir}".format(dir=TESTDIR), shell=True) call("/bin/rm -rf {dir}".format(dir=DATADIR), shell=True) + ERRORS += test_removeall(CFSD_PREFIX, db, OBJREPPGS, REP_POOL, CEPH_BIN, OSDDIR, REP_NAME, NUM_CLONED_REP_OBJECTS) + # vstart() starts 4 OSDs ERRORS += test_get_set_osdmap(CFSD_PREFIX, range(4), ALLOSDS) ERRORS += test_get_set_inc_osdmap(CFSD_PREFIX, ALLOSDS[0]) diff --git a/src/test/osd/osd-scrub-snaps.sh b/src/test/osd/osd-scrub-snaps.sh index 55f873501d04..9b378bfcda53 100755 --- a/src/test/osd/osd-scrub-snaps.sh +++ b/src/test/osd/osd-scrub-snaps.sh @@ -98,7 +98,7 @@ function TEST_scrub_snaps() { # Don't need to ceph_objectstore_tool function because osd stopped JSON="$(ceph-objectstore-tool --data-path $dir/0 --journal-path $dir/0/journal --op list obj1 | grep \"snapid\":-2)" - ceph-objectstore-tool --data-path $dir/0 --journal-path $dir/0/journal "$JSON" remove + ceph-objectstore-tool --data-path $dir/0 --journal-path $dir/0/journal "$JSON" --force remove JSON="$(ceph-objectstore-tool --data-path $dir/0 --journal-path $dir/0/journal --op list obj5 | grep \"snapid\":2)" ceph-objectstore-tool --data-path $dir/0 --journal-path $dir/0/journal "$JSON" remove diff --git a/src/tools/ceph_objectstore_tool.cc b/src/tools/ceph_objectstore_tool.cc index 9937335f64e6..7488a25e5006 100644 --- a/src/tools/ceph_objectstore_tool.cc +++ b/src/tools/ceph_objectstore_tool.cc @@ -1429,8 +1429,25 @@ int do_meta(ObjectStore *store, string object, Formatter *formatter, bool debug, return 0; } +int remove_object(coll_t coll, ghobject_t &ghobj, + SnapMapper &mapper, + MapCacher::Transaction *_t, + ObjectStore::Transaction *t) +{ + int r = mapper.remove_oid(ghobj.hobj, _t); + if (r < 0 && r != -ENOENT) { + cerr << "remove_oid returned " << cpp_strerror(r) << std::endl; + return r; + } + + t->remove(coll, ghobj); + return 0; +} + +int get_snapset(ObjectStore *store, coll_t coll, ghobject_t &ghobj, SnapSet &ss, bool silent); + int do_remove_object(ObjectStore *store, coll_t coll, - ghobject_t &ghobj, + ghobject_t &ghobj, bool all, bool force, ObjectStore::Sequencer &osr) { spg_t pg; @@ -1448,20 +1465,52 @@ int do_remove_object(ObjectStore *store, coll_t coll, return r; } - cout << "remove " << ghobj << std::endl; - if (dry_run) - return 0; + SnapSet ss; + if (ghobj.hobj.has_snapset()) { + r = get_snapset(store, coll, ghobj, ss, false); + if (r < 0) { + cerr << "Can't get snapset error " << cpp_strerror(r) << std::endl; + return r; + } + if (!ss.snaps.empty() && !all) { + if (force) { + cout << "WARNING: only removing " + << (ghobj.hobj.is_head() ? "head" : "snapdir") + << " with snapshots present" << std::endl; + ss.snaps.clear(); + } else { + cerr << "Snapshots are present, use removeall to delete everything" << std::endl; + return -EINVAL; + } + } + } + ObjectStore::Transaction t; OSDriver::OSTransaction _t(driver.get_transaction(&t)); - r = mapper.remove_oid(ghobj.hobj, &_t); - if (r < 0 && r != -ENOENT) { - cerr << "remove_oid returned " << cpp_strerror(r) << std::endl; - return r; + + cout << "remove " << ghobj << std::endl; + + if (!dry_run) { + r = remove_object(coll, ghobj, mapper, &_t, &t); + if (r < 0) + return r; + } + + ghobject_t snapobj = ghobj; + for (vector::iterator i = ss.snaps.begin() ; + i != ss.snaps.end() ; ++i) { + snapobj.hobj.snap = *i; + cout << "remove " << snapobj << std::endl; + if (!dry_run) { + r = remove_object(coll, snapobj, mapper, &_t, &t); + if (r < 0) + return r; + } } - t.remove(coll, ghobj); + if (!dry_run) + store->apply_transaction(&osr, std::move(t)); - store->apply_transaction(&osr, std::move(t)); return 0; } @@ -2160,7 +2209,7 @@ void usage(po::options_description &desc) cerr << "ceph-objectstore-tool ... set-omaphdr [file]" << std::endl; cerr << "ceph-objectstore-tool ... list-attrs" << std::endl; cerr << "ceph-objectstore-tool ... list-omap" << std::endl; - cerr << "ceph-objectstore-tool ... remove" << std::endl; + cerr << "ceph-objectstore-tool ... remove|removeall" << std::endl; cerr << "ceph-objectstore-tool ... dump" << std::endl; cerr << "ceph-objectstore-tool ... set-size" << std::endl; cerr << "ceph-objectstore-tool ... remove-clone-metadata " << std::endl; @@ -2838,8 +2887,9 @@ int main(int argc, char **argv) if (vm.count("objcmd")) { ret = 0; - if (objcmd == "remove") { - ret = do_remove_object(fs, coll, ghobj, *osr); + if (objcmd == "remove" || objcmd == "removeall") { + bool all = (objcmd == "removeall"); + ret = do_remove_object(fs, coll, ghobj, all, force, *osr); goto out; } else if (objcmd == "list-attrs") { ret = do_list_attrs(fs, coll, ghobj);