]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[5100] Extracted command management into BaseCommandMgr class.
authorMarcin Siodelski <marcin@isc.org>
Tue, 3 Jan 2017 09:58:32 +0000 (10:58 +0100)
committerMarcin Siodelski <marcin@isc.org>
Tue, 3 Jan 2017 11:08:38 +0000 (12:08 +0100)
src/lib/config/Makefile.am
src/lib/config/base_command_mgr.cc [new file with mode: 0644]
src/lib/config/base_command_mgr.h [new file with mode: 0644]
src/lib/config/command_mgr.cc
src/lib/config/command_mgr.h

index 6025276d599807f5f21e89ff51079829c84594ab..d01a6b8f644467f0a66e97ccfe9ffd878de01907 100644 (file)
@@ -15,6 +15,7 @@ BUILT_SOURCES = config_messages.h config_messages.cc
 lib_LTLIBRARIES = libkea-cfgclient.la
 libkea_cfgclient_la_SOURCES = config_data.h config_data.cc
 libkea_cfgclient_la_SOURCES += module_spec.h module_spec.cc
+libkea_cfgclient_la_SOURCES += base_command_mgr.cc base_command_mgr.h
 libkea_cfgclient_la_SOURCES += command_mgr.cc command_mgr.h
 libkea_cfgclient_la_SOURCES += command_socket.cc command_socket.h
 libkea_cfgclient_la_SOURCES += command_socket_factory.cc command_socket_factory.h
