]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
common/ceph_argparse: make parse_ip_port_vec handle list of addrs or addrvecs
authorSage Weil <sage@redhat.com>
Thu, 10 Jan 2019 20:18:55 +0000 (14:18 -0600)
committerSage Weil <sage@redhat.com>
Wed, 16 Jan 2019 14:33:03 +0000 (08:33 -0600)
This helper is only used for mon_host.

We want to be able to list addrs or addrvecs.  It is slight wonky because
you could parse something like

 "1.2.3.4,5.6.7.8"

as either a list of addrs or a list of addrvecs.  Since the addr parse
takes a default type, it is preferred, so first try parsing as an addr
before proceeding.  Addrvecs that are size >1 must have brackets, so we
will always parse "[1.2.3.4,5.6.7.8]" unambiguously (since "[1.2.3.4"
won't parse as an addr).

Signed-off-by: Sage Weil <sage@redhat.com>
src/common/ceph_argparse.cc
src/test/ceph_argparse.cc

index 3de9f091bdefff961e6a5676bcf74bb8aa8f2231..818f8d0767514cda62744fe1091a43ec33be8b0f 100644 (file)
@@ -204,19 +204,37 @@ void ceph_arg_value_type(const char * nextargstr, bool *bool_option, bool *bool_
 
 bool parse_ip_port_vec(const char *s, vector<entity_addrvec_t>& vec, int type)
 {
-  const char *p = s;
-  const char *end = p + strlen(p);
-  while (p < end) {
-    entity_addr_t a;
-    //cout << " parse at '" << p << "'" << std::endl;
-    if (!a.parse(p, &p, type)) {
-      //dout(0) << " failed to parse address '" << p << "'" << dendl;
-      return false;
+  // first split by [ ;], which are not valid for an addrvec
+  list<string> items;
+  get_str_list(s, " ;", items);
+
+  for (auto& i : items) {
+    const char *s = i.c_str();
+    while (*s) {
+      const char *end;
+
+      // try parsing as an addr
+      entity_addr_t a;
+      if (a.parse(s, &end, type)) {
+       vec.push_back(entity_addrvec_t(a));
+       s = end;
+       if (*s == ',') {
+         ++s;
+       }
+       continue;
+      }
+
+      // ok, try parsing as an addrvec
+      entity_addrvec_t av;
+      if (!av.parse(s, &end)) {
+       return false;
+      }
+      vec.push_back(av);
+      s = end;
+      if (*s == ',') {
+       ++s;
+      }
     }
-    //cout << " got " << a << ", rest is '" << p << "'" << std::endl;
-    vec.push_back(entity_addrvec_t(a));
-    while (*p == ',' || *p == ' ' || *p == ';')
-      p++;
   }
   return true;
 }
index 7ff4e3ca005f271fbef613a431a57568a70f71f0..b1cc07d4f39dda520efec30657dac45213d7c72c 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "gtest/gtest.h"
 #include <vector>
+#include "include/stringify.h"
 
 /* Holds a std::vector with C-strings.
  * Will free() them properly in the destructor.
@@ -481,6 +482,58 @@ TEST(CephArgParse, env_to_vec) {
     EXPECT_EQ(string("c"), args[3]);
   }
 }
+
+TEST(CephArgParse, parse_ip_port_vec) {
+  struct {
+    const char *from;
+    int type;
+    const char *to;
+  } tests[] = {
+    { "1.2.3.4", entity_addr_t::TYPE_MSGR2,
+      "v2:1.2.3.4:0/0\n" },
+    { "v1:1.2.3.4", entity_addr_t::TYPE_MSGR2,
+      "v1:1.2.3.4:0/0\n" },
+    { "1.2.3.4", entity_addr_t::TYPE_LEGACY,
+      "v1:1.2.3.4:0/0\n" },
+    { "[::],1.2.3.4", entity_addr_t::TYPE_LEGACY,
+      "v1:[::]:0/0\nv1:1.2.3.4:0/0\n" },
+    { "v2:1.2.3.4:111,v1:5.6.7.8:222", entity_addr_t::TYPE_LEGACY,
+      "v2:1.2.3.4:111/0\nv1:5.6.7.8:222/0\n" },
+    { "v2:1.2.3.4:111 v1:5.6.7.8:222", entity_addr_t::TYPE_LEGACY,
+      "v2:1.2.3.4:111/0\nv1:5.6.7.8:222/0\n" },
+    { "[v2:1.2.3.4:111,v1:5.6.7.8:222] [v2:[::]:3300,v1:[::]:6789]",
+      entity_addr_t::TYPE_LEGACY,
+      "[v2:1.2.3.4:111/0,v1:5.6.7.8:222/0]\n[v2:[::]:3300/0,v1:[::]:6789/0]\n" },
+    { "[v2:1.2.3.4:111,v1:5.6.7.8:222],[v2:[::]:3300,v1:[::]:6789]",
+      entity_addr_t::TYPE_LEGACY,
+      "[v2:1.2.3.4:111/0,v1:5.6.7.8:222/0]\n[v2:[::]:3300/0,v1:[::]:6789/0]\n" },
+    { 0, 0, 0 },
+  };
+
+  for (unsigned i = 0; tests[i].from; ++i) {
+    vector<entity_addrvec_t> v;
+    cout << "-- " << tests[i].from << " type " << tests[i].type
+        << " ->\n" << tests[i].to;
+    ASSERT_TRUE(parse_ip_port_vec(tests[i].from, v, tests[i].type));
+    string actual;
+    for (auto s : v) {
+      actual += stringify(s) + "\n";
+    }
+    ASSERT_EQ(actual, tests[i].to);
+  }
+
+  const char *bad[] = {
+    "1.2.3.4 foo",
+    0
+  };
+  for (unsigned i = 0; bad[i]; ++i) {
+    vector<entity_addrvec_t> v;
+    cout << "bad " << bad[i] << std::endl;
+    ASSERT_FALSE(parse_ip_port_vec(bad[i], v));
+  }
+}
+
+
 /*
  * Local Variables:
  * compile-command: "cd .. ; make unittest_ceph_argparse && ./unittest_ceph_argparse"