tools: monmaptool: support monmap features

Adds three new options:

  --feature-list     will list monmap features, as well as available
                     features.
  --feature-set      sets a feature on the monmap
  --feature-unset    unsets a feature on the monmap

Signed-off-by: Joao Eduardo Luis <joao@suse.de>
This commit is contained in:
Joao Eduardo Luis 2016-08-22 22:51:29 +01:00
parent acf4b8604c
commit f0e29abe4c
6 changed files with 306 additions and 6 deletions

View File

@ -11,7 +11,12 @@
$ monmaptool --add foo 3.4.5.6:7890 mymonmap
monmaptool: monmap file mymonmap
monmaptool: map already contains mon.foo
usage: [--print] [--create [--clobber][--fsid uuid]] [--generate] [--set-initial-members] [--add name 1.2.3.4:567] [--rm name] <mapfilename>
usage: [--print] [--create [--clobber][--fsid uuid]]
[--generate] [--set-initial-members]
[--add name 1.2.3.4:567] [--rm name]
[--feature-list [plain|parseable]]
[--feature-set <value> [--optional|--persistent]]
[--feature-unset <value> [--optional|--persistent]] <mapfilename>
[1]
$ monmaptool --print mymonmap

View File

@ -0,0 +1,91 @@
$ monmaptool --create --add a 10.10.10.10:1234 /tmp/test.monmap.1234
monmaptool: monmap file /tmp/test.monmap.1234
monmaptool: generated fsid [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} (re)
monmaptool: writing epoch 0 to /tmp/test.monmap.1234 (1 monitors)
$ monmaptool --feature-list --feature-list plain --feature-list parseable /tmp/test.monmap.1234
monmaptool: monmap file /tmp/test.monmap.1234
MONMAP FEATURES:
persistent: [none]
optional: [none]
required: [none]
AVAILABLE FEATURES:
supported: [kraken(1)]
persistent: [kraken(1)]
MONMAP FEATURES:
persistent: [none]
optional: [none]
required: [none]
AVAILABLE FEATURES:
supported: [kraken(1)]
persistent: [kraken(1)]
monmap:persistent:[none]
monmap:optional:[none]
monmap:required:[none]
available:supported:[kraken(1)]
available:persistent:[kraken(1)]
$ monmaptool --feature-set foo /tmp/test.monmap.1234
unknown features name 'foo' or unable to parse value: Expected option value to be integer, got 'foo'
usage: [--print] [--create [--clobber][--fsid uuid]]
[--generate] [--set-initial-members]
[--add name 1.2.3.4:567] [--rm name]
[--feature-list [plain|parseable]]
[--feature-set <value> [--optional|--persistent]]
[--feature-unset <value> [--optional|--persistent]] <mapfilename>
[1]
$ monmaptool --feature-set kraken --feature-set 16 --optional --feature-set 32 --persistent /tmp/test.monmap.1234
monmaptool: monmap file /tmp/test.monmap.1234
monmaptool: writing epoch 0 to /tmp/test.monmap.1234 (1 monitors)
$ monmaptool --feature-list /tmp/test.monmap.1234
monmaptool: monmap file /tmp/test.monmap.1234
MONMAP FEATURES:
persistent: [kraken(1),unknown(32)]
optional: [unknown(16)]
required: [kraken(1),unknown(16),unknown(32)]
AVAILABLE FEATURES:
supported: [kraken(1)]
persistent: [kraken(1)]
$ monmaptool --feature-unset 32 --optional --feature-list /tmp/test.monmap.1234
monmaptool: monmap file /tmp/test.monmap.1234
MONMAP FEATURES:
persistent: [kraken(1),unknown(32)]
optional: [unknown(16)]
required: [kraken(1),unknown(16),unknown(32)]
AVAILABLE FEATURES:
supported: [kraken(1)]
persistent: [kraken(1)]
monmaptool: writing epoch 0 to /tmp/test.monmap.1234 (1 monitors)
$ monmaptool --feature-unset 32 --persistent --feature-unset 16 --optional --feature-list /tmp/test.monmap.1234
monmaptool: monmap file /tmp/test.monmap.1234
MONMAP FEATURES:
persistent: [kraken(1)]
optional: [none]
required: [kraken(1)]
AVAILABLE FEATURES:
supported: [kraken(1)]
persistent: [kraken(1)]
monmaptool: writing epoch 0 to /tmp/test.monmap.1234 (1 monitors)
$ monmaptool --feature-unset kraken --feature-list /tmp/test.monmap.1234
monmaptool: monmap file /tmp/test.monmap.1234
MONMAP FEATURES:
persistent: [none]
optional: [none]
required: [none]
AVAILABLE FEATURES:
supported: [kraken(1)]
persistent: [kraken(1)]
monmaptool: writing epoch 0 to /tmp/test.monmap.1234 (1 monitors)
$ rm /tmp/test.monmap.1234

