diff options
Diffstat (limited to 'src/test/librados/test_common.cc')
-rw-r--r-- | src/test/librados/test_common.cc | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/src/test/librados/test_common.cc b/src/test/librados/test_common.cc new file mode 100644 index 00000000..013f5c3b --- /dev/null +++ b/src/test/librados/test_common.cc @@ -0,0 +1,166 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "common/Formatter.h" +#include "include/stringify.h" +#include "json_spirit/json_spirit.h" +#include "test_common.h" + +namespace { + +using namespace ceph; + +int wait_for_healthy(rados_t *cluster) +{ + bool healthy = false; + // This timeout is very long because the tests are sometimes + // run on a thrashing cluster + int timeout = 3600; + int slept = 0; + + while(!healthy) { + JSONFormatter cmd_f; + cmd_f.open_object_section("command"); + cmd_f.dump_string("prefix", "status"); + cmd_f.dump_string("format", "json"); + cmd_f.close_section(); + std::ostringstream cmd_stream; + cmd_f.flush(cmd_stream); + const std::string serialized_cmd = cmd_stream.str(); + + const char *cmd[2]; + cmd[1] = NULL; + cmd[0] = serialized_cmd.c_str(); + + char *outbuf = NULL; + size_t outlen = 0; + int ret = rados_mon_command(*cluster, (const char **)cmd, 1, "", 0, + &outbuf, &outlen, NULL, NULL); + if (ret) { + return ret; + } + + std::string out(outbuf, outlen); + rados_buffer_free(outbuf); + + json_spirit::mValue root; + [[maybe_unused]] bool json_parse_success = json_spirit::read(out, root); + ceph_assert(json_parse_success); + json_spirit::mObject root_obj = root.get_obj(); + json_spirit::mObject pgmap = root_obj["pgmap"].get_obj(); + json_spirit::mArray pgs_by_state = pgmap["pgs_by_state"].get_array(); + + if (pgs_by_state.size() == 1) { + json_spirit::mObject state = pgs_by_state[0].get_obj(); + std::string state_name = state["state_name"].get_str(); + if (state_name != std::string("active+clean")) { + healthy = false; + } else { + healthy = true; + } + } else { + healthy = false; + } + + if (slept >= timeout) { + return -ETIMEDOUT; + }; + + if (!healthy) { + sleep(1); + slept += 1; + } + } + + return 0; +} + +int rados_pool_set( + rados_t *cluster, + const std::string &pool_name, + const std::string &var, + const std::string &val) +{ + JSONFormatter cmd_f; + cmd_f.open_object_section("command"); + cmd_f.dump_string("prefix", "osd pool set"); + cmd_f.dump_string("pool", pool_name); + cmd_f.dump_string("var", var); + cmd_f.dump_string("val", val); + cmd_f.close_section(); + + std::ostringstream cmd_stream; + cmd_f.flush(cmd_stream); + + const std::string serialized_cmd = cmd_stream.str(); + + const char *cmd[2]; + cmd[1] = NULL; + cmd[0] = serialized_cmd.c_str(); + int ret = rados_mon_command(*cluster, (const char **)cmd, 1, "", 0, NULL, + NULL, NULL, NULL); + return ret; +} + +struct pool_op_error : std::exception { + string msg; + pool_op_error(const std::string& pool_name, + const std::string& func_name, + int err) { + std::ostringstream oss; + oss << func_name << "(" << pool_name << ") failed with error " << err; + msg = oss.str(); + } + const char* what() const noexcept override { + return msg.c_str(); + } +}; + +template<typename Func> +std::string with_healthy_cluster(rados_t* cluster, + const std::string& pool_name, + Func&& func) +{ + try { + // Wait for 'creating/backfilling' to clear + if (int r = wait_for_healthy(cluster); r != 0) { + throw pool_op_error{pool_name, "wait_for_healthy", r}; + } + func(); + // Wait for 'creating/backfilling' to clear + if (int r = wait_for_healthy(cluster); r != 0) { + throw pool_op_error{pool_name, "wait_for_healthy", r}; + } + } catch (const pool_op_error& e) { + rados_shutdown(*cluster); + return e.what(); + } + return ""; +} +} + +std::string set_pg_num( + rados_t *cluster, const std::string &pool_name, uint32_t pg_num) +{ + return with_healthy_cluster(cluster, pool_name, [&] { + // Adjust pg_num + if (int r = rados_pool_set(cluster, pool_name, "pg_num", + stringify(pg_num)); + r != 0) { + throw pool_op_error{pool_name, "set_pg_num", r}; + } + }); +} + +std::string set_pgp_num( + rados_t *cluster, const std::string &pool_name, uint32_t pgp_num) +{ + return with_healthy_cluster(cluster, pool_name, [&] { + // Adjust pgp_num + if (int r = rados_pool_set(cluster, pool_name, "pgp_num", + stringify(pgp_num)); + r != 0) { + throw pool_op_error{pool_name, "set_pgp_num", r}; + } + }); +} |