return false;
}
- char cmd[80];
+ char cmd[1024];
int pos = 0;
string c;
while (1) {
firstword = c.substr(0, c.find(" "));
m_lock.Lock();
- map<string,AdminSocketHook*>::iterator p = m_hooks.find(firstword);
+ map<string,AdminSocketHook*>::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());
/**
* 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.
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<AdminSocket>
+ 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());
+}