#include <errno.h>
#include <fstream>
+#include <type_traits>
#include "common/debug.h"
#include "common/errno.h"
cout << " -i mapfn --reweight-item name weight\n";
cout << " reweight a given item (and adjust ancestor\n"
<< " weights as needed)\n";
+ cout << " -i mapfn --add-bucket name type [--loc type name ...]\n"
+ << " insert a bucket into the hierachy at the given\n"
+ << " location\n";
cout << " -i mapfn --reweight recalculate all bucket weights\n";
cout << " -i mapfn --create-simple-rule name root type mode\n"
<< " create crush rule <name> to start from <root>,\n"
int size;
};
+template<typename... Args>
+bool argparse_withargs(std::vector<const char*> &args,
+ std::vector<const char*>::iterator& i,
+ std::ostream& oss,
+ const char* opt,
+ Args*... opts)
+{
+ if (!ceph_argparse_flag(args, i, opt, nullptr)) {
+ return false;
+ }
+ auto parse = [&](auto& opt) {
+ if (i == args.end()) {
+ oss << "expecting additional argument to " << opt;
+ return false;
+ }
+ using opt_t = std::remove_pointer_t<decay_t<decltype(opt)>>;
+ string err;
+ if constexpr (std::is_same_v<opt_t, string>) {
+ opt->assign(*i);
+ } else if constexpr (is_same_v<opt_t, int>) {
+ *opt = strict_strtol(*i, 10, &err);
+ } else if constexpr (is_same_v<opt_t, float>) {
+ *opt = strict_strtof(*i, &err);
+ }
+ i = args.erase(i);
+ if (err.empty())
+ return true;
+ else {
+ oss << err;
+ return false;
+ }
+ };
+ (... && parse(opts));
+ return true;
+}
+
+int do_add_bucket(CephContext* cct,
+ const char* me,
+ CrushWrapper& crush,
+ const string& add_name,
+ const string& add_type,
+ const map<string,string>& add_loc) {
+ int bucketno;
+ if (crush.name_exists(add_name)) {
+ cerr << me << " bucket '" << add_name << "' already exists" << std::endl;
+ return -EEXIST;
+ }
+ int type = crush.get_type_id(add_type);
+ if (type <= 0) {
+ cerr << me << " bad bucket type: " << add_type << std::endl;
+ return -EINVAL;
+ }
+ if (int r = crush.add_bucket(0, 0, CRUSH_HASH_DEFAULT, type, 0, nullptr, nullptr, &bucketno);
+ r < 0) {
+ cerr << me << " unable to add bucket: " << cpp_strerror(r) << std::endl;
+ return r;
+ }
+ if (int r = crush.set_item_name(bucketno, add_name); r < 0) {
+ cerr << me << " bad bucket name: " << add_name << std::endl;
+ return r;
+ }
+ if (!add_loc.empty()) {
+ if (!crush.check_item_loc(cct, bucketno, add_loc, (int*)nullptr)) {
+ if (int r = crush.move_bucket(cct, bucketno, add_loc); r < 0) {
+ cerr << me << " error moving bucket '" << add_name << "' to " << add_loc << std::endl;
+ return r;
+ }
+ }
+ }
+ return 0;
+}
+
int main(int argc, const char **argv)
{
vector<const char*> args;
argv_to_vec(argc, argv, args);
const char *me = argv[0];
- std::string infn, srcfn, outfn, add_name, remove_name, reweight_name;
+ std::string infn, srcfn, outfn, add_name, add_type, remove_name, reweight_name;
bool compile = false;
bool decompile = false;
bool check = false;
bool reweight = false;
int add_item = -1;
+ bool add_bucket = false;
bool update_item = false;
bool add_rule = false;
std::string rule_name, rule_root, rule_type, rule_mode, rule_device_class;
}
add_name.assign(*i);
i = args.erase(i);
+ } else if (argparse_withargs(args, i, err, "--add-bucket",
+ &add_name, &add_type)) {
+ if (!err.str().empty()) {
+ cerr << err.str() << std::endl;
+ return EXIT_FAILURE;
+ }
+ add_bucket = true;
} else if (ceph_argparse_witharg(args, i, &val, err, "--create-simple-rule", (char*)NULL)) {
rule_name.assign(val);
if (!err.str().empty()) {
return EXIT_FAILURE;
}
if (!check && !compile && !decompile && !build && !test && !reweight && !adjust && !tree && !dump &&
- add_item < 0 && !add_rule && !del_rule && full_location < 0 &&
+ add_item < 0 && !add_bucket && !add_rule && !del_rule && full_location < 0 &&
remove_name.empty() && reweight_name.empty()) {
cerr << "no action specified; -h for help" << std::endl;
return EXIT_FAILURE;
}
}
+ if (add_bucket) {
+ if (int r = do_add_bucket(cct.get(), me, crush, add_name, add_type, add_loc); !r) {
+ modified = true;
+ } else {
+ return r;
+ }
+ }
+
if (add_rule) {
if (crush.rule_exists(rule_name)) {
cerr << "rule " << rule_name << " already exists" << std::endl;