Files
tromcho.net/src/cmd/cli_modify_osd.cpp
T

218 lines
6.9 KiB
C++

// 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 "json_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;
}
if (set_reweight && new_reweight > 1)
{
result = (cli_result_t){ .err = EINVAL, .text = "Reweight can't be larger than 1" };
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;
};
}