summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bin/agent/ca_command_mgr.cc14
-rw-r--r--src/bin/agent/ca_command_mgr.h2
-rw-r--r--src/bin/agent/ca_messages.mes5
-rw-r--r--src/bin/shell/tests/.gitignore3
-rw-r--r--src/lib/config/config_messages.mes7
-rw-r--r--src/lib/config/hooked_command_mgr.cc119
-rw-r--r--src/lib/config/hooked_command_mgr.h42
-rw-r--r--src/lib/config/tests/command_mgr_unittests.cc216
-rw-r--r--src/lib/hooks/callout_manager.h4
-rw-r--r--src/lib/hooks/library_handle.cc2
-rw-r--r--src/lib/hooks/library_handle.h4
-rw-r--r--src/lib/hooks/server_hooks.cc12
-rw-r--r--src/lib/hooks/server_hooks.h13
-rw-r--r--src/lib/hooks/tests/callout_manager_unittest.cc8
-rw-r--r--src/lib/hooks/tests/full_callout_library.cc4
-rw-r--r--src/lib/hooks/tests/load_callout_library.cc4
-rw-r--r--src/lib/hooks/tests/server_hooks_unittest.cc13
17 files changed, 191 insertions, 281 deletions
diff --git a/src/bin/agent/ca_command_mgr.cc b/src/bin/agent/ca_command_mgr.cc
index f2081e286f..85e998db61 100644
--- a/src/bin/agent/ca_command_mgr.cc
+++ b/src/bin/agent/ca_command_mgr.cc
@@ -97,18 +97,12 @@ CtrlAgentCommandMgr::handleCommandInternal(std::string cmd_name,
ElementPtr answer_list = Element::createList();
- // Before the command is forwarded it should be processed by the hooks libraries.
+ // Before the command is forwarded we check if there are any hooks libraries
+ // which would process the command.
if (HookedCommandMgr::delegateCommandToHookLibrary(cmd_name, params, original_cmd,
answer_list)) {
- // If the hooks libraries set the 'skip' flag, they indicate that the
- // commands have been processed. The answer_list should contain the list
- // of answers with each answer pertaining to one service.
- if (callout_handle_->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
- LOG_DEBUG(agent_logger, isc::log::DBGLVL_COMMAND,
- CTRL_AGENT_COMMAND_PROCESS_SKIP)
- .arg(cmd_name);
- return (answer_list);
- }
+ // The command has been processed by hooks library. Return the result.
+ return (answer_list);
}
// We don't know whether the hooks libraries modified the value of the
diff --git a/src/bin/agent/ca_command_mgr.h b/src/bin/agent/ca_command_mgr.h
index 819fa3399c..fef155c75d 100644
--- a/src/bin/agent/ca_command_mgr.h
+++ b/src/bin/agent/ca_command_mgr.h
@@ -30,8 +30,6 @@ public:
/// it is also intended to forward commands to the respective Kea servers
/// when the command is not supported directly by the Control Agent.
///
-/// @todo This Command Manager doesn't yet support forwarding commands.
-///
/// The @ref CtrlAgentCommandMgr is implemented as a singleton. The commands
/// are registered using @c CtrlAgentCommandMgr::instance().registerCommand().
/// The @ref CtrlAgentResponseCreator uses the sole instance of the Command
diff --git a/src/bin/agent/ca_messages.mes b/src/bin/agent/ca_messages.mes
index 181b4b4b91..ac042d3df8 100644
--- a/src/bin/agent/ca_messages.mes
+++ b/src/bin/agent/ca_messages.mes
@@ -19,11 +19,6 @@ This debug message is issued when the Control Agent failed forwarding a
received command to one of the Kea servers. The second argument provides
the details of the error.
-% CTRL_AGENT_COMMAND_PROCESS_SKIP command %1 already processed by hooks libraries, skipping
-This debug message is issued when the Control Agent skips processing
-received command because it has determined that the hooks libraries
-already processed the command.
-
% CTRL_AGENT_CONFIG_CHECK_FAIL Control Agent configuration check failed: %1
This error message indicates that the CA had failed configuration
check. Details are provided. Additional details may be available
diff --git a/src/bin/shell/tests/.gitignore b/src/bin/shell/tests/.gitignore
index 13066d0906..ed32d08a60 100644
--- a/src/bin/shell/tests/.gitignore
+++ b/src/bin/shell/tests/.gitignore
@@ -1 +1,2 @@
-shell_process_tests.sh
+/shell_process_tests.sh
+/shell_unittest.py
diff --git a/src/lib/config/config_messages.mes b/src/lib/config/config_messages.mes
index 4262f64673..a40bd2b569 100644
--- a/src/lib/config/config_messages.mes
+++ b/src/lib/config/config_messages.mes
@@ -16,13 +16,6 @@ This debug message indicates that the daemon started supporting specified
command. The handler for the registered command includes a parameter holding
entire command to be processed.
-% COMMAND_HOOK_RECEIVE_SKIP command %1 has been handled by the hook library which returned the skip state
-This debug message is issued when a hook library has processed the control
-command and returned the skip status. The callout should have set the
-'response' argument which contains the result of processing the command.
-The Command Manager skips processing of this command and simply returns
-the response generated by the hook library.
-
% COMMAND_PROCESS_ERROR1 Error while processing command: %1
This warning message indicates that the server encountered an error while
processing received command. Additional information will be provided, if
diff --git a/src/lib/config/hooked_command_mgr.cc b/src/lib/config/hooked_command_mgr.cc
index 690a3595ff..9a8e091c6a 100644
--- a/src/lib/config/hooked_command_mgr.cc
+++ b/src/lib/config/hooked_command_mgr.cc
@@ -8,33 +8,13 @@
#include <config/hooked_command_mgr.h>
#include <config/config_log.h>
#include <hooks/hooks_manager.h>
+#include <hooks/server_hooks.h>
#include <boost/pointer_cast.hpp>
+#include <vector>
using namespace isc::data;
using namespace isc::hooks;
-namespace {
-
-/// @brief Structure that holds registered hook indexes.
-struct CommandMgrHooks {
- /// @brief Index for "control_command_receive" hook point.
- int hook_index_control_command_receive_;
-
- /// @brief Constructor that registers hook points for HookedCommandMgr
- CommandMgrHooks() {
- hook_index_control_command_receive_ =
- HooksManager::registerHook("control_command_receive");
- }
-};
-
-// Declare a hooks object. As this is outside any function or method, it
-// will be instantiated (and the constructor run) when the module is loaded.
-// As a result, the hook indexes will be defined before any method in this
-// module is called.
-CommandMgrHooks Hooks;
-
-} // end of anonymous namespace
-
namespace isc {
namespace config {
@@ -43,13 +23,13 @@ HookedCommandMgr::HookedCommandMgr()
}
bool
-HookedCommandMgr::delegateCommandToHookLibrary(std::string& cmd_name,
- ConstElementPtr& params,
- ConstElementPtr& original_cmd,
+HookedCommandMgr::delegateCommandToHookLibrary(const std::string& cmd_name,
+ const ConstElementPtr& params,
+ const ConstElementPtr& original_cmd,
ElementPtr& answer) {
ConstElementPtr hook_response;
- if (HooksManager::calloutsPresent(Hooks.hook_index_control_command_receive_)) {
+ if (HooksManager::commandHandlersPresent(cmd_name)) {
callout_handle_ = HooksManager::createCalloutHandle();
@@ -66,21 +46,11 @@ HookedCommandMgr::delegateCommandToHookLibrary(std::string& cmd_name,
callout_handle_->setArgument("command", command);
callout_handle_->setArgument("response", hook_response);
- HooksManager::callCallouts(Hooks.hook_index_control_command_receive_,
- *callout_handle_);
+ HooksManager::callCommandHandlers(cmd_name, *callout_handle_);
// The callouts should set the response.
callout_handle_->getArgument("response", hook_response);
-
- // The hook library can modify the command or arguments. Thus, we
- // retrieve the command returned by the callouts and use it as input
- // to the local command handler.
- ConstElementPtr hook_command;
- callout_handle_->getArgument("command", hook_command);
- cmd_name = parseCommand(params, hook_command);
- original_cmd = hook_command;
-
answer = boost::const_pointer_cast<Element>(hook_response);
return (true);
@@ -98,33 +68,62 @@ HookedCommandMgr::handleCommand(const std::string& cmd_name,
"Manager: this is a programming error");
}
- std::string mutable_cmd_name = cmd_name;
- ConstElementPtr mutable_params = params;
- ConstElementPtr mutable_cmd = original_cmd;
-
- ElementPtr hook_response;
- if (delegateCommandToHookLibrary(mutable_cmd_name, mutable_params,
- mutable_cmd, hook_response)) {
- if (callout_handle_->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
- LOG_DEBUG(command_logger, DBG_COMMAND, COMMAND_HOOK_RECEIVE_SKIP)
- .arg(cmd_name);
-
+ // The 'list-commands' is a special case. Hook libraries do not implement
+ // this command. We determine what commands are supported by the hook
+ // libraries by checking what hook points are present that have callouts
+ // registered.
+ if ((cmd_name != "list-commands")) {
+ ElementPtr hook_response;
+ // Check if there are any hooks libraries to process this command.
+ if (delegateCommandToHookLibrary(cmd_name, params, original_cmd,
+ hook_response)) {
+ // Hooks libraries processed this command so simply return a
+ // result.
return (hook_response);
}
+
}
- // If we're here it means that the callouts weren't called or the 'skip'
- // status wasn't returned. The latter is the case when the 'list-commands'
- // is being processed. Anyhow, we need to handle the command using local
- // Command Mananger.
- ConstElementPtr response = BaseCommandMgr::handleCommand(mutable_cmd_name,
- mutable_params,
- mutable_cmd);
-
- // For the 'list-commands' case we will have to combine commands supported
- // by the hook libraries with the commands that this Command Manager supports.
- if ((mutable_cmd_name == "list-commands") && hook_response && response) {
- response = combineCommandsLists(hook_response, response);
+ // If we're here it means that the callouts weren't called. We need
+ // to handle the command using local Command Mananger.
+ ConstElementPtr response = BaseCommandMgr::handleCommand(cmd_name,
+ params,
+ original_cmd);
+
+ // If we're processing 'list-commands' command we may need to include
+ // commands supported by hooks libraries in the response.
+ if (cmd_name == "list-commands") {
+ // Hooks names can be used to decode what commands are supported.
+ const std::vector<std::string>& hooks =
+ ServerHooks::getServerHooksPtr()->getHookNames();
+
+ // Only update the response if there are any hooks present.
+ if (!hooks.empty()) {
+ ElementPtr hooks_commands = Element::createList();
+ for (auto h = hooks.cbegin(); h != hooks.end(); ++h) {
+ // Try to convert hook name to command name. If non-empty
+ // string is returned it means that the hook point may have
+ // command hanlers associated with it. Otherwise, it means that
+ // existing hook points are not for command handlers but for
+ // regular callouts.
+ std::string command_name = ServerHooks::hookToCommandName(*h);
+ if (!command_name.empty()) {
+ // Final check: are command handlers registered for this
+ // hook point? If there are no command handlers associated,
+ // it means that the hook library was already unloaded.
+ if (HooksManager::commandHandlersPresent(command_name)) {
+ hooks_commands->add(Element::create(command_name));
+ }
+ }
+ }
+
+ // If there is at least one hook point with command handlers
+ // registered
+ // for it, combine the lists of commands.
+ if (!hooks_commands->empty()) {
+ response = combineCommandsLists(response, createAnswer(0, hooks_commands));
+ }
+ }
}
return (response);
diff --git a/src/lib/config/hooked_command_mgr.h b/src/lib/config/hooked_command_mgr.h
index 4113bdf461..bfa2ada933 100644
--- a/src/lib/config/hooked_command_mgr.h
+++ b/src/lib/config/hooked_command_mgr.h
@@ -18,7 +18,25 @@ namespace config {
///
/// This class extends @ref BaseCommandMgr with the logic to delegate the
/// commands to a hook library if the hook library is installed and provides
-/// callouts for the control API.
+/// command handlers for the control API.
+///
+/// The command handlers are registered by a hook library by calling
+/// @ref isc::hooks::LibraryHandle::registerCommandCallout. This call
+/// creates a hook point for this command (if one doesn't exist) and then
+/// registeres the specified handler(s). When the @ref HookedCommandMgr
+/// receives a command for processing it calls the
+/// @ref isc::hooks::HooksManager::commandHandlersPresent to check if there
+/// are handlers present for this command. If so, the @ref HookedCommandMgr
+/// calls @ref isc::hooks::HooksManager::callCommandHandlers to process
+/// the command in the hooks libraries. If command handlers are not installed
+/// for this command, the @ref HookedCommandMgr will try to process the
+/// command on its own.
+///
+/// The @ref isc::hooks::CalloutHandle::CalloutNextStep flag setting by the
+/// command handlers does NOT have any influence on the operation of the
+/// @ref HookedCommandMgr, i.e. it will always skip processing command on
+/// its own if the command handlers are present for the given command, even
+/// if the handlers return an error code.
class HookedCommandMgr : public BaseCommandMgr {
public:
@@ -39,32 +57,28 @@ protected:
/// @brief Handles the command within the hooks libraries.
///
/// This method checks if the hooks libraries are installed which implement
- /// callouts for the 'control_command_receive' hook point, and calls them
- /// if they exist. If the hooks library supports the given command it creates
- /// a response and returns it in the @c answer argument.
+ /// command handlers for the specified command to be processed. If the
+ /// command handlers are present, this method calls them to create a response
+ /// and then passes the response back within the @c answer argument.
///
/// Values of all arguments can be modified by the hook library.
///
- /// @param [out] cmd_name Command name.
- /// @param [out] params Command arguments.
- /// @param [out] original_cmd Original command received.
+ /// @param cmd_name Command name.
+ /// @param params Command arguments.
+ /// @param original_cmd Original command received.
/// @param [out] answer Command processing result returned by the hook.
///
/// @return Boolean value indicating if any callouts have been executed.
bool
- delegateCommandToHookLibrary(std::string& cmd_name,
- isc::data::ConstElementPtr& params,
- isc::data::ConstElementPtr& original_cmd,
+ delegateCommandToHookLibrary(const std::string& cmd_name,
+ const isc::data::ConstElementPtr& params,
+ const isc::data::ConstElementPtr& original_cmd,
isc::data::ElementPtr& answer);
/// @brief Handles the command having a given name and arguments.
///
/// This method calls @ref HookedCommandMgr::delegateCommandToHookLibrary to
/// try to process the command with the hook libraries, if they are installed.
- /// If the returned @c skip value indicates that the callout set the 'skip' flag
- /// the command is assumed to have been processed and the response is returned.
- /// If the 'skip' flag is not set, the @ref BaseCommandMgr::handleCommand is
- /// called.
///
/// @param cmd_name Command name.
/// @param params Command arguments.
diff --git a/src/lib/config/tests/command_mgr_unittests.cc b/src/lib/config/tests/command_mgr_unittests.cc
index 9bff3f9839..a927df5f86 100644
--- a/src/lib/config/tests/command_mgr_unittests.cc
+++ b/src/lib/config/tests/command_mgr_unittests.cc
@@ -33,9 +33,9 @@ public:
CommandMgr::instance().setIOService(io_service_);
- handler_name = "";
- handler_params = ElementPtr();
- handler_called = false;
+ handler_name_ = "";
+ handler_params_ = ElementPtr();
+ handler_called_ = false;
CommandMgr::instance().deregisterAll();
CommandMgr::instance().closeCommandSocket();
@@ -48,8 +48,6 @@ public:
CommandMgr::instance().deregisterAll();
CommandMgr::instance().closeCommandSocket();
resetCalloutIndicators();
- HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts(
- "control_command_receive");
}
/// @brief Returns socket path (using either hardcoded path or env variable)
@@ -67,18 +65,27 @@ public:
}
/// @brief Resets indicators related to callout invocation.
+ ///
+ /// It also removes any registered callouts.
static void resetCalloutIndicators() {
- callout_name = "";
- callout_argument_names.clear();
+ callout_name_ = "";
+ callout_argument_names_.clear();
+
+ // Iterate over existing hook points and for each of them remove
+ // callouts registered.
+ std::vector<std::string> hooks = ServerHooks::getServerHooksPtr()->getHookNames();
+ for (auto h = hooks.cbegin(); h != hooks.cend(); ++h) {
+ HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts(*h);
+ }
}
/// @brief A simple command handler that always returns an eror
static ConstElementPtr my_handler(const std::string& name,
const ConstElementPtr& params) {
- handler_name = name;
- handler_params = params;
- handler_called = true;
+ handler_name_ = name;
+ handler_params_ = params;
+ handler_called_ = true;
return (createAnswer(123, "test error message"));
}
@@ -92,76 +99,14 @@ public:
return (createAnswer(234, "text generated by hook handler"));
}
- /// @brief Test callback which stores callout name and passed arguments.
- ///
- /// This callout doesn't indicate that the command has been processed,
- /// allowing the Command Manager to process it.
- ///
- /// @param callout_handle Handle passed by the hooks framework.
- /// @return Always 0.
- static int
- control_command_receive_callout(CalloutHandle& callout_handle) {
- callout_name = "control_command_receive";
-
- ConstElementPtr response;
- callout_handle.setArgument("response", response);
-
- callout_argument_names = callout_handle.getArgumentNames();
- // Sort arguments alphabetically, so as we can access them on
- // expected positions and verify.
- std::sort(callout_argument_names.begin(), callout_argument_names.end());
- return (0);
- }
-
/// @brief Test callback which stores callout name and passed arguments and
/// which handles the command.
///
- /// This callout returns the skip status to indicate the the command has
- /// been handled.
- ///
/// @param callout_handle Handle passed by the hooks framework.
/// @return Always 0.
static int
control_command_receive_handle_callout(CalloutHandle& callout_handle) {
- callout_name = "control_command_receive";
-
- // Create a hooks specific command manager.
- BaseCommandMgr callout_command_mgr;
- callout_command_mgr.registerCommand("my-command", my_hook_handler);
-
- ConstElementPtr command;
- callout_handle.getArgument("command", command);
-
- ConstElementPtr arg;
- std::string command_name = parseCommand(arg, command);
-
- ConstElementPtr response = callout_command_mgr.processCommand(command);
- callout_handle.setArgument("response", response);
-
- // Set 'skip' status to indicate that the command has been handled.
- if (command_name != "list-commands") {
- callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
- }
-
- callout_argument_names = callout_handle.getArgumentNames();
- // Sort arguments alphabetically, so as we can access them on
- // expected positions and verify.
- std::sort(callout_argument_names.begin(), callout_argument_names.end());
- return (0);
- }
-
- /// @brief Test callback which modifies parameters of the command and
- /// does not return skip status.
- ///
- /// This callout is used to test the case when the callout modifies the
- /// received command and does not set next state SKIP to propagate the
- /// command with modified parameters to the local command handler.
- ///
- /// @param callout_handle Handle passed by the hooks framework.
- /// @return Always 0.
- static int
- control_command_receive_modify_callout(CalloutHandle& callout_handle) {
- callout_name = "control_command_receive";
+ callout_name_ = "control_command_receive_handle";
ConstElementPtr command;
callout_handle.getArgument("command", command);
@@ -169,16 +114,13 @@ public:
ConstElementPtr arg;
std::string command_name = parseCommand(arg, command);
- ElementPtr new_arg = Element::createList();
- new_arg->add(Element::create("hook-param"));
- command = createCommand(command_name, new_arg);
+ callout_handle.setArgument("response",
+ createAnswer(234, "text generated by hook handler"));
- callout_handle.setArgument("command", command);
-
- callout_argument_names = callout_handle.getArgumentNames();
+ callout_argument_names_ = callout_handle.getArgumentNames();
// Sort arguments alphabetically, so as we can access them on
// expected positions and verify.
- std::sort(callout_argument_names.begin(), callout_argument_names.end());
+ std::sort(callout_argument_names_.begin(), callout_argument_names_.end());
return (0);
}
@@ -186,35 +128,35 @@ public:
IOServicePtr io_service_;
/// @brief Name of the command (used in my_handler)
- static std::string handler_name;
+ static std::string handler_name_;
/// @brief Parameters passed to the handler (used in my_handler)
- static ConstElementPtr handler_params;
+ static ConstElementPtr handler_params_;
/// @brief Indicates whether my_handler was called
- static bool handler_called;
+ static bool handler_called_;
/// @brief Holds invoked callout name.
- static std::string callout_name;
+ static std::string callout_name_;
/// @brief Holds a list of arguments passed to the callout.
- static std::vector<std::string> callout_argument_names;
+ static std::vector<std::string> callout_argument_names_;
};
/// Name passed to the handler (used in my_handler)
-std::string CommandMgrTest::handler_name("");
+std::string CommandMgrTest::handler_name_("");
/// Parameters passed to the handler (used in my_handler)
-ConstElementPtr CommandMgrTest::handler_params;
+ConstElementPtr CommandMgrTest::handler_params_;
/// Indicates whether my_handler was called
-bool CommandMgrTest::handler_called(false);
+bool CommandMgrTest::handler_called_(false);
/// Holds invoked callout name.
-std::string CommandMgrTest::callout_name("");
+std::string CommandMgrTest::callout_name_("");
/// Holds a list of arguments passed to the callout.
-std::vector<std::string> CommandMgrTest::callout_argument_names;
+std::vector<std::string> CommandMgrTest::callout_argument_names_;
// Test checks whether the internal command 'list-commands'
// is working properly.
@@ -338,12 +280,6 @@ TEST_F(CommandMgrTest, deregisterAll) {
// Test checks whether a command handler can be installed and then
// runs through processCommand to check that it's indeed called.
TEST_F(CommandMgrTest, processCommand) {
-
- // Register callout so as we can check that it is called before
- // processing the command by the manager.
- HooksManager::preCalloutsLibraryHandle().registerCallout(
- "control_command_receive", control_command_receive_callout);
-
// Install my handler
EXPECT_NO_THROW(CommandMgr::instance().registerCommand("my-command",
my_handler));
@@ -366,26 +302,22 @@ TEST_F(CommandMgrTest, processCommand) {
EXPECT_EQ(123, status_code);
// Check that the parameters passed are correct.
- EXPECT_EQ(true, handler_called);
- EXPECT_EQ("my-command", handler_name);
- ASSERT_TRUE(handler_params);
- EXPECT_EQ("[ \"just\", \"some\", \"data\" ]", handler_params->str());
-
- EXPECT_EQ("control_command_receive", callout_name);
-
- // Check that the appropriate arguments have been set. Include the
- // 'response' which should have been set by the callout.
- ASSERT_EQ(2, callout_argument_names.size());
- EXPECT_EQ("command", callout_argument_names[0]);
- EXPECT_EQ("response", callout_argument_names[1]);
+ EXPECT_EQ(true, handler_called_);
+ EXPECT_EQ("my-command", handler_name_);
+ ASSERT_TRUE(handler_params_);
+ EXPECT_EQ("[ \"just\", \"some\", \"data\" ]", handler_params_->str());
+
+ // Command handlers not installed so expecting that callouts weren't
+ // called.
+ EXPECT_TRUE(callout_name_.empty());
}
// Verify that processing a command can be delegated to a hook library.
TEST_F(CommandMgrTest, delegateProcessCommand) {
// Register callout so as we can check that it is called before
// processing the command by the manager.
- HooksManager::preCalloutsLibraryHandle().registerCallout(
- "control_command_receive", control_command_receive_handle_callout);
+ HooksManager::preCalloutsLibraryHandle().registerCommandCallout(
+ "my-command", control_command_receive_handle_callout);
// Install local handler
EXPECT_NO_THROW(CommandMgr::instance().registerCommand("my-command",
@@ -403,7 +335,7 @@ TEST_F(CommandMgrTest, delegateProcessCommand) {
// Local handler shouldn't be called because the command is handled by the
// hook library.
- ASSERT_FALSE(handler_called);
+ ASSERT_FALSE(handler_called_);
// Returned status should be unique for the hook library.
ConstElementPtr answer_arg;
@@ -411,13 +343,13 @@ TEST_F(CommandMgrTest, delegateProcessCommand) {
ASSERT_NO_THROW(answer_arg = parseAnswer(status_code, answer));
EXPECT_EQ(234, status_code);
- EXPECT_EQ("control_command_receive", callout_name);
+ EXPECT_EQ("control_command_receive_handle", callout_name_);
// Check that the appropriate arguments have been set. Include the
// 'response' which should have been set by the callout.
- ASSERT_EQ(2, callout_argument_names.size());
- EXPECT_EQ("command", callout_argument_names[0]);
- EXPECT_EQ("response", callout_argument_names[1]);
+ ASSERT_EQ(2, callout_argument_names_.size());
+ EXPECT_EQ("command", callout_argument_names_[0]);
+ EXPECT_EQ("response", callout_argument_names_[1]);
}
// Verify that 'list-command' command returns combined list of supported
@@ -425,8 +357,8 @@ TEST_F(CommandMgrTest, delegateProcessCommand) {
TEST_F(CommandMgrTest, delegateListCommands) {
// Register callout so as we can check that it is called before
// processing the command by the manager.
- HooksManager::preCalloutsLibraryHandle().registerCallout(
- "control_command_receive", control_command_receive_handle_callout);
+ HooksManager::preCalloutsLibraryHandle().registerCommandCallout(
+ "my-command", control_command_receive_handle_callout);
// Create my-command-bis which is unique for the local Command Manager,
// i.e. not supported by the hook library. This command should also
@@ -464,56 +396,6 @@ TEST_F(CommandMgrTest, delegateListCommands) {
EXPECT_EQ("my-command-bis", command_names_list[2]);
}
-// This test verifies the scenario in which the hook library influences the
-// command processing by the Kea server. In this test, the callout modifies
-// the arguments of the command and passes the command on to the Command
-// Manager for processing.
-TEST_F(CommandMgrTest, modifyCommandArgsInHook) {
- // Register callout so as we can check that it is called before
- // processing the command by the manager.
- HooksManager::preCalloutsLibraryHandle().registerCallout(
- "control_command_receive", control_command_receive_modify_callout);
-
- // Install local handler
- EXPECT_NO_THROW(CommandMgr::instance().registerCommand("my-command",
- my_handler));
-
- // Now tell CommandMgr to process a command 'my-command' with the
- // specified parameter.
- ElementPtr my_params = Element::fromJSON("[ \"just\", \"some\", \"data\" ]");
- ConstElementPtr command = createCommand("my-command", my_params);
- ConstElementPtr answer;
- ASSERT_NO_THROW(answer = CommandMgr::instance().processCommand(command));
-
- // There should be an answer.
- ASSERT_TRUE(answer);
-
- // Returned status should be unique for the my_handler.
- ConstElementPtr answer_arg;
- int status_code;
- ASSERT_NO_THROW(answer_arg = parseAnswer(status_code, answer));
- EXPECT_EQ(123, status_code);
-
- // Local handler should have been called after the callout.
- ASSERT_TRUE(handler_called);
- EXPECT_EQ("my-command", handler_name);
- ASSERT_TRUE(handler_params);
- // Check that the local handler received the command with arguments
- // set by the callout.
- EXPECT_EQ("[ \"hook-param\" ]", handler_params->str());
-
-
- // Check that the callout has been called with appropriate parameters.
- EXPECT_EQ("control_command_receive", callout_name);
-
- // Check that the appropriate arguments have been set. Include the
- // 'response' which should have been set by the callout.
- ASSERT_EQ(2, callout_argument_names.size());
- EXPECT_EQ("command", callout_argument_names[0]);
- EXPECT_EQ("response", callout_argument_names[1]);
-
-}
-
// This test verifies that a Unix socket can be opened properly and that input
// parameters (socket-type and socket-name) are verified.
TEST_F(CommandMgrTest, unixCreate) {
diff --git a/src/lib/hooks/callout_manager.h b/src/lib/hooks/callout_manager.h
index 06e9dac39a..a4a7f8a641 100644
--- a/src/lib/hooks/callout_manager.h
+++ b/src/lib/hooks/callout_manager.h
@@ -119,11 +119,11 @@ public:
///
/// The @ref CalloutManager::registerCommandHook has been added to allow for
/// dynamically creating hook points for which command handlers are registered.
-/// This method is called from the @ref LibraryHandle::registerCommandHandler
+/// This method is called from the @ref LibraryHandle::registerCommandCallout
/// as a result of registering the command handlers by the hook library in
/// its @c load() function. If the hook point for the given command already
/// exists, this function doesn't do anything. The
-/// @ref LibraryHandle::registerCommandHandler can install callouts on this
+/// @ref LibraryHandle::registerCommandCallout can install callouts on this
/// hook point.
///
/// Note that the callout functions do not access the CalloutManager: instead,
diff --git a/src/lib/hooks/library_handle.cc b/src/lib/hooks/library_handle.cc
index 1df6de5d61..5707dbae52 100644
--- a/src/lib/hooks/library_handle.cc
+++ b/src/lib/hooks/library_handle.cc
@@ -36,7 +36,7 @@ LibraryHandle::registerCallout(const std::string& name, CalloutPtr callout) {
}
void
-LibraryHandle::registerCommandHandler(const std::string& command_name,
+LibraryHandle::registerCommandCallout(const std::string& command_name,
CalloutPtr callout) {
// Register hook point for this command, if one doesn't exist.
callout_manager_->registerCommandHook(command_name);
diff --git a/src/lib/hooks/library_handle.h b/src/lib/hooks/library_handle.h
index f04c95283e..5dfad2a909 100644
--- a/src/lib/hooks/library_handle.h
+++ b/src/lib/hooks/library_handle.h
@@ -48,7 +48,7 @@ extern "C" {
/// handler similarly to this:
/// @code
/// int load(LibraryHandle& libhandle) {
-/// libhandle.registerCommandHandler("foo-bar", foo_bar_handler);
+/// libhandle.registerCommandCallout("foo-bar", foo_bar_handler);
/// return (0);
/// }
/// @endcode
@@ -104,7 +104,7 @@ public:
///
/// @param command_name Command name for which handler should be installed.
/// @param callout Pointer to the command handler implemented as a callout.
- void registerCommandHandler(const std::string& command_name, CalloutPtr callout);
+ void registerCommandCallout(const std::string& command_name, CalloutPtr callout);
/// @brief De-Register a callout on a hook
///
diff --git a/src/lib/hooks/server_hooks.cc b/src/lib/hooks/server_hooks.cc
index e8f12ead24..d7cfcdf901 100644
--- a/src/lib/hooks/server_hooks.cc
+++ b/src/lib/hooks/server_hooks.cc
@@ -182,7 +182,17 @@ ServerHooks::commandToHookName(const std::string& command_name) {
return (hook_name);
}
+std::string
+ServerHooks::hookToCommandName(const std::string& hook_name) {
+ if (!hook_name.empty() && hook_name.front() == '$') {
+ std::string command_name = hook_name.substr(1);
+ std::replace(command_name.begin(), command_name.end(), '_', '-');
+ return (command_name);
+ }
+ return ("");
+}
+
-} // namespace util
+} // namespace hooks
} // namespace isc
diff --git a/src/lib/hooks/server_hooks.h b/src/lib/hooks/server_hooks.h
index 43f7d7df14..bf100cdb15 100644
--- a/src/lib/hooks/server_hooks.h
+++ b/src/lib/hooks/server_hooks.h
@@ -167,8 +167,21 @@ public:
///
/// @param command_name Command name for which the hook point name is
/// to be generated.
+ ///
+ /// @return Hook point name, or an empty string if the command name
+ /// can't be converted to a hook name (e.g. when it lacks dollar sign).
static std::string commandToHookName(const std::string& command_name);
+ /// @brief Returns command name for a specified hook name.
+ ///
+ /// This function removes leading dollar sign and replaces underscores
+ /// with hyphens.
+ ///
+ /// @param hook_name Hook name for which command name should be returned.
+ ///
+ /// @return Command name.
+ static std::string hookToCommandName(const std::string& hook_name);
+
private:
/// @brief Constructor
///
diff --git a/src/lib/hooks/tests/callout_manager_unittest.cc b/src/lib/hooks/tests/callout_manager_unittest.cc
index 1b96585b42..03da266ab2 100644
--- a/src/lib/hooks/tests/callout_manager_unittest.cc
+++ b/src/lib/hooks/tests/callout_manager_unittest.cc
@@ -880,14 +880,14 @@ TEST_F(CalloutManagerTest, LibraryHandleRegisterCommandHandler) {
// 'command-two' should also be called.
getCalloutManager()->setLibraryIndex(0);
- getCalloutManager()->getLibraryHandle().registerCommandHandler("command-one",
+ getCalloutManager()->getLibraryHandle().registerCommandCallout("command-one",
callout_one);
- getCalloutManager()->getLibraryHandle().registerCommandHandler("command-one",
+ getCalloutManager()->getLibraryHandle().registerCommandCallout("command-one",
callout_four);
getCalloutManager()->setLibraryIndex(1);
- getCalloutManager()->getLibraryHandle().registerCommandHandler("command-one",
+ getCalloutManager()->getLibraryHandle().registerCommandCallout("command-one",
callout_two);
- getCalloutManager()->getLibraryHandle().registerCommandHandler("command-two",
+ getCalloutManager()->getLibraryHandle().registerCommandCallout("command-two",
callout_three);
// Command handlers are installed for commands: 'command-one' and 'command-two'.
diff --git a/src/lib/hooks/tests/full_callout_library.cc b/src/lib/hooks/tests/full_callout_library.cc
index 50a34296c1..1846592e15 100644
--- a/src/lib/hooks/tests/full_callout_library.cc
+++ b/src/lib/hooks/tests/full_callout_library.cc
@@ -151,8 +151,8 @@ load(LibraryHandle& handle) {
handle.registerCallout("hookpt_three", hook_nonstandard_three);
// Register command_handler_one as control command handler.
- handle.registerCommandHandler("command-one", command_handler_one);
- handle.registerCommandHandler("command-two", command_handler_two);
+ handle.registerCommandCallout("command-one", command_handler_one);
+ handle.registerCommandCallout("command-two", command_handler_two);
return (0);
}
diff --git a/src/lib/hooks/tests/load_callout_library.cc b/src/lib/hooks/tests/load_callout_library.cc
index 40606f7466..613ec2c79f 100644
--- a/src/lib/hooks/tests/load_callout_library.cc
+++ b/src/lib/hooks/tests/load_callout_library.cc
@@ -142,8 +142,8 @@ int load(LibraryHandle& handle) {
handle.registerCallout("hookpt_three", hook_nonstandard_three);
// Register command_handler_one as control command handler.
- handle.registerCommandHandler("command-one", command_handler_one);
- handle.registerCommandHandler("command-two", command_handler_two);
+ handle.registerCommandCallout("command-one", command_handler_one);
+ handle.registerCommandCallout("command-two", command_handler_two);
return (0);
}
diff --git a/src/lib/hooks/tests/server_hooks_unittest.cc b/src/lib/hooks/tests/server_hooks_unittest.cc
index 78d8e13788..6c012fa41f 100644
--- a/src/lib/hooks/tests/server_hooks_unittest.cc
+++ b/src/lib/hooks/tests/server_hooks_unittest.cc
@@ -198,7 +198,8 @@ TEST(ServerHooksTest, HookCount) {
EXPECT_EQ(6, hooks.getCount());
}
-// Check that the hook name is correctly generated for a control command name.
+// Check that the hook name is correctly generated for a control command name
+// and vice versa.
TEST(ServerHooksTest, CommandToHookName) {
EXPECT_EQ("$x_y_z", ServerHooks::commandToHookName("x-y-z"));
@@ -206,4 +207,14 @@ TEST(ServerHooksTest, CommandToHookName) {
EXPECT_EQ("$", ServerHooks::commandToHookName(""));
}
+TEST(ServerHooksTest, HookToCommandName) {
+ // Underscores replaced by hyphens.
+ EXPECT_EQ("x-y-z", ServerHooks::hookToCommandName("$x_y_z"));
+ EXPECT_EQ("foo-bar-foo", ServerHooks::hookToCommandName("$foo_bar-foo"));
+ // Single dollar is converted to empty string.
+ EXPECT_TRUE(ServerHooks::hookToCommandName("$").empty());
+ // If no dollar, it is not a hook name. Return empty string.
+ EXPECT_TRUE(ServerHooks::hookToCommandName("abc").empty());
+}
+
} // Anonymous namespace