Make CLI functions usable in library form
Return results and errors in a variable instead of just printing them, separate vitastor-cli main() from cli_tool_t, move positional argument parsing to CLI main from command implementations.
This commit is contained in:
+59
-31
@@ -13,6 +13,7 @@ struct image_changer_t
|
||||
std::string image_name;
|
||||
std::string new_name;
|
||||
uint64_t new_size = 0;
|
||||
bool force_size = false;
|
||||
bool set_readonly = false, set_readwrite = false, force = false;
|
||||
// interval between fsyncs
|
||||
int fsync_interval = 128;
|
||||
@@ -23,7 +24,8 @@ struct image_changer_t
|
||||
bool has_children = false;
|
||||
|
||||
int state = 0;
|
||||
std::function<bool(void)> cb;
|
||||
std::function<bool(cli_result_t &)> cb;
|
||||
cli_result_t result;
|
||||
|
||||
bool is_done()
|
||||
{
|
||||
@@ -36,6 +38,18 @@ struct image_changer_t
|
||||
goto resume_1;
|
||||
else if (state == 2)
|
||||
goto resume_2;
|
||||
if (image_name == "")
|
||||
{
|
||||
result = (cli_result_t){ .err = EINVAL, .text = "Image name is missing" };
|
||||
state = 100;
|
||||
return;
|
||||
}
|
||||
if (new_size != 0 && (new_size % 4096) && !force_size)
|
||||
{
|
||||
result = (cli_result_t){ .err = EINVAL, .text = "Image size should be a multiple of 4096" };
|
||||
state = 100;
|
||||
return;
|
||||
}
|
||||
for (auto & ic: parent->cli->st_cli.inode_config)
|
||||
{
|
||||
if (ic.second.name == image_name)
|
||||
@@ -46,14 +60,16 @@ struct image_changer_t
|
||||
}
|
||||
if (new_name != "" && ic.second.name == new_name)
|
||||
{
|
||||
fprintf(stderr, "Image %s already exists\n", new_name.c_str());
|
||||
exit(1);
|
||||
result = (cli_result_t){ .err = EEXIST, .text = "Image "+new_name+" already exists" };
|
||||
state = 100;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!inode_num)
|
||||
{
|
||||
fprintf(stderr, "Image %s does not exist\n", image_name.c_str());
|
||||
exit(1);
|
||||
result = (cli_result_t){ .err = ENOENT, .text = "Image "+image_name+" does not exist" };
|
||||
state = 100;
|
||||
return;
|
||||
}
|
||||
for (auto & ic: parent->cli->st_cli.inode_config)
|
||||
{
|
||||
@@ -68,7 +84,7 @@ struct image_changer_t
|
||||
(!new_size || cfg.size == new_size) &&
|
||||
(new_name == "" || new_name == image_name))
|
||||
{
|
||||
printf("No change\n");
|
||||
result = (cli_result_t){ .text = "No change" };
|
||||
state = 100;
|
||||
return;
|
||||
}
|
||||
@@ -79,23 +95,29 @@ struct image_changer_t
|
||||
// Check confirmation when trimming an image with children
|
||||
if (has_children && !force)
|
||||
{
|
||||
fprintf(stderr, "Image %s has children. Refusing to shrink it without --force\n", image_name.c_str());
|
||||
exit(1);
|
||||
result = (cli_result_t){ .err = EINVAL, .text = "Image "+image_name+" has children. Refusing to shrink it without --force" };
|
||||
state = 100;
|
||||
return;
|
||||
}
|
||||
// Shrink the image first
|
||||
cb = parent->start_rm(json11::Json::object {
|
||||
cb = parent->start_rm_data(json11::Json::object {
|
||||
{ "inode", INODE_NO_POOL(inode_num) },
|
||||
{ "pool", (uint64_t)INODE_POOL(inode_num) },
|
||||
{ "fsync-interval", fsync_interval },
|
||||
{ "min-offset", new_size },
|
||||
{ "min-offset", ((new_size+4095)/4096)*4096 },
|
||||
});
|
||||
resume_1:
|
||||
while (!cb())
|
||||
while (!cb(result))
|
||||
{
|
||||
state = 1;
|
||||
return;
|
||||
}
|
||||
cb = NULL;
|
||||
if (result.err)
|
||||
{
|
||||
state = 100;
|
||||
return;
|
||||
}
|
||||
}
|
||||
cfg.size = new_size;
|
||||
}
|
||||
@@ -109,8 +131,9 @@ resume_1:
|
||||
// Check confirmation when making an image with children read-write
|
||||
if (has_children && !force)
|
||||
{
|
||||
fprintf(stderr, "Image %s has children. Refusing to make it read-write without --force\n", image_name.c_str());
|
||||
exit(1);
|
||||
result = (cli_result_t){ .err = EINVAL, .text = "Image "+image_name+" has children. Refusing to make it read-write without --force" };
|
||||
state = 100;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (new_name != "")
|
||||
@@ -178,34 +201,38 @@ resume_1:
|
||||
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())
|
||||
{
|
||||
fprintf(stderr, "Image %s was modified by someone else, please repeat your request\n", image_name.c_str());
|
||||
exit(1);
|
||||
result = (cli_result_t){ .err = EAGAIN, .text = "Image "+image_name+" was modified by someone else, please repeat your request" };
|
||||
state = 100;
|
||||
return;
|
||||
}
|
||||
printf("Image %s modified\n", image_name.c_str());
|
||||
// Save into inode_config for library users to be able to take it from there immediately
|
||||
cfg.mod_revision = parent->etcd_result["responses"][0]["response_put"]["header"]["revision"].uint64_value();
|
||||
if (new_name != "")
|
||||
{
|
||||
parent->cli->st_cli.inode_by_name.erase(image_name);
|
||||
}
|
||||
parent->cli->st_cli.insert_inode_config(cfg);
|
||||
result = (cli_result_t){ .err = 0, .text = "Image "+image_name+" modified" };
|
||||
state = 100;
|
||||
}
|
||||
};
|
||||
|
||||
std::function<bool(void)> cli_tool_t::start_modify(json11::Json cfg)
|
||||
std::function<bool(cli_result_t &)> cli_tool_t::start_modify(json11::Json cfg)
|
||||
{
|
||||
json11::Json::array cmd = cfg["command"].array_items();
|
||||
auto changer = new image_changer_t();
|
||||
changer->parent = this;
|
||||
changer->image_name = cmd.size() > 1 ? cmd[1].string_value() : "";
|
||||
if (changer->image_name == "")
|
||||
{
|
||||
fprintf(stderr, "Image name is missing\n");
|
||||
exit(1);
|
||||
}
|
||||
changer->image_name = cfg["image"].string_value();
|
||||
changer->new_name = cfg["rename"].string_value();
|
||||
changer->new_size = parse_size(cfg["resize"].string_value());
|
||||
if (changer->new_size != 0 && (changer->new_size % 4096))
|
||||
{
|
||||
fprintf(stderr, "Image size should be a multiple of 4096\n");
|
||||
exit(1);
|
||||
}
|
||||
changer->new_size = parse_size(cfg["resize"].as_string());
|
||||
changer->force_size = cfg["force_size"].bool_value();
|
||||
changer->force = cfg["force"].bool_value();
|
||||
changer->set_readonly = cfg["readonly"].bool_value();
|
||||
changer->set_readwrite = cfg["readwrite"].bool_value();
|
||||
@@ -213,11 +240,12 @@ std::function<bool(void)> cli_tool_t::start_modify(json11::Json cfg)
|
||||
if (!changer->fsync_interval)
|
||||
changer->fsync_interval = 128;
|
||||
// FIXME Check that the image doesn't have children when shrinking
|
||||
return [changer]()
|
||||
return [changer](cli_result_t & result)
|
||||
{
|
||||
changer->loop();
|
||||
if (changer->is_done())
|
||||
{
|
||||
result = changer->result;
|
||||
delete changer;
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user