Add vitastor-cli modify-osd command
This commit is contained in:
@@ -0,0 +1,210 @@
|
||||
// Copyright (c) Vitaliy Filippov, 2019+
|
||||
// License: VNPL-1.1 (see README.md for details)
|
||||
|
||||
#include "cli.h"
|
||||
#include "cluster_client.h"
|
||||
#include "str_util.h"
|
||||
#include "http_client.h"
|
||||
|
||||
// Reweight OSD, change tags or set noout flag
|
||||
struct osd_changer_t
|
||||
{
|
||||
cli_tool_t *parent;
|
||||
|
||||
uint64_t osd_num = 0;
|
||||
bool set_tags = false;
|
||||
std::vector<std::string> new_tags;
|
||||
bool set_reweight = false;
|
||||
double new_reweight = 1;
|
||||
bool set_noout = false;
|
||||
double new_noout = false;
|
||||
bool force = false;
|
||||
|
||||
json11::Json::object osd_cfg;
|
||||
uint64_t osd_cfg_mod_rev = 0;
|
||||
json11::Json::array compare, success;
|
||||
|
||||
int state = 0;
|
||||
std::function<bool(cli_result_t &)> cb;
|
||||
cli_result_t result;
|
||||
|
||||
bool is_done()
|
||||
{
|
||||
return state == 100;
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (state == 1)
|
||||
goto resume_1;
|
||||
else if (state == 2)
|
||||
goto resume_2;
|
||||
if (!osd_num)
|
||||
{
|
||||
result = (cli_result_t){ .err = EINVAL, .text = "OSD number is missing" };
|
||||
state = 100;
|
||||
return;
|
||||
}
|
||||
if (!set_tags && !set_reweight && !set_noout)
|
||||
{
|
||||
result = (cli_result_t){ .err = EINVAL, .text = "Nothing to update" };
|
||||
state = 100;
|
||||
return;
|
||||
}
|
||||
if (set_reweight && new_reweight < 0)
|
||||
{
|
||||
result = (cli_result_t){ .err = EINVAL, .text = "Reweight can't be negative" };
|
||||
state = 100;
|
||||
return;
|
||||
}
|
||||
parent->etcd_txn(json11::Json::object {
|
||||
{ "success", json11::Json::array {
|
||||
json11::Json::object {
|
||||
{ "request_range", json11::Json::object {
|
||||
{ "key", base64_encode(parent->cli->st_cli.etcd_prefix+"/osd/stats/"+std::to_string(osd_num)) },
|
||||
} },
|
||||
},
|
||||
json11::Json::object {
|
||||
{ "request_range", json11::Json::object {
|
||||
{ "key", base64_encode(parent->cli->st_cli.etcd_prefix+"/config/osd/"+std::to_string(osd_num)) },
|
||||
} },
|
||||
},
|
||||
} },
|
||||
});
|
||||
state = 1;
|
||||
resume_1:
|
||||
if (parent->waiting > 0)
|
||||
return;
|
||||
if (parent->etcd_err.err)
|
||||
{
|
||||
result = parent->etcd_err;
|
||||
state = 100;
|
||||
return;
|
||||
}
|
||||
{
|
||||
auto osd_stats = parent->cli->st_cli.parse_etcd_kv(parent->etcd_result["responses"][0]["response_range"]["kvs"][0]).value;
|
||||
if (!osd_stats.is_object() && !force)
|
||||
{
|
||||
result = (cli_result_t){ .err = ENOENT, .text = "OSD "+std::to_string(osd_num)+" does not exist. Use --force to set configuration anyway" };
|
||||
state = 100;
|
||||
return;
|
||||
}
|
||||
auto kv = parent->cli->st_cli.parse_etcd_kv(parent->etcd_result["responses"][1]["response_range"]["kvs"][0]);
|
||||
osd_cfg_mod_rev = kv.mod_revision;
|
||||
osd_cfg = kv.value.object_items();
|
||||
if (set_reweight)
|
||||
{
|
||||
if (new_reweight != 1)
|
||||
osd_cfg["reweight"] = new_reweight;
|
||||
else
|
||||
osd_cfg.erase("reweight");
|
||||
}
|
||||
if (set_tags)
|
||||
{
|
||||
if (new_tags.size())
|
||||
osd_cfg["tags"] = new_tags;
|
||||
else
|
||||
osd_cfg.erase("tags");
|
||||
}
|
||||
if (set_noout)
|
||||
{
|
||||
if (new_noout)
|
||||
osd_cfg["noout"] = true;
|
||||
else
|
||||
osd_cfg.erase("noout");
|
||||
}
|
||||
compare.push_back(json11::Json::object {
|
||||
{ "target", "MOD" },
|
||||
{ "key", base64_encode(parent->cli->st_cli.etcd_prefix+"/config/osd/"+std::to_string(osd_num)) },
|
||||
{ "result", "LESS" },
|
||||
{ "mod_revision", osd_cfg_mod_rev+1 },
|
||||
});
|
||||
if (osd_cfg.size())
|
||||
{
|
||||
success.push_back(json11::Json::object {
|
||||
{ "request_delete_range", json11::Json::object {
|
||||
{ "key", base64_encode(parent->cli->st_cli.etcd_prefix+"/config/osd/"+std::to_string(osd_num)) },
|
||||
} },
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
success.push_back(json11::Json::object {
|
||||
{ "request_put", json11::Json::object {
|
||||
{ "key", base64_encode(parent->cli->st_cli.etcd_prefix+"/config/osd/"+std::to_string(osd_num)) },
|
||||
{ "value", base64_encode(json11::Json(osd_cfg).dump()) },
|
||||
} },
|
||||
});
|
||||
}
|
||||
}
|
||||
parent->etcd_txn(json11::Json::object {
|
||||
{ "compare", compare },
|
||||
{ "success", success },
|
||||
});
|
||||
state = 2;
|
||||
resume_2:
|
||||
if (parent->waiting > 0)
|
||||
return;
|
||||
if (parent->etcd_err.err)
|
||||
{
|
||||
result = parent->etcd_err;
|
||||
state = 100;
|
||||
return;
|
||||
}
|
||||
if (!parent->etcd_result["succeeded"].bool_value())
|
||||
{
|
||||
result = (cli_result_t){ .err = EAGAIN, .text = "OSD "+std::to_string(osd_num)+" configuration was modified by someone else, please repeat your request" };
|
||||
state = 100;
|
||||
return;
|
||||
}
|
||||
result = (cli_result_t){
|
||||
.err = 0,
|
||||
.text = "OSD "+std::to_string(osd_num)+" configuration modified",
|
||||
.data = osd_cfg,
|
||||
};
|
||||
state = 100;
|
||||
}
|
||||
};
|
||||
|
||||
std::function<bool(cli_result_t &)> cli_tool_t::start_modify_osd(json11::Json cfg)
|
||||
{
|
||||
auto changer = new osd_changer_t();
|
||||
changer->parent = this;
|
||||
changer->osd_num = cfg["osd_num"].uint64_value();
|
||||
if (!cfg["tags"].is_null())
|
||||
{
|
||||
changer->set_tags = true;
|
||||
if (cfg["tags"].is_string())
|
||||
{
|
||||
if (cfg["tags"].string_value() != "")
|
||||
changer->new_tags = explode(",", cfg["tags"].string_value(), true);
|
||||
}
|
||||
else if (cfg["tags"].is_array())
|
||||
{
|
||||
for (auto item: cfg["tags"].array_items())
|
||||
changer->new_tags.push_back(item.as_string());
|
||||
}
|
||||
}
|
||||
if (!cfg["reweight"].is_null())
|
||||
{
|
||||
changer->set_reweight = true;
|
||||
changer->new_reweight = cfg["reweight"].number_value();
|
||||
}
|
||||
if (!cfg["noout"].is_null())
|
||||
{
|
||||
changer->set_noout = true;
|
||||
changer->new_noout = json_is_true(cfg["noout"]);
|
||||
}
|
||||
changer->force = cfg["force"].bool_value();
|
||||
return [changer](cli_result_t & result)
|
||||
{
|
||||
changer->loop();
|
||||
if (changer->is_done())
|
||||
{
|
||||
result = changer->result;
|
||||
delete changer;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user