View File

@ -1,3 +1,8 @@
$ monmaptool --help
usage: [--print] [--create [--clobber][--fsid uuid]] [--generate] [--set-initial-members] [--add name 1.2.3.4:567] [--rm name] <mapfilename>
usage: [--print] [--create [--clobber][--fsid uuid]]
[--generate] [--set-initial-members]
[--add name 1.2.3.4:567] [--rm name]
[--feature-list [plain|parseable]]
[--feature-set <value> [--optional|--persistent]]
[--feature-unset <value> [--optional|--persistent]] <mapfilename>
[1]

View File

@ -9,7 +9,12 @@
monmaptool: monmap file mymonmap
monmaptool: removing doesnotexist
monmaptool: map does not contain doesnotexist
usage: [--print] [--create [--clobber][--fsid uuid]] [--generate] [--set-initial-members] [--add name 1.2.3.4:567] [--rm name] <mapfilename>
usage: [--print] [--create [--clobber][--fsid uuid]]
[--generate] [--set-initial-members]
[--add name 1.2.3.4:567] [--rm name]
[--feature-list [plain|parseable]]
[--feature-set <value> [--optional|--persistent]]
[--feature-unset <value> [--optional|--persistent]] <mapfilename>
[1]
$ monmaptool --print mymonmap

View File

@ -1,4 +1,9 @@
$ monmaptool
monmaptool: must specify monmap filename
usage: [--print] [--create [--clobber][--fsid uuid]] [--generate] [--set-initial-members] [--add name 1.2.3.4:567] [--rm name] <mapfilename>
usage: [--print] [--create [--clobber][--fsid uuid]]
[--generate] [--set-initial-members]
[--add name 1.2.3.4:567] [--rm name]
[--feature-list [plain|parseable]]
[--feature-set <value> [--optional|--persistent]]
[--feature-unset <value> [--optional|--persistent]] <mapfilename>
[1]

View File

