diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 862ffa7e..94ccb08f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -140,6 +140,7 @@ add_library(vitastor_client SHARED cli_merge.cpp cli_rm_data.cpp cli_rm.cpp + cli_rm_osd.cpp ) set_target_properties(vitastor_client PROPERTIES PUBLIC_HEADER "vitastor_c.h") target_link_libraries(vitastor_client diff --git a/src/cli.cpp b/src/cli.cpp index 6723a6a0..30f36e92 100644 --- a/src/cli.cpp +++ b/src/cli.cpp @@ -73,6 +73,9 @@ static const char* help_text = " must be a child of and may be one of the layers between\n" " and , including and .\n" "\n" + "vitastor-cli rm-osd [osd_id...]\n" + " Remove metadata and configuration for specified OSD(s) from etcd.\n" + "\n" "vitastor-cli alloc-osd\n" " Allocate a new OSD number and reserve it by creating empty /osd/stats/ key.\n" "\n" @@ -225,6 +228,16 @@ static int run(cli_tool_t *p, json11::Json::object cfg) // Delete inode data action_cb = p->start_rm_data(cfg); } + else if (cmd[0] == "rm-osd") + { + // Delete OSD metadata from etcd + if (cmd.size() > 1) + { + cmd.erase(cmd.begin(), cmd.begin()+1); + cfg["osd_id"] = cmd; + } + action_cb = p->start_rm_osd(cfg); + } else if (cmd[0] == "merge-data") { // Merge layer data without affecting metadata diff --git a/src/cli.h b/src/cli.h index 2bcfbaf4..01c921ed 100644 --- a/src/cli.h +++ b/src/cli.h @@ -64,6 +64,7 @@ public: std::function start_merge(json11::Json); std::function start_flatten(json11::Json); std::function start_rm(json11::Json); + std::function start_rm_osd(json11::Json cfg); std::function start_alloc_osd(json11::Json cfg); // Should be called like loop_and_wait(start_status(), ) diff --git a/src/cli_rm_osd.cpp b/src/cli_rm_osd.cpp new file mode 100644 index 00000000..8352ff48 --- /dev/null +++ b/src/cli_rm_osd.cpp @@ -0,0 +1,109 @@ +// Copyright (c) Vitaliy Filippov, 2019+ +// License: VNPL-1.1 (see README.md for details) + +#include +#include "cli.h" +#include "cluster_client.h" +#include "str_util.h" + +#include + +// Delete OSD metadata from etcd +struct rm_osd_t +{ + cli_tool_t *parent; + + std::vector osd_ids; + + int state = 0; + cli_result_t result; + + bool is_done() + { + return state == 100; + } + + void loop() + { + if (state == 1) + goto resume_1; + if (!osd_ids.size()) + { + result = (cli_result_t){ .err = EINVAL, .text = "OSD numbers are not specified" }; + state = 100; + return; + } + { + json11::Json::array rm_items; + for (auto osd_id: osd_ids) + { + if (!osd_id) + { + result = (cli_result_t){ .err = EINVAL, .text = "OSD number can't be zero" }; + state = 100; + return; + } + rm_items.push_back("/config/osd/"+std::to_string(osd_id)); + rm_items.push_back("/osd/stats/"+std::to_string(osd_id)); + rm_items.push_back("/osd/state/"+std::to_string(osd_id)); + rm_items.push_back("/osd/inodestats/"+std::to_string(osd_id)); + rm_items.push_back("/osd/space/"+std::to_string(osd_id)); + } + for (int i = 0; i < rm_items.size(); i++) + { + rm_items[i] = json11::Json::object { + { "request_delete_range", json11::Json::object { + { "key", base64_encode( + parent->cli->st_cli.etcd_prefix+rm_items[i].string_value() + ) }, + } }, + }; + } + parent->etcd_txn(json11::Json::object { { "success", rm_items } }); + } + resume_1: + state = 1; + if (parent->waiting > 0) + return; + if (parent->etcd_err.err) + { + result = parent->etcd_err; + state = 100; + return; + } + std::string ids = ""; + for (auto osd_id: osd_ids) + { + ids += (ids.size() ? ", " : "")+std::to_string(osd_id); + } + state = 100; + result = (cli_result_t){ + .text = (osd_ids.size() > 1 ? "OSDs " : "OSD ")+ids+(osd_ids.size() > 1 ? " are" : " is")+" removed from etcd", + .data = json11::Json::object{ { "osd_ids", osd_ids } }, + }; + } +}; + +std::function cli_tool_t::start_rm_osd(json11::Json cfg) +{ + auto rm_osd = new rm_osd_t(); + rm_osd->parent = this; + if (cfg["osd_id"].is_number() || cfg["osd_id"].is_string()) + rm_osd->osd_ids.push_back(cfg["osd_id"].uint64_value()); + else + { + for (auto & id: cfg["osd_id"].array_items()) + rm_osd->osd_ids.push_back(id.uint64_value()); + } + return [rm_osd](cli_result_t & result) + { + rm_osd->loop(); + if (rm_osd->is_done()) + { + result = rm_osd->result; + delete rm_osd; + return true; + } + return false; + }; +} diff --git a/tests/test_add_osd.sh b/tests/test_add_osd.sh index fbd2888d..e03ce4f6 100755 --- a/tests/test_add_osd.sh +++ b/tests/test_add_osd.sh @@ -33,12 +33,9 @@ if ! ($ETCDCTL get --prefix /vitastor/pg/state/ --print-value-only | jq -s -e '( fi sleep 1 -kill $OSD4_PID +kill -9 $OSD4_PID sleep 1 -$ETCDCTL del /vitastor/osd/state/4 -$ETCDCTL del /vitastor/osd/stats/4 -$ETCDCTL del /vitastor/osd/inodestats/4 -$ETCDCTL del /vitastor/osd/space/4 +build/src/vitastor-cli --etcd_address $ETCD_URL rm-osd 4 sleep 2