diff --git a/src/lib/config/base_command_mgr.cc b/src/lib/config/base_command_mgr.cc
new file mode 100644 (file)
index 0000000..7a1a8f6
--- /dev/null
@@ -0,0 +1,111 @@
+// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <cc/command_interpreter.h>
+#include <config/base_command_mgr.h>
+#include <config/config_log.h>
+#include <boost/bind.hpp>
+
+using namespace isc::data;
+
+namespace isc {
+namespace config {
+
+BaseCommandMgr::BaseCommandMgr() {
+    registerCommand("list-commands", boost::bind(&BaseCommandMgr::listCommandsHandler,
+                                                 this, _1, _2));
+}
+
+void
+BaseCommandMgr::registerCommand(const std::string& cmd, CommandHandler handler) {
+    if (!handler) {
+        isc_throw(InvalidCommandHandler, "Specified command handler is NULL");
+    }
+
+    HandlerContainer::const_iterator it = handlers_.find(cmd);
+    if (it != handlers_.end()) {
+        isc_throw(InvalidCommandName, "Handler for command '" << cmd
+                  << "' is already installed.");
+    }
+
+    handlers_.insert(make_pair(cmd, handler));
+
+    LOG_DEBUG(command_logger, DBG_COMMAND, COMMAND_REGISTERED).arg(cmd);
+}
+
+void
+BaseCommandMgr::deregisterCommand(const std::string& cmd) {
+    if (cmd == "list-commands") {
+        isc_throw(InvalidCommandName,
+                  "Can't uninstall internal command 'list-commands'");
+    }
+
+    HandlerContainer::iterator it = handlers_.find(cmd);
+    if (it == handlers_.end()) {
+        isc_throw(InvalidCommandName, "Handler for command '" << cmd
+                  << "' not found.");
+    }
+    handlers_.erase(it);
+
+    LOG_DEBUG(command_logger, DBG_COMMAND, COMMAND_DEREGISTERED).arg(cmd);
+}
+
+void
+BaseCommandMgr::deregisterAll() {
+
+    // No need to log anything here. deregisterAll is not used in production
+    // code, just in tests.
+    handlers_.clear();
+    registerCommand("list-commands",
+        boost::bind(&BaseCommandMgr::listCommandsHandler, this, _1, _2));
+}
+
+isc::data::ConstElementPtr
+BaseCommandMgr::processCommand(const isc::data::ConstElementPtr& cmd) {
+    if (!cmd) {
+        return (createAnswer(CONTROL_RESULT_ERROR,
+                             "Command processing failed: NULL command parameter"));
+    }
+
+    try {
+        ConstElementPtr arg;
+        std::string name = parseCommand(arg, cmd);
+
+        LOG_INFO(command_logger, COMMAND_RECEIVED).arg(name);
+
+        HandlerContainer::const_iterator it = handlers_.find(name);
+        if (it == handlers_.end()) {
+            // Ok, there's no such command.
+            return (createAnswer(CONTROL_RESULT_ERROR,
+                                 "'" + name + "' command not supported."));
+        }
+
+        // Call the actual handler and return whatever it returned
+        return (it->second(name, arg));
+
+    } catch (const Exception& e) {
+        LOG_WARN(command_logger, COMMAND_PROCESS_ERROR2).arg(e.what());
+        return (createAnswer(CONTROL_RESULT_ERROR,
+                             std::string("Error during command processing:")
+                             + e.what()));
+    }
+}
+
+isc::data::ConstElementPtr
+BaseCommandMgr::listCommandsHandler(const std::string& name,
+                                    const isc::data::ConstElementPtr& params) {
+    using namespace isc::data;
+    ElementPtr commands = Element::createList();
+    for (HandlerContainer::const_iterator it = handlers_.begin();
+         it != handlers_.end(); ++it) {
+        commands->add(Element::create(it->first));
+    }
+    return (createAnswer(CONTROL_RESULT_SUCCESS, commands));
+}
+
+
+} // namespace isc::config
+} // namespace isc
diff --git a/src/lib/config/base_command_mgr.h b/src/lib/config/base_command_mgr.h
new file mode 100644 (file)
index 0000000..389027f
--- /dev/null
@@ -0,0 +1,147 @@
+// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef BASE_COMMAND_MGR_H
+#define BASE_COMMAND_MGR_H
+
+#include <cc/data.h>
+#include <exceptions/exceptions.h>
+#include <boost/function.hpp>
+#include <map>
+#include <string>
+
+namespace isc {
+namespace config {
+
+/// @brief Exception indicating that the handler specified is not valid
+class InvalidCommandHandler : public Exception {
+public:
+    InvalidCommandHandler(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) { };
+};
+
+/// @brief Exception indicating that the command name is not valid
+class InvalidCommandName : public Exception {
+public:
+    InvalidCommandName(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) { };
+};
+
+/// @brief Commands Manager, responsible for processing external commands.
+///
+/// Commands Manager is a generic interface for handling external commands.
+/// Commands are received over control sockets. Derivations of this class
+/// provide implementations of the control socket layers, e.g. unix domain
+/// sockets, TCP sockets etc. This base class merely provides methods to manage
+/// command handling functions, i.e. register commands, deregister commands.
+/// It also includes a @ref BaseCommandMgr::processCommand method which
+/// uses the command as an input and invokes appropriate handlers.
+///
+/// The commands and responses are formatted using JSON.
+/// See http://kea.isc.org/wiki/StatsDesign for details.
+///
+/// Below is an example of the command using JSON format:
+/// @code
+/// {
+///     "command": "statistic-get",
+///     "arguments": {
+///         "name": "received-packets"
+///     }
+/// }
+/// @endcode
+///
+/// And the response is:
+///
+/// @code
+/// {
+///     "result": 0,
+///     "observations": {
+///         "received-packets": [ [ 1234, "2015-04-15 12:34:45.123" ] ]
+///     }
+/// }
+/// @endcode
+///
+/// BaseCommandsMgr does not implement the commands (except one,
+/// "list-commands") itself, but rather provides an interface
+/// (see @ref registerCommand, @ref deregisterCommand, @ref processCommand)
+/// for other components to use it.
+class BaseCommandMgr {
+public:
+
+    /// @brief Defines command handler type
+    ///
+    /// Command handlers are expected to use this format.
+    ///
+    /// @param name name of the commands
+    /// @param params parameters specific to the command
+    /// @return response (created with createAnswer())
+    typedef boost::function<isc::data::ConstElementPtr (const std::string& name,
+        const isc::data::ConstElementPtr& params)> CommandHandler;
+
+    /// @brief Constructor.
+    ///
+    /// Registers "list-commands" command.
+    BaseCommandMgr();
+
+    /// @brief Destructor.
+    virtual ~BaseCommandMgr() { };
+
+    /// @brief Triggers command processing.
+    ///
+    /// This method processes specified command. The command is specified using
+    /// a single Element. See @ref BaseCommandMgr for description of its syntax.
+    ///
+    /// @param cmd Pointer to the data element representing command in JSON
+    /// format.
+    virtual isc::data::ConstElementPtr
+    processCommand(const isc::data::ConstElementPtr& cmd);
+
+    /// @brief Registers specified command handler for a given command
+    ///
+    /// @param cmd Name of the command to be handled.
+    /// @param handler Pointer to the method that will handle the command.
+    void registerCommand(const std::string& cmd, CommandHandler handler);
+
+    /// @brief Deregisters specified command handler.
+    ///
+    /// @param cmd Name of the command that's no longer handled.
+    void deregisterCommand(const std::string& cmd);
+
+    /// @brief Auxiliary method that removes all installed commands.
+    ///
+    /// The only unwipeable method is list-commands, which is internally
+    /// handled at all times.
+    void deregisterAll();
+
+protected:
+
+    /// @brief Type of the container for command handlers.
+    typedef std::map<std::string, CommandHandler> HandlerContainer;
+
+    /// @brief Container for command handlers.
+    HandlerContainer handlers_;
+
+private:
+
+    /// @brief 'list-commands' command handler.
+    ///
+    /// This method implements command 'list-commands'. It returns a list of all
+    /// currently supported commands.
+    ///
+    /// @param name Name of the command (should always be 'list-commands').
+    /// @param params Additional parameters (ignored).
+    ///
+    /// @return Pointer to the structure that includes all currently supported
+    /// commands.
+    isc::data::ConstElementPtr
+    listCommandsHandler(const std::string& name,
+                        const isc::data::ConstElementPtr& params);
+};
+
+} // end of namespace isc::config
+} // end of namespace isc
+
+#endif
index ae33188014de8ec205db30e04518642d5e067c09..1239df650e6ccc3412ee7e6f1515212dc18ea37b 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2017 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -17,9 +17,8 @@ using namespace isc::data;
 namespace isc {
 namespace config {
 
-CommandMgr::CommandMgr() {
-    registerCommand("list-commands",
-        boost::bind(&CommandMgr::listCommandsHandler, this, _1, _2));
+CommandMgr::CommandMgr()
+    : BaseCommandMgr() {
 }
 
 CommandSocketPtr
@@ -76,48 +75,6 @@ CommandMgr::instance() {
     return (cmd_mgr);
 }
 
-void CommandMgr::registerCommand(const std::string& cmd, CommandHandler handler) {
-
-    if (!handler) {
-        isc_throw(InvalidCommandHandler, "Specified command handler is NULL");
-    }
-
-    HandlerContainer::const_iterator it = handlers_.find(cmd);
-    if (it != handlers_.end()) {
-        isc_throw(InvalidCommandName, "Handler for command '" << cmd
-                  << "' is already installed.");
-    }
-
-    handlers_.insert(make_pair(cmd, handler));
-
-    LOG_DEBUG(command_logger, DBG_COMMAND, COMMAND_REGISTERED).arg(cmd);
-}
-
-void CommandMgr::deregisterCommand(const std::string& cmd) {
-    if (cmd == "list-commands") {
-        isc_throw(InvalidCommandName,
-                  "Can't uninstall internal command 'list-commands'");
-    }
-
-    HandlerContainer::iterator it = handlers_.find(cmd);
-    if (it == handlers_.end()) {
-        isc_throw(InvalidCommandName, "Handler for command '" << cmd
-                  << "' not found.");
-    }
-    handlers_.erase(it);
-
-    LOG_DEBUG(command_logger, DBG_COMMAND, COMMAND_DEREGISTERED).arg(cmd);
-}
-
-void CommandMgr::deregisterAll() {
-
-    // No need to log anything here. deregisterAll is not used in production
-    // code, just in tests.
-    handlers_.clear();
-    registerCommand("list-commands",
-        boost::bind(&CommandMgr::listCommandsHandler, this, _1, _2));
-}
-
 void
 CommandMgr::commandReader(int sockfd) {
 
@@ -191,48 +148,5 @@ CommandMgr::commandReader(int sockfd) {
     }
 }
 
-isc::data::ConstElementPtr
-CommandMgr::processCommand(const isc::data::ConstElementPtr& cmd) {
-    if (!cmd) {
-        return (createAnswer(CONTROL_RESULT_ERROR,
-                             "Command processing failed: NULL command parameter"));
-    }
-
-    try {
-        ConstElementPtr arg;
-        std::string name = parseCommand(arg, cmd);
-
-        LOG_INFO(command_logger, COMMAND_RECEIVED).arg(name);
-
-        HandlerContainer::const_iterator it = handlers_.find(name);
-        if (it == handlers_.end()) {
-            // Ok, there's no such command.
-            return (createAnswer(CONTROL_RESULT_ERROR,
-                                 "'" + name + "' command not supported."));
-        }
-
-        // Call the actual handler and return whatever it returned
-        return (it->second(name, arg));
-
-    } catch (const Exception& e) {
-        LOG_WARN(command_logger, COMMAND_PROCESS_ERROR2).arg(e.what());
-        return (createAnswer(CONTROL_RESULT_ERROR,
-                             std::string("Error during command processing:")
-                             + e.what()));
-    }
-}
-
-isc::data::ConstElementPtr
-CommandMgr::listCommandsHandler(const std::string& name,
-                                const isc::data::ConstElementPtr& params) {
-    using namespace isc::data;
-    ElementPtr commands = Element::createList();
-    for (HandlerContainer::const_iterator it = handlers_.begin();
-         it != handlers_.end(); ++it) {
-        commands->add(Element::create(it->first));
-    }
-    return (createAnswer(CONTROL_RESULT_SUCCESS, commands));
-}
-
 }; // end of isc::config
 }; // end of isc
index 976b2223b1e638f8b7d698b678c6f6477bb69ac3..31a41ad814b03ba7f811c49df4570d884ae9e84d 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2017 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -8,72 +8,21 @@
 #define COMMAND_MGR_H
 
 #include <cc/data.h>
+#include <config/base_command_mgr.h>
 #include <config/command_socket.h>
 #include <boost/noncopyable.hpp>
-#include <boost/function.hpp>
-#include <string>
 #include <list>
-#include <map>
 
 namespace isc {
 namespace config {
 
-/// @brief CommandMgr exception indicating that the handler specified is not valid
-class InvalidCommandHandler : public Exception {
-public:
-    InvalidCommandHandler(const char* file, size_t line, const char* what) :
-        isc::Exception(file, line, what) { };
-};
-
-/// @brief CommandMgr exception indicating that the command name is not valid
-class InvalidCommandName : public Exception {
-public:
-    InvalidCommandName(const char* file, size_t line, const char* what) :
-        isc::Exception(file, line, what) { };
-};
-
-/// @brief Commands Manager, responsible for processing external commands
+/// @brief Commands Manager implementation for the Kea servers.
 ///
-/// Commands Manager is a generic interface for handling external commands.
-/// Commands can be received over control sockets. Currently unix socket is
-/// supported, but additional type (udp, tcp, https etc.) may be added later.
-/// The commands and responses are sent in JSON format.
-/// See http://kea.isc.org/wiki/StatsDesign for details.
-///
-/// In general, the command has the following format:
-/// {
-///     "command": "statistic-get",
-///     "arguments": {
-///         "name": "received-packets"
-///     }
-/// }
-///
-/// And the response is:
-///
-/// {
-///     "result": 0,
-///     "observations": {
-///         "received-packets": [ [ 1234, "2015-04-15 12:34:45.123" ] ]
-///     }
-/// }
-///
-/// CommandsMgr does not implement the commands (except one, "list-commands")
-/// itself, but rather provides an interface (see @ref registerCommand,
-/// @ref deregisterCommand, @ref processCommand) for other components to use
-/// it. The @ref CommandHandler type is specified in a way to easily use
-/// existing command handlers in DHCPv4 and DHCPv6 components.
-class CommandMgr : public boost::noncopyable {
+/// This class extends @ref BaseCommandMgr with the ability to receive and
+/// respond to commands over unix domain sockets.
+class CommandMgr : public BaseCommandMgr, public boost::noncopyable {
 public:
 
-    /// @brief Defines command handler type
-    ///
-    /// Command handlers are expected to use this format.
-    /// @param name name of the commands
-    /// @param params parameters specific to the command
-    /// @return response (created with createAnswer())
-    typedef boost::function<isc::data::ConstElementPtr (const std::string& name,
-        const isc::data::ConstElementPtr& params)> CommandHandler;
-
     /// @brief CommandMgr is a singleton class. This method returns reference
     /// to its sole instance.
     ///
@@ -98,26 +47,6 @@ public:
     /// @brief Shuts down any open control sockets
     void closeCommandSocket();
 
-    /// @brief Registers specified command handler for a given command
-    ///
-    /// @param cmd name of the command to be handled
-    /// @param handler pointer to the method that will handle the command
-    void registerCommand(const std::string& cmd, CommandHandler handler);
-
-    /// @brief Deregisters specified command handler
-    ///
-    /// @param cmd name of the command that's no longer handled
-    void deregisterCommand(const std::string& cmd);
-
-    /// @brief Triggers command processing
-    ///
-    /// This method processes specified command. The command is specified using
-    /// a single Element. See @ref CommandMgr for description of its syntax.
-    /// Typically, this method is called internally, when there's a new data
-    /// received over control socket. However, in some cases (e.g. signal received)
-    /// it may be called by external code explicitly. Hence this method is public.
-    isc::data::ConstElementPtr processCommand(const isc::data::ConstElementPtr& cmd);
-
     /// @brief Reads data from a socket, parses as JSON command and processes it
     ///
     /// This method is used to handle traffic on connected socket. This callback
@@ -130,12 +59,6 @@ public:
     /// @param sockfd socket descriptor of a connected socket
     static void commandReader(int sockfd);
 
-    /// @brief Auxiliary method that removes all installed commands.
-    ///
-    /// The only unwipeable method is list-commands, which is internally
-    /// handled at all times.
-    void deregisterAll();
-
     /// @brief Adds an information about opened connection socket
     ///
     /// @param conn Connection socket to be stored
@@ -161,22 +84,6 @@ private:
     /// Registers internal 'list-commands' command.
     CommandMgr();
 
-    /// @brief 'list-commands' command handler
-    ///
-    /// This method implements command 'list-commands'. It returns a list of all
-    /// currently supported commands.
-    /// @param name name of the command (should always be 'list-commands')
-    /// @param params additional parameters (ignored)
-    /// @return structure that includes all currently supported commands
-    isc::data::ConstElementPtr
-    listCommandsHandler(const std::string& name,
-                        const isc::data::ConstElementPtr& params);
-
-    typedef std::map<std::string, CommandHandler> HandlerContainer;
-
-    /// @brief Container for command handlers
-    HandlerContainer handlers_;
-
     /// @brief Control socket structure
     ///
     /// This is the socket that accepts incoming connections. There can be at