]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
tools: monmaptool: support monmap features
authorJoao Eduardo Luis <joao@suse.de>
Mon, 22 Aug 2016 21:51:29 +0000 (22:51 +0100)
committerJoao Eduardo Luis <joao@suse.de>
Wed, 2 Nov 2016 23:50:12 +0000 (23:50 +0000)
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>
src/test/cli/monmaptool/add-exists.t
src/test/cli/monmaptool/feature-set-unset-list.t [new file with mode: 0644]
src/test/cli/monmaptool/help.t
src/test/cli/monmaptool/rm-nonexistent.t
src/test/cli/monmaptool/simple.t
src/tools/monmaptool.cc

index c23d51f26247930587079fc2478bb12d4c46fb3c..130c88cbfb6f80f4b299ca076713d7875cc736a7 100644 (file)
   $ 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
diff --git a/src/test/cli/monmaptool/feature-set-unset-list.t b/src/test/cli/monmaptool/feature-set-unset-list.t
new file mode 100644 (file)
index 0000000..cebec92
--- /dev/null
@@ -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
index 31a372a665393d149c5d948c037fa93620bf5aa8..d6267ef964d0d67d4d4d9910fd1aee5a3ee35934 100644 (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]
index e23ebf3e95c921c7f247ad6ac226dc1d4932041c..efba162558c23373d873b1e340907419fe4695b9 100644 (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
index ee7d6304bb26ac973da975f18508da77ef95f30a..cee2ab56767d5986f87e8e4578b8003371179b84 100644 (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]
index 515abd79829e6b95ca6760c57712e739638e8258..274f67c0c28d0734fcb15fca1735917c81760eae 100644 (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)