summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/guide/ctrl-channel.xml32
-rw-r--r--doc/guide/dhcp4-srv.xml6
-rw-r--r--doc/guide/dhcp6-srv.xml6
-rw-r--r--src/bin/agent/ca_controller.cc20
-rw-r--r--src/bin/agent/ca_controller.h19
-rw-r--r--src/bin/agent/ca_process.cc27
-rw-r--r--src/bin/agent/ca_process.h20
-rw-r--r--src/bin/d2/d2_process.cc13
-rw-r--r--src/bin/d2/d2_process.h14
-rw-r--r--src/bin/d2/tests/d2_controller_unittests.cc29
-rw-r--r--src/bin/d2/tests/d2_process_unittests.cc14
-rw-r--r--src/bin/dhcp4/ctrl_dhcp4_srv.cc34
-rw-r--r--src/bin/dhcp4/ctrl_dhcp4_srv.h25
-rw-r--r--src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc29
-rw-r--r--src/bin/dhcp6/ctrl_dhcp6_srv.cc35
-rw-r--r--src/bin/dhcp6/ctrl_dhcp6_srv.h25
-rw-r--r--src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc26
-rw-r--r--src/bin/shell/tests/shell_process_tests.sh.in2
-rw-r--r--src/lib/cc/command_interpreter.cc54
-rw-r--r--src/lib/cc/command_interpreter.h17
-rw-r--r--src/lib/config/base_command_mgr.cc52
-rw-r--r--src/lib/config/base_command_mgr.h21
-rw-r--r--src/lib/log/logger_impl.cc2
-rw-r--r--src/lib/process/d_controller.cc106
-rw-r--r--src/lib/process/d_controller.h90
-rw-r--r--src/lib/process/d_process.h26
-rw-r--r--src/lib/process/tests/d_controller_unittests.cc64
-rw-r--r--src/lib/process/testutils/d_test_stubs.h9
28 files changed, 431 insertions, 386 deletions
diff --git a/doc/guide/ctrl-channel.xml b/doc/guide/ctrl-channel.xml
index 95a61f2794..abfefcdd4d 100644
--- a/doc/guide/ctrl-channel.xml
+++ b/doc/guide/ctrl-channel.xml
@@ -113,6 +113,22 @@ will be sent to Kea and the responses received from Kea printed to standard outp
<section id="commands-common">
<title>Commands Supported by Both the DHCPv4 and DHCPv6 Servers</title>
+ <section id="command-build-report">
+ <title>build-report</title>
+ <para>
+ The <emphasis>build-report</emphasis> command returns
+ on the control channel what the command line
+ <command>-W</command> argument displays, i.e. the embedded
+ content of the <filename>config.report</filename> file.
+ This command does not take any parameters.
+ </para>
+<screen>
+{
+ "command": "build-report"
+}
+</screen>
+ </section> <!-- end of command-build-report -->
+
<section id="command-config-get">
<title>config-get</title>
@@ -315,7 +331,21 @@ will be sent to Kea and the responses received from Kea printed to standard outp
</para>
</section> <!-- end of command-shutdown -->
-
+ <section id="command-version-get">
+ <title>version-get</title>
+ <para>
+ The <emphasis>version-get</emphasis> command returns on the control
+ channel what the command line <command>-v</command> argument
+ displays with in arguments the extended version, i.e., what
+ the command line <command>-V</command> argument displays. This command
+ does not take any parameters.
+ </para>
+<screen>
+{
+ "command": "version-get"
+}
+</screen>
+ </section> <!-- end of command-version-get -->
</section> <!-- end of commands supported by both servers -->
diff --git a/doc/guide/dhcp4-srv.xml b/doc/guide/dhcp4-srv.xml
index 16456ce16d..71a032a01e 100644
--- a/doc/guide/dhcp4-srv.xml
+++ b/doc/guide/dhcp4-srv.xml
@@ -195,7 +195,7 @@ opening curly bracket (or brace). Each configuration consists of
one or more objects. In this specific example, we have only one
object, called Dhcp4. This is a simplified configuration, as usually
there will be additional objects, like <command>Logging</command> or
-<command>DhcpDns</command>, but we omit them now for clarity. The Dhcp4
+<command>DhcpDdns</command>, but we omit them now for clarity. The Dhcp4
configuration starts with the <command>"Dhcp4": {</command> line
and ends with the corresponding closing brace (in the above example,
the brace after the last comment). Everything defined between those
@@ -2475,7 +2475,7 @@ It is merely echoed by the server
indicates that the server will use the "client identifier" for lease
lookups and "chaddr" if the first lookup returns no results. The
<command>false</command> means that the server will only
- use the "chaddr" to search for client"s lease. Whether the DHCID for
+ use the "chaddr" to search for client's lease. Whether the DHCID for
DNS updates is generated from the "client identifier" or "chaddr" is
controlled through the same parameter accordingly.</para>
@@ -3723,12 +3723,14 @@ src/lib/dhcpsrv/cfg_host_operations.cc -->
<para>The DHCPv4 server supports the following operational commands:
<itemizedlist>
+ <listitem>build-report</listitem>
<listitem>config-get</listitem>
<listitem>config-write</listitem>
<listitem>leases-reclaim</listitem>
<listitem>list-commands</listitem>
<listitem>set-config</listitem>
<listitem>shutdown</listitem>
+ <listitem>version-get</listitem>
</itemizedlist>
as described in <xref linkend="commands-common"/>. In addition,
it supports the following statistics related commands:
diff --git a/doc/guide/dhcp6-srv.xml b/doc/guide/dhcp6-srv.xml
index 0383fc90d6..e811d97b58 100644
--- a/doc/guide/dhcp6-srv.xml
+++ b/doc/guide/dhcp6-srv.xml
@@ -196,7 +196,7 @@ opening curly bracket (or brace). Each configuration consists of
one or more objects. In this specific example, we have only one
object, called Dhcp6. This is a simplified configuration, as usually
there will be additional objects, like <command>Logging</command> or
-<command>DhcpDns</command>, but we omit them now for clarity. The Dhcp6
+<command>DhcpDdns</command>, but we omit them now for clarity. The Dhcp6
configuration starts with the <command>"Dhcp6": {</command> line
and ends with the corresponding closing brace (in the above example,
the brace after the last comment). Everything defined between those
@@ -2892,7 +2892,7 @@ should include options from the isc option space:
<userinput>"option-data": [
{
"name": "vendor-opts",
- "data": 4491"
+ "data": 4491
},
{
"name": "tftp-servers",
@@ -4131,12 +4131,14 @@ If not specified, the default value is:
<para>The DHCPv6 server supports the following operational commands:
<itemizedlist>
+ <listitem>build-report</listitem>
<listitem>config-get</listitem>
<listitem>config-write</listitem>
<listitem>leases-reclaim</listitem>
<listitem>list-commands</listitem>
<listitem>set-config</listitem>
<listitem>shutdown</listitem>
+ <listitem>version-get</listitem>
</itemizedlist>
as described in <xref linkend="commands-common"/>. In addition,
it supports the following statistics related commands:
diff --git a/src/bin/agent/ca_controller.cc b/src/bin/agent/ca_controller.cc
index 475072bf66..38ae98388e 100644
--- a/src/bin/agent/ca_controller.cc
+++ b/src/bin/agent/ca_controller.cc
@@ -8,6 +8,7 @@
#include <agent/ca_controller.h>
#include <agent/ca_process.h>
+#include <agent/ca_command_mgr.h>
#include <agent/parser_context.h>
using namespace isc::process;
@@ -47,6 +48,25 @@ CtrlAgentController::parseFile(const std::string& name) {
return (parser.parseFile(name, ParserContext::PARSER_AGENT));
}
+void
+CtrlAgentController::registerCommands() {
+ CtrlAgentCommandMgr::instance().registerCommand(VERSION_GET_COMMAND,
+ boost::bind(&DControllerBase::versionGetHandler, this, _1, _2));
+
+ CtrlAgentCommandMgr::instance().registerCommand(BUILD_REPORT_COMMAND,
+ boost::bind(&DControllerBase::buildReportHandler, this, _1, _2));
+
+ CtrlAgentCommandMgr::instance().registerCommand(SHUT_DOWN_COMMAND,
+ boost::bind(&DControllerBase::shutdownHandler, this, _1, _2));
+}
+
+void
+CtrlAgentController::deregisterCommands() {
+ CtrlAgentCommandMgr::instance().deregisterCommand(VERSION_GET_COMMAND);
+ CtrlAgentCommandMgr::instance().deregisterCommand(BUILD_REPORT_COMMAND);
+ CtrlAgentCommandMgr::instance().deregisterCommand(SHUT_DOWN_COMMAND);
+}
+
CtrlAgentController::CtrlAgentController()
: DControllerBase(agent_app_name_, agent_bin_name_) {
}
diff --git a/src/bin/agent/ca_controller.h b/src/bin/agent/ca_controller.h
index 1f2f34417a..179d35d710 100644
--- a/src/bin/agent/ca_controller.h
+++ b/src/bin/agent/ca_controller.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2016-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
@@ -47,6 +47,19 @@ public:
isc::data::ConstElementPtr
parseFile(const std::string& name);
+ /// @brief Register commands.
+ ///
+ /// For all commands in the commands_ set at the exception of
+ /// list-commands register the command with the generic
+ /// @ref isc::process::DControllerBase::executeCommand() handler.
+ void registerCommands();
+
+ /// @brief Deregister commands.
+ ///
+ /// For all commands in the commands_ set at the exception of
+ /// list-commands deregister the command.
+ void deregisterCommands();
+
private:
/// @brief Creates an instance of the Control Agent application
@@ -64,9 +77,11 @@ private:
/// @brief Constructor is declared private to maintain the integrity of
/// the singleton instance.
CtrlAgentController();
-
};
+// @Defines a shared pointer to CtrlAgentController
+typedef boost::shared_ptr<CtrlAgentController> CtrlAgentControllerPtr;
+
} // namespace isc::agent
} // namespace isc
diff --git a/src/bin/agent/ca_process.cc b/src/bin/agent/ca_process.cc
index 7847ac9bc2..085fe01d3f 100644
--- a/src/bin/agent/ca_process.cc
+++ b/src/bin/agent/ca_process.cc
@@ -6,6 +6,7 @@
#include <config.h>
#include <agent/ca_process.h>
+#include <agent/ca_controller.h>
#include <agent/ca_response_creator_factory.h>
#include <agent/ca_log.h>
#include <asiolink/io_address.h>
@@ -47,13 +48,20 @@ CtrlAgentProcess::run() {
try {
+ // Register commands.
+ CtrlAgentControllerPtr controller =
+ boost::dynamic_pointer_cast<CtrlAgentController>(
+ CtrlAgentController::instance());
+ controller->registerCommands();
+
// Create response creator factory first. It will be used to generate
// response creators. Each response creator will be used to generate
// answer to specific request.
HttpResponseCreatorFactoryPtr rcf(new CtrlAgentResponseCreatorFactory());
DCfgContextBasePtr base_ctx = getCfgMgr()->getContext();
- CtrlAgentCfgContextPtr ctx = boost::dynamic_pointer_cast<CtrlAgentCfgContext>(base_ctx);
+ CtrlAgentCfgContextPtr ctx =
+ boost::dynamic_pointer_cast<CtrlAgentCfgContext>(base_ctx);
if (!ctx) {
isc_throw(Unexpected, "Interal logic error: bad context type");
}
@@ -99,6 +107,16 @@ CtrlAgentProcess::run() {
"Process run method failed: " << ex.what());
}
+ try {
+ // Deregister commands.
+ CtrlAgentControllerPtr controller =
+ boost::dynamic_pointer_cast<CtrlAgentController>(
+ CtrlAgentController::instance());
+ controller->deregisterCommands();
+ } catch (const std::exception&) {
+ // What to do? Simply ignore...
+ }
+
LOG_DEBUG(agent_logger, DBGLVL_START_SHUT, CTRL_AGENT_RUN_EXIT);
}
@@ -118,13 +136,6 @@ CtrlAgentProcess::configure(isc::data::ConstElementPtr config_set,
return (answer);
}
-isc::data::ConstElementPtr
-CtrlAgentProcess::command(const std::string& command,
- isc::data::ConstElementPtr /*args*/) {
- return (isc::config::createAnswer(COMMAND_INVALID, "Unrecognized command: "
- + command));
-}
-
CtrlAgentCfgMgrPtr
CtrlAgentProcess::getCtrlAgentCfgMgr() {
diff --git a/src/bin/agent/ca_process.h b/src/bin/agent/ca_process.h
index 69de600021..168ed1404b 100644
--- a/src/bin/agent/ca_process.h
+++ b/src/bin/agent/ca_process.h
@@ -87,26 +87,6 @@ public:
configure(isc::data::ConstElementPtr config_set,
bool check_only = false);
- /// @brief Processes the given command.
- ///
- /// This method is called to execute any custom commands supported by the
- /// process. This method must not throw, it should catch any processing
- /// errors and return a success or failure answer as described below.
- ///
- /// @param command is a string label representing the command to execute.
- /// @param args is a set of arguments (if any) required for the given
- /// command.
- /// @return an Element that contains the results of command composed
- /// of an integer status value:
- ///
- /// - COMMAND_SUCCESS indicates a command was successful.
- /// - COMMAND_ERROR indicates a valid command failed execute.
- /// - COMMAND_INVALID indicates a command is not valid.
- ///
- /// and a string explanation of the outcome.
- virtual isc::data::ConstElementPtr
- command(const std::string& command, isc::data::ConstElementPtr args);
-
/// @brief Returns a pointer to the configuration manager.
CtrlAgentCfgMgrPtr getCtrlAgentCfgMgr();
};
diff --git a/src/bin/d2/d2_process.cc b/src/bin/d2/d2_process.cc
index 4070ff4856..c950bf06f4 100644
--- a/src/bin/d2/d2_process.cc
+++ b/src/bin/d2/d2_process.cc
@@ -362,19 +362,6 @@ D2Process::reconfigureQueueMgr() {
}
}
-isc::data::ConstElementPtr
-D2Process::command(const std::string& command,
- isc::data::ConstElementPtr args) {
- // @todo This is the initial implementation. If and when D2 is extended
- // to support its own commands, this implementation must change. Otherwise
- // it should reject all commands as it does now.
- LOG_DEBUG(d2_logger, DBGLVL_TRACE_BASIC, DHCP_DDNS_COMMAND)
- .arg(command).arg(args ? args->str() : "(no args)");
-
- return (isc::config::createAnswer(COMMAND_INVALID, "Unrecognized command: "
- + command));
-}
-
D2Process::~D2Process() {
};
diff --git a/src/bin/d2/d2_process.h b/src/bin/d2/d2_process.h
index 14a5127389..afeaf52c2f 100644
--- a/src/bin/d2/d2_process.h
+++ b/src/bin/d2/d2_process.h
@@ -161,20 +161,6 @@ public:
configure(isc::data::ConstElementPtr config_set,
bool check_only = false);
- /// @brief Processes the given command.
- ///
- /// This method is called to execute any custom commands supported by the
- /// process. This method must not throw, it should catch any processing
- /// errors and return a success or failure answer as described below.
- ///
- /// @param command is a string label representing the command to execute.
- /// @param args is a set of arguments (if any) required for the given
- /// command. It can be a NULL pointer if no arguments exist for a command.
- /// @return an Element that contains the results of command composed
- /// of an integer status value (0 means successful, non-zero means failure),
- /// and a string explanation of the outcome.
- virtual isc::data::ConstElementPtr command(const std::string& command,
- isc::data::ConstElementPtr args);
/// @brief Destructor
virtual ~D2Process();
diff --git a/src/bin/d2/tests/d2_controller_unittests.cc b/src/bin/d2/tests/d2_controller_unittests.cc
index 37eb976f9c..856a88a7c5 100644
--- a/src/bin/d2/tests/d2_controller_unittests.cc
+++ b/src/bin/d2/tests/d2_controller_unittests.cc
@@ -199,35 +199,6 @@ TEST_F(D2ControllerTest, configUpdateTests) {
EXPECT_EQ(1, rcode);
}
-/// @brief Command execution tests.
-/// This really tests just the ability of the handler to invoke the necessary
-/// chain of methods and to handle error conditions.
-/// This test verifies that:
-/// 1. That an unrecognized command is detected and returns a status of
-/// d2::COMMAND_INVALID.
-/// 2. Shutdown command is recognized and returns a d2::COMMAND_SUCCESS status.
-TEST_F(D2ControllerTest, executeCommandTests) {
- int rcode = -1;
- isc::data::ConstElementPtr answer;
- isc::data::ElementPtr arg_set;
-
- // Initialize the application process.
- ASSERT_NO_THROW(initProcess());
- EXPECT_TRUE(checkProcess());
-
- // Verify that an unknown command returns an COMMAND_INVALID response.
- std::string bogus_command("bogus");
- answer = executeCommand(bogus_command, arg_set);
- isc::config::parseAnswer(rcode, answer);
- EXPECT_EQ(COMMAND_INVALID, rcode);
-
- // Verify that shutdown command returns COMMAND_SUCCESS response.
- //answer = executeCommand(SHUT_DOWN_COMMAND, isc::data::ElementPtr());
- answer = executeCommand(SHUT_DOWN_COMMAND, arg_set);
- isc::config::parseAnswer(rcode, answer);
- EXPECT_EQ(COMMAND_SUCCESS, rcode);
-}
-
// Tests that the original configuration is retained after a SIGHUP triggered
// reconfiguration fails due to invalid config content.
TEST_F(D2ControllerTest, invalidConfigReload) {
diff --git a/src/bin/d2/tests/d2_process_unittests.cc b/src/bin/d2/tests/d2_process_unittests.cc
index 065fc85120..900a893c61 100644
--- a/src/bin/d2/tests/d2_process_unittests.cc
+++ b/src/bin/d2/tests/d2_process_unittests.cc
@@ -394,20 +394,6 @@ TEST_F(D2ProcessTest, badConfigureRecovery) {
EXPECT_FALSE(getReconfQueueFlag());
}
-/// @brief Verifies basic command method behavior.
-/// @TODO IF the D2Process is extended to support extra commands this testing
-/// will need to augmented accordingly.
-TEST_F(D2ProcessTest, command) {
- // Verify that the process will process unsupported command and
- // return a failure response.
- int rcode = -1;
- string args = "{ \"arg1\": 77 } ";
- isc::data::ElementPtr json = isc::data::Element::fromJSON(args);
- isc::data::ConstElementPtr answer = command("bogus_command", json);
- parseAnswer(rcode, answer);
- EXPECT_EQ(COMMAND_INVALID, rcode);
-}
-
/// @brief Tests shutdown command argument parsing
/// The shutdown command supports an optional "type" argument. This test
/// checks that for valid values, the shutdown() method: sets the shutdown
diff --git a/src/bin/dhcp4/ctrl_dhcp4_srv.cc b/src/bin/dhcp4/ctrl_dhcp4_srv.cc
index c45f61cabe..30872a653c 100644
--- a/src/bin/dhcp4/ctrl_dhcp4_srv.cc
+++ b/src/bin/dhcp4/ctrl_dhcp4_srv.cc
@@ -15,6 +15,7 @@
#include <dhcpsrv/cfg_db_access.h>
#include <config/command_mgr.h>
#include <stats/stats_mgr.h>
+#include <cfgrpt/config_report.h>
using namespace isc::data;
using namespace isc::hooks;
@@ -206,6 +207,25 @@ ControlledDhcpv4Srv::commandSetConfigHandler(const string&,
}
ConstElementPtr
+ControlledDhcpv4Srv::commandVersionGetHandler(const string&, ConstElementPtr) {
+ ElementPtr extended = Element::create(Dhcpv4Srv::getVersion(true));
+ ElementPtr arguments = Element::createMap();
+ arguments->set("extended", extended);
+ ConstElementPtr answer = isc::config::createAnswer(0,
+ Dhcpv4Srv::getVersion(false),
+ arguments);
+ return (answer);
+}
+
+ConstElementPtr
+ControlledDhcpv4Srv::commandBuildReportHandler(const string&,
+ ConstElementPtr) {
+ ConstElementPtr answer =
+ isc::config::createAnswer(0, isc::detail::getConfigReport());
+ return (answer);
+}
+
+ConstElementPtr
ControlledDhcpv4Srv::commandLeasesReclaimHandler(const string&,
ConstElementPtr args) {
int status_code = 1;
@@ -262,6 +282,12 @@ ControlledDhcpv4Srv::processCommand(const string& command,
} else if (command == "config-get") {
return (srv->commandConfigGetHandler(command, args));
+ } else if (command == "version-get") {
+ return (srv->commandVersionGetHandler(command, args));
+
+ } else if (command == "build-report") {
+ return (srv->commandBuildReportHandler(command, args));
+
} else if (command == "leases-reclaim") {
return (srv->commandLeasesReclaimHandler(command, args));
@@ -398,6 +424,9 @@ ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t port /*= DHCP4_SERVER_PORT*/)
// These are the commands always supported by the DHCPv4 server.
// Please keep the list in alphabetic order.
+ CommandMgr::instance().registerCommand("build-report",
+ boost::bind(&ControlledDhcpv4Srv::commandBuildReportHandler, this, _1, _2));
+
CommandMgr::instance().registerCommand("config-get",
boost::bind(&ControlledDhcpv4Srv::commandConfigGetHandler, this, _1, _2));
@@ -418,6 +447,9 @@ ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t port /*= DHCP4_SERVER_PORT*/)
CommandMgr::instance().registerCommand("shutdown",
boost::bind(&ControlledDhcpv4Srv::commandShutdownHandler, this, _1, _2));
+ CommandMgr::instance().registerCommand("version-get",
+ boost::bind(&ControlledDhcpv4Srv::commandVersionGetHandler, this, _1, _2));
+
// Register statistic related commands
CommandMgr::instance().registerCommand("statistic-get",
boost::bind(&StatsMgr::statisticGetHandler, _1, _2));
@@ -457,6 +489,7 @@ ControlledDhcpv4Srv::~ControlledDhcpv4Srv() {
CommandMgr::instance().closeCommandSocket();
// Deregister any registered commands (please keep in alphabetic order)
+ CommandMgr::instance().deregisterCommand("build-report");
CommandMgr::instance().deregisterCommand("config-get");
CommandMgr::instance().deregisterCommand("config-write");
CommandMgr::instance().deregisterCommand("leases-reclaim");
@@ -469,6 +502,7 @@ ControlledDhcpv4Srv::~ControlledDhcpv4Srv() {
CommandMgr::instance().deregisterCommand("statistic-remove-all");
CommandMgr::instance().deregisterCommand("statistic-reset");
CommandMgr::instance().deregisterCommand("statistic-reset-all");
+ CommandMgr::instance().deregisterCommand("version-get");
} catch (...) {
// Don't want to throw exceptions from the destructor. The server
diff --git a/src/bin/dhcp4/ctrl_dhcp4_srv.h b/src/bin/dhcp4/ctrl_dhcp4_srv.h
index 34b30b4977..163f167e5c 100644
--- a/src/bin/dhcp4/ctrl_dhcp4_srv.h
+++ b/src/bin/dhcp4/ctrl_dhcp4_srv.h
@@ -187,6 +187,31 @@ private:
commandSetConfigHandler(const std::string& command,
isc::data::ConstElementPtr args);
+ /// @brief handler for processing 'version-get' command
+ ///
+ /// This handler processes version-get command, which returns
+ /// over the control channel the -v and -V command line arguments.
+ /// @param command (parameter ignored)
+ /// @param args (parameter ignored)
+ ///
+ /// @return status of the command with the version in text and
+ /// the extended version in arguments.
+ isc::data::ConstElementPtr
+ commandVersionGetHandler(const std::string& command,
+ isc::data::ConstElementPtr args);
+
+ /// @brief handler for processing 'build-report' command
+ ///
+ /// This handler processes build-report command, which returns
+ /// over the control channel the -W command line argument.
+ /// @param command (parameter ignored)
+ /// @param args (parameter ignored)
+ ///
+ /// @return status of the command with the config report
+ isc::data::ConstElementPtr
+ commandBuildReportHandler(const std::string& command,
+ isc::data::ConstElementPtr args);
+
/// @brief Handler for processing 'leases-reclaim' command
///
/// This handler processes leases-reclaim command, which triggers
diff --git a/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc b/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc
index 7bad1859ab..e6554c2eec 100644
--- a/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc
+++ b/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc
@@ -381,12 +381,20 @@ TEST_F(CtrlChannelDhcpv4SrvTest, commandsRegistration) {
std::string command_list = answer->get("arguments")->str();
EXPECT_TRUE(command_list.find("\"list-commands\"") != string::npos);
+ EXPECT_TRUE(command_list.find("\"build-report\"") != string::npos);
+ EXPECT_TRUE(command_list.find("\"config-get\"") != string::npos);
+ EXPECT_TRUE(command_list.find("\"config-write\"") != string::npos);
+ EXPECT_TRUE(command_list.find("\"leases-reclaim\"") != string::npos);
+ EXPECT_TRUE(command_list.find("\"libreload\"") != string::npos);
+ EXPECT_TRUE(command_list.find("\"set-config\"") != string::npos);
+ EXPECT_TRUE(command_list.find("\"shutdown\"") != string::npos);
EXPECT_TRUE(command_list.find("\"statistic-get\"") != string::npos);
EXPECT_TRUE(command_list.find("\"statistic-get-all\"") != string::npos);
EXPECT_TRUE(command_list.find("\"statistic-remove\"") != string::npos);
EXPECT_TRUE(command_list.find("\"statistic-remove-all\"") != string::npos);
EXPECT_TRUE(command_list.find("\"statistic-reset\"") != string::npos);
EXPECT_TRUE(command_list.find("\"statistic-reset-all\"") != string::npos);
+ EXPECT_TRUE(command_list.find("\"version-get\"") != string::npos);
// Ok, and now delete the server. It should deregister its commands.
server_.reset();
@@ -482,6 +490,25 @@ TEST_F(CtrlChannelDhcpv4SrvTest, controlLeasesReclaim) {
EXPECT_TRUE(lease1->stateExpiredReclaimed());
}
+// This test verifies that the DHCP server handles version-get commands
+TEST_F(CtrlChannelDhcpv4SrvTest, getversion) {
+ createUnixChannelServer();
+
+ std::string response;
+
+ // Send the version-get command
+ sendUnixCommand("{ \"command\": \"version-get\" }", response);
+ EXPECT_TRUE(response.find("\"result\": 0") != string::npos);
+ EXPECT_TRUE(response.find("log4cplus") != string::npos);
+ EXPECT_FALSE(response.find("GTEST_VERSION") != string::npos);
+
+ // Send the build-report command
+ sendUnixCommand("{ \"command\": \"build-report\" }", response);
+ EXPECT_TRUE(response.find("\"result\": 0") != string::npos);
+ EXPECT_TRUE(response.find("GTEST_VERSION") != string::npos);
+}
+
+// This test verifies that the DHCP server immediately removed expired
// This test verifies that the DHCP server immediately removed expired
// leases on leases-reclaim command with remove = true
TEST_F(CtrlChannelDhcpv4SrvTest, controlLeasesReclaimRemove) {
@@ -722,6 +749,7 @@ TEST_F(CtrlChannelDhcpv4SrvTest, listCommands) {
EXPECT_NO_THROW(rsp = Element::fromJSON(response));
// We expect the server to report at least the following commands:
+ checkListCommands(rsp, "build-report");
checkListCommands(rsp, "config-get");
checkListCommands(rsp, "config-write");
checkListCommands(rsp, "list-commands");
@@ -735,6 +763,7 @@ TEST_F(CtrlChannelDhcpv4SrvTest, listCommands) {
checkListCommands(rsp, "statistic-remove-all");
checkListCommands(rsp, "statistic-reset");
checkListCommands(rsp, "statistic-reset-all");
+ checkListCommands(rsp, "version-get");
}
// Tests if the server returns its configuration using config-get.
diff --git a/src/bin/dhcp6/ctrl_dhcp6_srv.cc b/src/bin/dhcp6/ctrl_dhcp6_srv.cc
index ab0fd5095d..10363c30b8 100644
--- a/src/bin/dhcp6/ctrl_dhcp6_srv.cc
+++ b/src/bin/dhcp6/ctrl_dhcp6_srv.cc
@@ -16,6 +16,7 @@
#include <dhcp6/json_config_parser.h>
#include <hooks/hooks_manager.h>
#include <stats/stats_mgr.h>
+#include <cfgrpt/config_report.h>
using namespace isc::config;
using namespace isc::data;
@@ -212,6 +213,24 @@ ControlledDhcpv6Srv::commandSetConfigHandler(const string&,
ConstElementPtr
+ControlledDhcpv6Srv::commandVersionGetHandler(const string&, ConstElementPtr) {
+ ElementPtr extended = Element::create(Dhcpv6Srv::getVersion(true));
+ ElementPtr arguments = Element::createMap();
+ arguments->set("extended", extended);
+ ConstElementPtr answer = isc::config::createAnswer(0,
+ Dhcpv6Srv::getVersion(false),
+ arguments);
+ return (answer);
+}
+
+ConstElementPtr
+ControlledDhcpv6Srv::commandBuildReportHandler(const string&, ConstElementPtr) {
+ ConstElementPtr answer =
+ isc::config::createAnswer(0, isc::detail::getConfigReport());
+ return (answer);
+}
+
+ConstElementPtr
ControlledDhcpv6Srv::commandLeasesReclaimHandler(const string&,
ConstElementPtr args) {
int status_code = 1;
@@ -268,6 +287,12 @@ ControlledDhcpv6Srv::processCommand(const std::string& command,
} else if (command == "config-get") {
return (srv->commandConfigGetHandler(command, args));
+ } else if (command == "version-get") {
+ return (srv->commandVersionGetHandler(command, args));
+
+ } else if (command == "build-report") {
+ return (srv->commandBuildReportHandler(command, args));
+
} else if (command == "leases-reclaim") {
return (srv->commandLeasesReclaimHandler(command, args));
@@ -427,6 +452,9 @@ ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t port)
// These are the commands always supported by the DHCPv6 server.
// Please keep the list in alphabetic order.
+ CommandMgr::instance().registerCommand("build-report",
+ boost::bind(&ControlledDhcpv6Srv::commandBuildReportHandler, this, _1, _2));
+
CommandMgr::instance().registerCommand("config-get",
boost::bind(&ControlledDhcpv6Srv::commandConfigGetHandler, this, _1, _2));
@@ -447,6 +475,9 @@ ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t port)
CommandMgr::instance().registerCommand("shutdown",
boost::bind(&ControlledDhcpv6Srv::commandShutdownHandler, this, _1, _2));
+ CommandMgr::instance().registerCommand("version-get",
+ boost::bind(&ControlledDhcpv6Srv::commandVersionGetHandler, this, _1, _2));
+
// Register statistic related commands
CommandMgr::instance().registerCommand("statistic-get",
boost::bind(&StatsMgr::statisticGetHandler, _1, _2));
@@ -485,10 +516,11 @@ ControlledDhcpv6Srv::~ControlledDhcpv6Srv() {
CommandMgr::instance().closeCommandSocket();
// Deregister any registered commands (please keep in alphabetic order)
+ CommandMgr::instance().deregisterCommand("build-report");
CommandMgr::instance().deregisterCommand("config-get");
CommandMgr::instance().deregisterCommand("config-write");
- CommandMgr::instance().deregisterCommand("libreload");
CommandMgr::instance().deregisterCommand("leases-reclaim");
+ CommandMgr::instance().deregisterCommand("libreload");
CommandMgr::instance().deregisterCommand("set-config");
CommandMgr::instance().deregisterCommand("shutdown");
CommandMgr::instance().deregisterCommand("statistic-get");
@@ -497,6 +529,7 @@ ControlledDhcpv6Srv::~ControlledDhcpv6Srv() {
CommandMgr::instance().deregisterCommand("statistic-remove-all");
CommandMgr::instance().deregisterCommand("statistic-reset");
CommandMgr::instance().deregisterCommand("statistic-reset-all");
+ CommandMgr::instance().deregisterCommand("version-get");
} catch (...) {
// Don't want to throw exceptions from the destructor. The server
diff --git a/src/bin/dhcp6/ctrl_dhcp6_srv.h b/src/bin/dhcp6/ctrl_dhcp6_srv.h
index 214c114c2c..3749fbc580 100644
--- a/src/bin/dhcp6/ctrl_dhcp6_srv.h
+++ b/src/bin/dhcp6/ctrl_dhcp6_srv.h
@@ -187,6 +187,31 @@ private:
commandSetConfigHandler(const std::string& command,
isc::data::ConstElementPtr args);
+ /// @brief handler for processing 'version-get' command
+ ///
+ /// This handler processes version-get command, which returns
+ /// over the control channel the -v and -V command line arguments.
+ /// @param command (parameter ignored)
+ /// @param args (parameter ignored)
+ ///
+ /// @return status of the command with the version in text and
+ /// the extended version in arguments.
+ isc::data::ConstElementPtr
+ commandVersionGetHandler(const std::string& command,
+ isc::data::ConstElementPtr args);
+
+ /// @brief handler for processing 'build-report' command
+ ///
+ /// This handler processes build-report command, which returns
+ /// over the control channel the -W command line argument.
+ /// @param command (parameter ignored)
+ /// @param args (parameter ignored)
+ ///
+ /// @return status of the command with the config report
+ isc::data::ConstElementPtr
+ commandBuildReportHandler(const std::string& command,
+ isc::data::ConstElementPtr args);
+
/// @brief Handler for processing 'leases-reclaim' command
///
/// This handler processes leases-reclaim command, which triggers
diff --git a/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc
index cbb1db96d8..c7efdcaf97 100644
--- a/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc
+++ b/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc
@@ -602,12 +602,20 @@ TEST_F(CtrlDhcpv6SrvTest, commandsRegistration) {
std::string command_list = answer->get("arguments")->str();
EXPECT_TRUE(command_list.find("\"list-commands\"") != string::npos);
+ EXPECT_TRUE(command_list.find("\"build-report\"") != string::npos);
+ EXPECT_TRUE(command_list.find("\"config-get\"") != string::npos);
+ EXPECT_TRUE(command_list.find("\"config-write\"") != string::npos);
+ EXPECT_TRUE(command_list.find("\"leases-reclaim\"") != string::npos);
+ EXPECT_TRUE(command_list.find("\"libreload\"") != string::npos);
+ EXPECT_TRUE(command_list.find("\"set-config\"") != string::npos);
+ EXPECT_TRUE(command_list.find("\"shutdown\"") != string::npos);
EXPECT_TRUE(command_list.find("\"statistic-get\"") != string::npos);
EXPECT_TRUE(command_list.find("\"statistic-get-all\"") != string::npos);
EXPECT_TRUE(command_list.find("\"statistic-remove\"") != string::npos);
EXPECT_TRUE(command_list.find("\"statistic-remove-all\"") != string::npos);
EXPECT_TRUE(command_list.find("\"statistic-reset\"") != string::npos);
EXPECT_TRUE(command_list.find("\"statistic-reset-all\"") != string::npos);
+ EXPECT_TRUE(command_list.find("\"version-get\"") != string::npos);
// Ok, and now delete the server. It should deregister its commands.
srv.reset();
@@ -645,6 +653,24 @@ TEST_F(CtrlChannelDhcpv6SrvTest, controlChannelShutdown) {
EXPECT_EQ("{ \"result\": 0, \"text\": \"Shutting down.\" }",response);
}
+// This test verifies that the DHCP server handles version-get commands
+TEST_F(CtrlChannelDhcpv6SrvTest, getversion) {
+ createUnixChannelServer();
+
+ std::string response;
+
+ // Send the version-get command
+ sendUnixCommand("{ \"command\": \"version-get\" }", response);
+ EXPECT_TRUE(response.find("\"result\": 0") != string::npos);
+ EXPECT_TRUE(response.find("log4cplus") != string::npos);
+ EXPECT_FALSE(response.find("GTEST_VERSION") != string::npos);
+
+ // Send the build-report command
+ sendUnixCommand("{ \"command\": \"build-report\" }", response);
+ EXPECT_TRUE(response.find("\"result\": 0") != string::npos);
+ EXPECT_TRUE(response.find("GTEST_VERSION") != string::npos);
+}
+
// This test verifies that the DHCP server immediately reclaims expired
// leases on leases-reclaim command
TEST_F(CtrlChannelDhcpv6SrvTest, controlLeasesReclaim) {
diff --git a/src/bin/shell/tests/shell_process_tests.sh.in b/src/bin/shell/tests/shell_process_tests.sh.in
index 8ec872cf3d..a220640eec 100644
--- a/src/bin/shell/tests/shell_process_tests.sh.in
+++ b/src/bin/shell/tests/shell_process_tests.sh.in
@@ -178,6 +178,6 @@ version_test() {
version_test "shell.version"
shell_command_test "shell.list-commands" "list-commands" \
- "[ { \"arguments\": [ \"list-commands\" ], \"result\": 0 } ]" ""
+ "[ { \"arguments\": [ \"build-report\", \"list-commands\", \"shutdown\", \"version-get\" ], \"result\": 0 } ]" ""
shell_command_test "shell.bogus" "give-me-a-beer" \
"[ { \"result\": 1, \"text\": \"'give-me-a-beer' command not supported.\" } ]" ""
diff --git a/src/lib/cc/command_interpreter.cc b/src/lib/cc/command_interpreter.cc
index c17230b242..163cdc1da0 100644
--- a/src/lib/cc/command_interpreter.cc
+++ b/src/lib/cc/command_interpreter.cc
@@ -8,8 +8,9 @@
#include <exceptions/exceptions.h>
#include <cc/command_interpreter.h>
-#include <string>
#include <cc/data.h>
+#include <string>
+#include <set>
using namespace std;
@@ -171,5 +172,56 @@ parseCommand(ConstElementPtr& arg, ConstElementPtr command) {
return (cmd->stringValue());
}
+ConstElementPtr
+combineCommandsLists(const ConstElementPtr& response1,
+ const ConstElementPtr& response2) {
+ // Usually when this method is called there should be two non-null
+ // responses. If there is just a single response, return this
+ // response.
+ if (!response1 && response2) {
+ return (response2);
+
+ } else if (response1 && !response2) {
+ return (response1);
+
+ } else if (!response1 && !response2) {
+ return (ConstElementPtr());
+
+ } else {
+ // Both responses are non-null so we need to combine the lists
+ // of supported commands if the status codes are 0.
+ int status_code;
+ ConstElementPtr args1 = parseAnswer(status_code, response1);
+ if (status_code != 0) {
+ return (response1);
+ }
+
+ ConstElementPtr args2 = parseAnswer(status_code, response2);
+ if (status_code != 0) {
+ return (response2);
+ }
+
+ const std::vector<ElementPtr> vec1 = args1->listValue();
+ const std::vector<ElementPtr> vec2 = args2->listValue();
+
+ // Storing command names in a set guarantees that the non-unique
+ // command names are aggregated.
+ std::set<std::string> combined_set;
+ for (auto v = vec1.cbegin(); v != vec1.cend(); ++v) {
+ combined_set.insert((*v)->stringValue());
+ }
+ for (auto v = vec2.cbegin(); v != vec2.cend(); ++v) {
+ combined_set.insert((*v)->stringValue());
+ }
+
+ // Create a combined list of commands.
+ ElementPtr combined_list = Element::createList();
+ for (auto s = combined_set.cbegin(); s != combined_set.cend(); ++s) {
+ combined_list->add(Element::create(*s));
+ }
+ return (createAnswer(CONTROL_RESULT_SUCCESS, combined_list));
+ }
+}
+
}
}
diff --git a/src/lib/cc/command_interpreter.h b/src/lib/cc/command_interpreter.h
index 9f5b69fba3..3420086620 100644
--- a/src/lib/cc/command_interpreter.h
+++ b/src/lib/cc/command_interpreter.h
@@ -126,6 +126,23 @@ isc::data::ConstElementPtr createCommand(const std::string& command,
std::string parseCommand(isc::data::ConstElementPtr& arg,
isc::data::ConstElementPtr command);
+/// @brief Combines lists of commands carried in two responses.
+///
+/// This method is used to combine list of commands returned by the
+/// two command managers.
+///
+/// If the same command appears in two responses only a single
+/// instance is returned in the combined response.
+///
+/// @param response1 First command response.
+/// @param response2 Second command response.
+///
+/// @return Pointer to the 'list-commands' response holding combined
+/// list of commands.
+isc::data::ConstElementPtr
+combineCommandsLists(const isc::data::ConstElementPtr& response1,
+ const isc::data::ConstElementPtr& response2);
+
}; // end of namespace isc::config
}; // end of namespace isc
diff --git a/src/lib/config/base_command_mgr.cc b/src/lib/config/base_command_mgr.cc
index 18b25555aa..c148dc5f3d 100644
--- a/src/lib/config/base_command_mgr.cc
+++ b/src/lib/config/base_command_mgr.cc
@@ -8,7 +8,6 @@
#include <config/base_command_mgr.h>
#include <config/config_log.h>
#include <boost/bind.hpp>
-#include <set>
using namespace isc::data;
@@ -88,57 +87,6 @@ BaseCommandMgr::processCommand(const isc::data::ConstElementPtr& cmd) {
}
ConstElementPtr
-BaseCommandMgr::combineCommandsLists(const ConstElementPtr& response1,
- const ConstElementPtr& response2) const {
- // Usually when this method is called there should be two non-null
- // responses. If there is just a single response, return this
- // response.
- if (!response1 && response2) {
- return (response2);
-
- } else if (response1 && !response2) {
- return (response1);
-
- } else if (!response1 && !response2) {
- return (ConstElementPtr());
-
- } else {
- // Both responses are non-null so we need to combine the lists
- // of supported commands if the status codes are 0.
- int status_code;
- ConstElementPtr args1 = parseAnswer(status_code, response1);
- if (status_code != 0) {
- return (response1);
- }
-
- ConstElementPtr args2 = parseAnswer(status_code, response2);
- if (status_code != 0) {
- return (response2);
- }
-
- const std::vector<ElementPtr> vec1 = args1->listValue();
- const std::vector<ElementPtr> vec2 = args2->listValue();
-
- // Storing command names in a set guarantees that the non-unique
- // command names are aggregated.
- std::set<std::string> combined_set;
- for (auto v = vec1.cbegin(); v != vec1.cend(); ++v) {
- combined_set.insert((*v)->stringValue());
- }
- for (auto v = vec2.cbegin(); v != vec2.cend(); ++v) {
- combined_set.insert((*v)->stringValue());
- }
-
- // Create a combined list of commands.
- ElementPtr combined_list = Element::createList();
- for (auto s = combined_set.cbegin(); s != combined_set.cend(); ++s) {
- combined_list->add(Element::create(*s));
- }
- return (createAnswer(CONTROL_RESULT_SUCCESS, combined_list));
- }
-}
-
-ConstElementPtr
BaseCommandMgr::handleCommand(const std::string& cmd_name,
const ConstElementPtr& params) {
auto it = handlers_.find(cmd_name);
diff --git a/src/lib/config/base_command_mgr.h b/src/lib/config/base_command_mgr.h
index 499dcdf744..97321a5387 100644
--- a/src/lib/config/base_command_mgr.h
+++ b/src/lib/config/base_command_mgr.h
@@ -118,27 +118,6 @@ public:
protected:
- /// @brief Combines lists of commands carried in two responses.
- ///
- /// This method is used to combine list of commands returned by the
- /// hook library with the commands supported by the local Command
- /// Manager. This method should also be used within the hook library
- /// to combine commands supported by this hook library with the
- /// commands returned by other hook libraries attached to the server
- /// at the same time.
- ///
- /// If the same command appears in two responses only a single
- /// instance is returned in the combined response.
- ///
- /// @param response1 First command response.
- /// @param response2 Second command response.
- ///
- /// @return Pointer to the 'list-commands' response holding combined
- /// list of commands.
- isc::data::ConstElementPtr
- combineCommandsLists(const isc::data::ConstElementPtr& response1,
- const isc::data::ConstElementPtr& response2) const;
-
/// @brief Handles the command having a given name and arguments.
///
/// This method can be overridden in the derived classes to provide
diff --git a/src/lib/log/logger_impl.cc b/src/lib/log/logger_impl.cc
index 66c6379e91..44d7095e8c 100644
--- a/src/lib/log/logger_impl.cc
+++ b/src/lib/log/logger_impl.cc
@@ -82,7 +82,7 @@ LoggerImpl::~LoggerImpl() {
std::string
LoggerImpl::getVersion() {
std::ostringstream ver;
- ver << "log4plus ";
+ ver << "log4cplus ";
ver << log4cplus::versionStr;
return (ver.str());
}
diff --git a/src/lib/process/d_controller.cc b/src/lib/process/d_controller.cc
index 28cbf8d427..974e178392 100644
--- a/src/lib/process/d_controller.cc
+++ b/src/lib/process/d_controller.cc
@@ -29,6 +29,9 @@
#include <sstream>
#include <unistd.h>
+using namespace isc::data;
+using namespace isc::config;
+
namespace isc {
namespace process {
@@ -54,9 +57,9 @@ DControllerBase::setController(const DControllerBasePtr& controller) {
controller_ = controller;
}
-isc::data::ConstElementPtr
+ConstElementPtr
DControllerBase::parseFile(const std::string&) {
- isc::data::ConstElementPtr elements;
+ ConstElementPtr elements;
return (elements);
}
@@ -125,8 +128,7 @@ DControllerBase::launch(int argc, char* argv[], const bool test_mode) {
// Step 3 is to load configuration from file.
int rcode;
- isc::data::ConstElementPtr comment
- = isc::config::parseAnswer(rcode, configFromFile());
+ ConstElementPtr comment = parseAnswer(rcode, configFromFile());
if (rcode != 0) {
LOG_FATAL(dctl_logger, DCTL_CONFIG_FILE_LOAD_FAIL)
.arg(app_name_).arg(comment->stringValue());
@@ -169,7 +171,7 @@ DControllerBase::checkConfigOnly() {
// Basic sanity check: file name must not be empty.
isc_throw(InvalidUsage, "JSON configuration file not specified");
}
- isc::data::ConstElementPtr whole_config = parseFile(config_file);
+ ConstElementPtr whole_config = parseFile(config_file);
if (!whole_config) {
// No fallback to fromJSONFile
isc_throw(InvalidUsage, "No configuration found");
@@ -179,7 +181,7 @@ DControllerBase::checkConfigOnly() {
}
// Check the logic next.
- isc::data::ConstElementPtr module_config;
+ ConstElementPtr module_config;
module_config = whole_config->get(getAppName());
if (!module_config) {
isc_throw(InvalidUsage, "Config file " << config_file <<
@@ -189,10 +191,9 @@ DControllerBase::checkConfigOnly() {
// Get an application process object.
initProcess();
- isc::data::ConstElementPtr answer;
- answer = checkConfig(module_config);
+ ConstElementPtr answer = checkConfig(module_config);
int rcode = 0;
- answer = isc::config::parseAnswer(rcode, answer);
+ answer = parseAnswer(rcode, answer);
if (rcode != 0) {
isc_throw(InvalidUsage, "Error encountered: "
<< answer->stringValue());
@@ -312,15 +313,15 @@ DControllerBase::initProcess() {
process_->init();
}
-isc::data::ConstElementPtr
+ConstElementPtr
DControllerBase::configFromFile() {
// Rollback any previous staging configuration. For D2, only a
// logger configuration is used here.
isc::dhcp::CfgMgr::instance().rollback();
// Will hold configuration.
- isc::data::ConstElementPtr module_config;
+ ConstElementPtr module_config;
// Will receive configuration result.
- isc::data::ConstElementPtr answer;
+ ConstElementPtr answer;
try {
std::string config_file = getConfigFile();
if (config_file.empty()) {
@@ -331,10 +332,10 @@ DControllerBase::configFromFile() {
// If parseFile returns an empty pointer, then pass the file onto the
// original JSON parser.
- isc::data::ConstElementPtr whole_config = parseFile(config_file);
+ ConstElementPtr whole_config = parseFile(config_file);
if (!whole_config) {
// Read contents of the file and parse it as JSON
- whole_config = isc::data::Element::fromJSONFile(config_file, true);
+ whole_config = Element::fromJSONFile(config_file, true);
}
// Let's configure logging before applying the configuration,
@@ -358,7 +359,7 @@ DControllerBase::configFromFile() {
answer = updateConfig(module_config);
int rcode = 0;
- isc::config::parseAnswer(rcode, answer);
+ parseAnswer(rcode, answer);
if (!rcode) {
// Configuration successful, so apply the logging configuration
// to log4cplus.
@@ -370,9 +371,8 @@ DControllerBase::configFromFile() {
// Rollback logging configuration.
isc::dhcp::CfgMgr::instance().rollback();
// build an error result
- isc::data::ConstElementPtr error =
- isc::config::createAnswer(1,
- std::string("Configuration parsing failed: ") + ex.what());
+ ConstElementPtr error = createAnswer(COMMAND_ERROR,
+ std::string("Configuration parsing failed: ") + ex.what());
return (error);
}
@@ -394,55 +394,45 @@ DControllerBase::runProcess() {
}
// Instance method for handling new config
-isc::data::ConstElementPtr
-DControllerBase::updateConfig(isc::data::ConstElementPtr new_config) {
+ConstElementPtr
+DControllerBase::updateConfig(ConstElementPtr new_config) {
return (process_->configure(new_config, false));
}
// Instance method for checking new config
-isc::data::ConstElementPtr
-DControllerBase::checkConfig(isc::data::ConstElementPtr new_config) {
+ConstElementPtr
+DControllerBase::checkConfig(ConstElementPtr new_config) {
return (process_->configure(new_config, true));
}
+ConstElementPtr
+DControllerBase::versionGetHandler(const std::string&, ConstElementPtr args) {
+ ConstElementPtr answer;
-// Instance method for executing commands
-isc::data::ConstElementPtr
-DControllerBase::executeCommand(const std::string& command,
- isc::data::ConstElementPtr args) {
- // Shutdown is universal. If its not that, then try it as
- // a custom command supported by the derivation. If that
- // doesn't pan out either, than send to it the application
- // as it may be supported there.
- isc::data::ConstElementPtr answer;
- if (command.compare(SHUT_DOWN_COMMAND) == 0) {
- answer = shutdownProcess(args);
- } else {
- // It wasn't shutdown, so it may be a custom controller command.
- int rcode = 0;
- answer = customControllerCommand(command, args);
- isc::config::parseAnswer(rcode, answer);
- if (rcode == COMMAND_INVALID)
- {
- // It wasn't a controller command, so it may be an application command.
- answer = process_->command(command, args);
- }
- }
-
+ // For version-get put the extended version in arguments
+ ElementPtr extended = Element::create(getVersion(true));
+ ElementPtr arguments = Element::createMap();
+ arguments->set("extended", extended);
+ answer = createAnswer(COMMAND_SUCCESS, getVersion(false), arguments);
return (answer);
}
-isc::data::ConstElementPtr
-DControllerBase::customControllerCommand(const std::string& command,
- isc::data::ConstElementPtr /* args */) {
+ConstElementPtr
+DControllerBase::buildReportHandler(const std::string&, ConstElementPtr args) {
+ return (createAnswer(COMMAND_SUCCESS, isc::detail::getConfigReport()));
+}
- // Default implementation always returns invalid command.
- return (isc::config::createAnswer(COMMAND_INVALID,
- "Unrecognized command: " + command));
+ConstElementPtr
+DControllerBase::shutdownHandler(const std::string&, ConstElementPtr args) {
+ // Shutdown is universal. If its not that, then try it as
+ // a custom command supported by the derivation. If that
+ // doesn't pan out either, than send to it the application
+ // as it may be supported there.
+ return (shutdownProcess(args));
}
-isc::data::ConstElementPtr
-DControllerBase::shutdownProcess(isc::data::ConstElementPtr args) {
+ConstElementPtr
+DControllerBase::shutdownProcess(ConstElementPtr args) {
if (process_) {
return (process_->shutdown(args));
}
@@ -450,7 +440,7 @@ DControllerBase::shutdownProcess(isc::data::ConstElementPtr args) {
// Not really a failure, but this condition is worth noting. In reality
// it should be pretty hard to cause this.
LOG_WARN(dctl_logger, DCTL_NOT_RUNNING).arg(app_name_);
- return (isc::config::createAnswer(0, "Process has not been initialized."));
+ return (createAnswer(COMMAND_SUCCESS, "Process has not been initialized"));
}
void
@@ -498,9 +488,7 @@ DControllerBase::processSignal(int signum) {
LOG_INFO(dctl_logger, DCTL_CFG_FILE_RELOAD_SIGNAL_RECVD)
.arg(signum).arg(getConfigFile());
int rcode;
- isc::data::ConstElementPtr comment = isc::config::
- parseAnswer(rcode,
- configFromFile());
+ ConstElementPtr comment = parseAnswer(rcode, configFromFile());
if (rcode != 0) {
LOG_ERROR(dctl_logger, DCTL_CFG_FILE_RELOAD_ERROR)
.arg(comment->stringValue());
@@ -514,8 +502,8 @@ DControllerBase::processSignal(int signum) {
{
LOG_DEBUG(dctl_logger, DBGLVL_START_SHUT,
DCTL_SHUTDOWN_SIGNAL_RECVD).arg(signum);
- isc::data::ElementPtr arg_set;
- executeCommand(SHUT_DOWN_COMMAND, arg_set);
+ ElementPtr arg_set;
+ shutdownHandler(SHUT_DOWN_COMMAND, arg_set);
break;
}
diff --git a/src/lib/process/d_controller.h b/src/lib/process/d_controller.h
index edd92c70e0..f4b536202b 100644
--- a/src/lib/process/d_controller.h
+++ b/src/lib/process/d_controller.h
@@ -19,6 +19,8 @@
#include <boost/shared_ptr.hpp>
#include <boost/noncopyable.hpp>
+#include <string>
+#include <set>
namespace isc {
namespace process {
@@ -216,39 +218,6 @@ public:
/// non-zero means failure), and a string explanation of the outcome.
virtual isc::data::ConstElementPtr configFromFile();
- /// @brief Instance method invoked by the command event handler and which
- /// processes the actual command directive.
- ///
- /// It supports the execution of:
- ///
- /// 1. Stock controller commands - commands common to all DControllerBase
- /// derivations. Currently there is only one, the shutdown command.
- ///
- /// 2. Custom controller commands - commands that the deriving controller
- /// class implements. These commands are executed by the deriving
- /// controller.
- ///
- /// 3. Custom application commands - commands supported by the application
- /// process implementation. These commands are executed by the application
- /// process.
- ///
- /// @param command is a string label representing the command to execute.
- /// @param args is a set of arguments (if any) required for the given
- /// command.
- ///
- /// @return an Element that contains the results of command composed
- /// of an integer status value and a string explanation of the outcome.
- /// The status value is one of the following:
- /// COMMAND_SUCCESS - Command executed successfully
- /// COMMAND_ERROR - Command is valid but suffered an operational
- /// failure.
- /// COMMAND_INVALID - Command is not recognized as valid be either
- /// the controller or the application process.
- virtual isc::data::ConstElementPtr executeCommand(const std::string&
- command,
- isc::data::
- ConstElementPtr args);
-
/// @brief Fetches the name of the application under control.
///
/// @return returns the controller service name string
@@ -263,6 +232,41 @@ public:
return (bin_name_);
}
+ /// @brief handler for version-get command
+ ///
+ /// This method handles the version-get command. It returns the basic and
+ /// extended version.
+ ///
+ /// @param command (ignored)
+ /// @param args (ignored)
+ /// @return answer with version details.
+ isc::data::ConstElementPtr
+ versionGetHandler(const std::string& command,
+ isc::data::ConstElementPtr args);
+
+ /// @brief handler for 'build-report' command
+ ///
+ /// This method handles build-report command. It returns the output printed
+ /// by configure script which contains most compilation parameters.
+ ///
+ /// @param command (ignored)
+ /// @param args (ignored)
+ /// @return answer with build report
+ isc::data::ConstElementPtr
+ buildReportHandler(const std::string& command,
+ isc::data::ConstElementPtr args);
+
+ /// @brief handler for 'shutdown' command
+ ///
+ /// This method handles shutdown command. It initiates the shutdown procedure
+ /// using CPL methods.
+ /// @param command (ignored)
+ /// @param args (ignored)
+ /// @return answer confirming that the shutdown procedure is started
+ isc::data::ConstElementPtr
+ shutdownHandler(const std::string& command,
+ isc::data::ConstElementPtr args);
+
protected:
/// @brief Virtual method that provides derivations the opportunity to
/// support additional command line options. It is invoked during command
@@ -287,26 +291,6 @@ protected:
/// Note this value is subsequently wrapped in a smart pointer.
virtual DProcessBase* createProcess() = 0;
- /// @brief Virtual method that provides derivations the opportunity to
- /// support custom external commands executed by the controller. This
- /// method is invoked by the processCommand if the received command is
- /// not a stock controller command.
- ///
- /// @param command is a string label representing the command to execute.
- /// @param args is a set of arguments (if any) required for the given
- /// command.
- ///
- /// @return an Element that contains the results of command composed
- /// of an integer status value and a string explanation of the outcome.
- /// The status value is one of the following:
- /// COMMAND_SUCCESS - Command executed successfully
- /// COMMAND_ERROR - Command is valid but suffered an operational
- /// failure.
- /// COMMAND_INVALID - Command is not recognized as a valid custom
- /// controller command.
- virtual isc::data::ConstElementPtr customControllerCommand(
- const std::string& command, isc::data::ConstElementPtr args);
-
/// @brief Virtual method which can be used to contribute derivation
/// specific usage text. It is invoked by the usage() method under
/// invalid usage conditions.
diff --git a/src/lib/process/d_process.h b/src/lib/process/d_process.h
index ea920e4275..0ab13133d5 100644
--- a/src/lib/process/d_process.h
+++ b/src/lib/process/d_process.h
@@ -25,6 +25,12 @@ public:
isc::Exception(file, line, what) { };
};
+/// @brief String value for the version-get command.
+static const std::string VERSION_GET_COMMAND("version-get");
+
+/// @brief String value for the build-report command.
+static const std::string BUILD_REPORT_COMMAND("build-report");
+
/// @brief String value for the shutdown command.
static const std::string SHUT_DOWN_COMMAND("shutdown");
@@ -121,26 +127,6 @@ public:
configure(isc::data::ConstElementPtr config_set,
bool check_only = false) = 0;
- /// @brief Processes the given command.
- ///
- /// This method is called to execute any custom commands supported by the
- /// process. This method must not throw, it should catch any processing
- /// errors and return a success or failure answer as described below.
- ///
- /// @param command is a string label representing the command to execute.
- /// @param args is a set of arguments (if any) required for the given
- /// command.
- /// @return an Element that contains the results of command composed
- /// of an integer status value:
- ///
- /// - COMMAND_SUCCESS indicates a command was successful.
- /// - COMMAND_ERROR indicates a valid command failed execute.
- /// - COMMAND_INVALID indicates a command is not valid.
- ///
- /// and a string explanation of the outcome.
- virtual isc::data::ConstElementPtr command(
- const std::string& command, isc::data::ConstElementPtr args) = 0;
-
/// @brief Destructor
virtual ~DProcessBase(){};
diff --git a/src/lib/process/tests/d_controller_unittests.cc b/src/lib/process/tests/d_controller_unittests.cc
index bfc7885200..1858e31628 100644
--- a/src/lib/process/tests/d_controller_unittests.cc
+++ b/src/lib/process/tests/d_controller_unittests.cc
@@ -290,70 +290,6 @@ TEST_F(DStubControllerTest, configUpdateTests) {
EXPECT_EQ(1, rcode);
}
-/// @brief Command execution tests.
-/// This really tests just the ability of the handler to invoke the necessary
-/// chain of methods and to handle error conditions.
-/// This test verifies that:
-/// 1. That an unrecognized command is detected and returns a status of
-/// process::COMMAND_INVALID.
-/// 2. Shutdown command is recognized and returns a process::COMMAND_SUCCESS
-/// status.
-/// 3. A valid, custom controller command is recognized a
-/// process::COMMAND_SUCCESS
-/// status.
-/// 4. A valid, custom process command is recognized a
-/// process::COMMAND_SUCCESS status.
-/// 5. That a valid controller command that fails returns a
-/// process::COMMAND_ERROR.
-/// 6. That a valid process command that fails returns a process::COMMAND_ERROR.
-TEST_F(DStubControllerTest, executeCommandTests) {
- int rcode = -1;
- isc::data::ConstElementPtr answer;
- isc::data::ElementPtr arg_set;
-
- // Initialize the application process.
- ASSERT_NO_THROW(initProcess());
- EXPECT_TRUE(checkProcess());
-
- // Verify that an unknown command returns an process::COMMAND_INVALID
- // response.
- std::string bogus_command("bogus");
- answer = executeCommand(bogus_command, arg_set);
- isc::config::parseAnswer(rcode, answer);
- EXPECT_EQ(COMMAND_INVALID, rcode);
-
- // Verify that shutdown command returns process::COMMAND_SUCCESS response.
- answer = executeCommand(SHUT_DOWN_COMMAND, arg_set);
- isc::config::parseAnswer(rcode, answer);
- EXPECT_EQ(COMMAND_SUCCESS, rcode);
-
- // Verify that a valid custom controller command returns
- // process::COMMAND_SUCCESS response.
- answer = executeCommand(DStubController::stub_ctl_command_, arg_set);
- isc::config::parseAnswer(rcode, answer);
- EXPECT_EQ(COMMAND_SUCCESS, rcode);
-
- // Verify that a valid custom process command returns
- // process::COMMAND_SUCCESS response.
- answer = executeCommand(DStubProcess::stub_proc_command_, arg_set);
- isc::config::parseAnswer(rcode, answer);
- EXPECT_EQ(COMMAND_SUCCESS, rcode);
-
- // Verify that a valid custom controller command that fails returns
- // a process::COMMAND_ERROR.
- SimFailure::set(SimFailure::ftControllerCommand);
- answer = executeCommand(DStubController::stub_ctl_command_, arg_set);
- isc::config::parseAnswer(rcode, answer);
- EXPECT_EQ(COMMAND_ERROR, rcode);
-
- // Verify that a valid custom process command that fails returns
- // a process::COMMAND_ERROR.
- SimFailure::set(SimFailure::ftProcessCommand);
- answer = executeCommand(DStubProcess::stub_proc_command_, arg_set);
- isc::config::parseAnswer(rcode, answer);
- EXPECT_EQ(COMMAND_ERROR, rcode);
-}
-
// Tests that registered signals are caught and handled.
TEST_F(DStubControllerTest, ioSignals) {
// Tell test controller just to record the signals, don't call the
diff --git a/src/lib/process/testutils/d_test_stubs.h b/src/lib/process/testutils/d_test_stubs.h
index ecb8959610..09c2298787 100644
--- a/src/lib/process/testutils/d_test_stubs.h
+++ b/src/lib/process/testutils/d_test_stubs.h
@@ -499,18 +499,11 @@ public:
return (getController()->checkConfig(new_config));
}
- /// @Wrapper to invoke the Controller's executeCommand method. Please
- /// refer to DControllerBase::executeCommand for details.
- isc::data::ConstElementPtr executeCommand(const std::string& command,
- isc::data::ConstElementPtr args){
- return (getController()->executeCommand(command, args));
- }
-
/// @brief Callback that will generate shutdown command via the
/// command callback function.
static void genShutdownCallback() {
isc::data::ElementPtr arg_set;
- getController()->executeCommand(SHUT_DOWN_COMMAND, arg_set);
+ getController()->shutdownHandler(SHUT_DOWN_COMMAND, arg_set);
}
/// @brief Callback that throws an exception.