From ce7670938a6072d62e7a9ea779f8b1526bfa526d Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Thu, 10 Jan 2019 14:18:55 -0600 Subject: [PATCH] common/ceph_argparse: make parse_ip_port_vec handle list of addrs or addrvecs 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 --- src/common/ceph_argparse.cc | 42 ++++++++++++++++++++--------- src/test/ceph_argparse.cc | 53 +++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 12 deletions(-) diff --git a/src/common/ceph_argparse.cc b/src/common/ceph_argparse.cc index 3de9f091bde..818f8d07675 100644 --- a/src/common/ceph_argparse.cc +++ b/src/common/ceph_argparse.cc @@ -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& 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 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; } diff --git a/src/test/ceph_argparse.cc b/src/test/ceph_argparse.cc index 7ff4e3ca005..b1cc07d4f39 100644 --- a/src/test/ceph_argparse.cc +++ b/src/test/ceph_argparse.cc @@ -16,6 +16,7 @@ #include "gtest/gtest.h" #include +#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 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 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" -- 2.39.5