@ -24,10 +24,146 @@ using namespace std;
void usage()
{
cout << " usage: [--print] [--create [--clobber][--fsid uuid]] [--generate] [--set-initial-members] [--add name 1.2.3.4:567] [--rm name] <mapfilename>" << std::endl;
cout << " usage: [--print] [--create [--clobber][--fsid uuid]]\n"
<< " [--generate] [--set-initial-members]\n"
<< " [--add name 1.2.3.4:567] [--rm name]\n"
<< " [--feature-list [plain|parseable]]\n"
<< " [--feature-set <value> [--optional|--persistent]]\n"
<< " [--feature-unset <value> [--optional|--persistent]] "
<< "<mapfilename>"
<< std::endl;
exit(1);
}
struct feature_op_t {
enum type_t {
PERSISTENT,
OPTIONAL,
PLAIN,
PARSEABLE,
NONE
};
enum op_t {
OP_SET,
OP_UNSET,
OP_LIST
};
op_t op;
type_t type;
mon_feature_t feature;
feature_op_t() : op(OP_LIST), type(NONE) { }
// default to 'persistent' feature if not specified
feature_op_t(op_t o) : op(o), type(PERSISTENT) { }
feature_op_t(op_t o, type_t t) : op(o), type(t) { }
feature_op_t(op_t o, type_t t, mon_feature_t &f) :
op(o), type(t), feature(t) { }
void set_optional() {
type = OPTIONAL;
}
void set_persistent() {
type = PERSISTENT;
}
bool parse_value(string &s, ostream *errout = NULL) {
feature = ceph::features::mon::get_feature_by_name(s);
if (feature != ceph::features::mon::FEATURE_NONE) {
return true;
}
// try parsing as numerical value
uint64_t feature_val;
string interr;
feature_val = strict_strtoll(s.c_str(), 10, &interr);
if (!interr.empty()) {
if (errout) {
*errout << "unknown features name '" << s
<< "' or unable to parse value: " << interr << std::endl;
}
return false;
}
feature = mon_feature_t(feature_val);
return true;
}
};
void features_list(feature_op_t &f, MonMap &m)
{
if (f.type == feature_op_t::type_t::PLAIN) {
cout << "MONMAP FEATURES:" << std::endl;
cout << " persistent: ";
m.persistent_features.print_with_value(cout);
cout << std::endl;
cout << " optional: ";
m.optional_features.print_with_value(cout);
cout << std::endl;
cout << " required: ";
m.get_required_features().print_with_value(cout);
cout << std::endl;
cout << std::endl;
cout << "AVAILABLE FEATURES:" << std::endl;
cout << " supported: ";
ceph::features::mon::get_supported().print_with_value(cout);
cout << std::endl;
cout << " persistent: ";
ceph::features::mon::get_persistent().print_with_value(cout);
cout << std::endl;
} else if (f.type == feature_op_t::type_t::PARSEABLE) {
cout << "monmap:persistent:";
m.persistent_features.print_with_value(cout);
cout << std::endl;
cout << "monmap:optional:";
m.optional_features.print_with_value(cout);
cout << std::endl;
cout << "monmap:required:";
m.get_required_features().print_with_value(cout);
cout << std::endl;
cout << "available:supported:";
ceph::features::mon::get_supported().print_with_value(cout);
cout << std::endl;
cout << "available:persistent:";
ceph::features::mon::get_persistent().print_with_value(cout);
cout << std::endl;
}
}
bool handle_features(list<feature_op_t>& lst, MonMap &m)
{
if (lst.empty())
return false;
bool modified = false;
for (auto &f : lst) {
if (f.op == feature_op_t::op_t::OP_LIST) {
features_list(f, m);
} else if (f.op == feature_op_t::op_t::OP_SET ||
f.op == feature_op_t::op_t::OP_UNSET) {
modified = true;
mon_feature_t &target =
( f.type == feature_op_t::type_t::OPTIONAL ?
m.optional_features : m.persistent_features );
if (f.op == feature_op_t::op_t::OP_SET) {
target.set_feature(f.feature);
} else {
target.unset_feature(f.feature);
}
} else {
cerr << "unknow feature operation type '" << f.op << "'" << std::endl;
}
}
return modified;
}
int main(int argc, const char **argv)
{
vector<const char*> args;
@ -40,10 +176,12 @@ int main(int argc, const char **argv)
bool create = false;
bool clobber = false;
bool modified = false;
bool show_features = false;
bool generate = false;
bool filter = false;
map<string,entity_addr_t> add;
list<string> rm;
list<feature_op_t> features;
global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY,
CINIT_FLAG_NO_DEFAULT_CONFIG_FILE);
@ -82,6 +220,53 @@ int main(int argc, const char **argv)
} else if (ceph_argparse_witharg(args, i, &val, "--rm", (char*)NULL)) {
rm.push_back(val);
modified = true;
} else if (ceph_argparse_flag(args, i, "--feature-list", (char*)NULL)) {
string format = *i;
if (format == "plain" || format == "parseable") {
i = args.erase(i);
} else {
format = "plain";
}
feature_op_t f(feature_op_t::op_t::OP_LIST,
feature_op_t::type_t::PLAIN);
if (format == "parseable") {
f.type = feature_op_t::type_t::PARSEABLE;
} else if (format != "plain") {
cerr << "invalid format type for list: '" << val << "'" << std::endl;
usage();
}
features.push_back(f);
show_features = true;
} else if (ceph_argparse_witharg(args, i, &val,
"--feature-set", (char*)NULL)) {
// parse value
feature_op_t f(feature_op_t::op_t::OP_SET);
if (!f.parse_value(val, &cerr)) {
usage();
}
features.push_back(f);
} else if (ceph_argparse_witharg(args, i, &val,
"--feature-unset", (char*)NULL)) {
// parse value
feature_op_t f(feature_op_t::op_t::OP_UNSET);
if (!f.parse_value(val, &cerr)) {
usage();
}
features.push_back(f);
} else if (ceph_argparse_flag(args, i, "--optional", (char*)NULL)) {
if (features.empty()) {
usage();
}
features.back().set_optional();
} else if (ceph_argparse_flag(args, i, "--persistent", (char*)NULL)) {
if (features.empty()) {
usage();
}
features.back().set_persistent();
} else {
++i;
}
@ -178,7 +363,11 @@ int main(int argc, const char **argv)
monmap.remove(*p);
}
if (!print && !modified)
if (handle_features(features, monmap)) {
modified = true;
}
if (!print && !modified && !show_features)
usage();
if (print)