From e30e937c8962249af283a7571eb106ef444b79e3 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Wed, 30 May 2012 20:08:23 -0700 Subject: [PATCH] admin_socket: register command prefixes Allow any command prefix to be registered, provided it is separated by a space. Previously, we always matched against the first word. Signed-off-by: Sage Weil --- src/common/admin_socket.cc | 30 ++++++++++++++++++++++++------ src/common/admin_socket.h | 9 +++++++++ src/test/admin_socket.cc | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 6 deletions(-) diff --git a/src/common/admin_socket.cc b/src/common/admin_socket.cc index 5eaf68d441a8d..526f41eb94cfe 100644 --- a/src/common/admin_socket.cc +++ b/src/common/admin_socket.cc @@ -254,7 +254,7 @@ bool AdminSocket::do_accept() return false; } - char cmd[80]; + char cmd[1024]; int pos = 0; string c; while (1) { @@ -305,17 +305,35 @@ bool AdminSocket::do_accept() firstword = c.substr(0, c.find(" ")); m_lock.Lock(); - map::iterator p = m_hooks.find(firstword); + map::iterator p; + string match = c; + while (match.size()) { + p = m_hooks.find(match); + if (p != m_hooks.end()) + break; + + // drop right-most word + size_t pos = match.rfind(' '); + if (pos == std::string::npos) { + match.clear(); // we fail + break; + } else { + match.resize(pos); + } + } + bufferlist out; - if (p == m_hooks.end()) { - lderr(m_cct) << "AdminSocket: request '" << firstword << "' not defined" << dendl; + if (match.size() == 0) { + lderr(m_cct) << "AdminSocket: request '" << c << "' not defined" << dendl; } else { bool success = p->second->call(c, out); if (!success) { - ldout(m_cct, 0) << "AdminSocket: request '" << c << "' to " << p->second << " failed" << dendl; + ldout(m_cct, 0) << "AdminSocket: request '" << c << "' (" << match + << ") to " << p->second << " failed" << dendl; out.append("failed"); } else { - ldout(m_cct, 20) << "AdminSocket: request '" << c << "' to " << p->second + ldout(m_cct, 20) << "AdminSocket: request '" << c << "' (" << match + << ") to " << p->second << " returned " << out.length() << " bytes" << dendl; } uint32_t len = htonl(out.length()); diff --git a/src/common/admin_socket.h b/src/common/admin_socket.h index a7ba1f8e25cdf..00828ad2df926 100644 --- a/src/common/admin_socket.h +++ b/src/common/admin_socket.h @@ -42,6 +42,15 @@ public: /** * register an admin socket command * + * The command is registered under a command string. Incoming + * commands are split by space and matched against the longest + * registered command. For example, if 'foo' and 'foo bar' are + * registered, and an incoming command is 'foo bar baz', it is + * matched with 'foo bar', while 'foo fud' will match 'foo'. + * + * The entire incoming command string is passed to the registred + * hook. + * * @param command command string * @param hook implementaiton * @param help help text. if empty, command will not be included in 'help' output. diff --git a/src/test/admin_socket.cc b/src/test/admin_socket.cc index 68893a3920155..05a9efa50e934 100644 --- a/src/test/admin_socket.cc +++ b/src/test/admin_socket.cc @@ -89,3 +89,38 @@ TEST(AdminSocket, RegisterCommand) { ASSERT_EQ("yes", result); ASSERT_EQ(true, asoct.shutdown()); } + +class MyTest2 : public AdminSocketHook { + bool call(std::string command, bufferlist& result) { + result.append("yessir"); + return true; + } +}; + +TEST(AdminSocket, RegisterCommandPrefixes) { + std::auto_ptr + asokc(new AdminSocket(g_ceph_context)); + AdminSocketTest asoct(asokc.get()); + ASSERT_EQ(true, asoct.shutdown()); + ASSERT_EQ(true, asoct.init(get_rand_socket_path())); + AdminSocketClient client(get_rand_socket_path()); + ASSERT_EQ(0, asoct.m_asokc->register_command("test", new MyTest(), "")); + ASSERT_EQ(0, asoct.m_asokc->register_command("test command", new MyTest2(), "")); + string result; + ASSERT_EQ("", client.do_request("test", &result)); + ASSERT_EQ("yes", result); + ASSERT_EQ("", client.do_request("test command", &result)); + ASSERT_EQ("yessir", result); + ASSERT_EQ("", client.do_request("test command post", &result)); + ASSERT_EQ("yessir", result); + ASSERT_EQ("", client.do_request("test command post", &result)); + ASSERT_EQ("yessir", result); + ASSERT_EQ("", client.do_request("test this thing", &result)); + ASSERT_EQ("yes", result); + + ASSERT_EQ("", client.do_request("test command post", &result)); + ASSERT_EQ("yes", result); + ASSERT_EQ("", client.do_request("test this thing", &result)); + ASSERT_EQ("yes", result); + ASSERT_EQ(true, asoct.shutdown()); +} -- 2.39.5