From e38e8d974c77d6b0e91bd270bab35f280e47a746 Mon Sep 17 00:00:00 2001 From: Francis Dupont Date: Fri, 17 Mar 2017 03:39:22 +0100 Subject: [102b] rebased --- doc/guide/ctrl-channel.xml | 32 ++++++- doc/guide/dhcp4-srv.xml | 6 +- doc/guide/dhcp6-srv.xml | 6 +- src/bin/agent/ca_controller.cc | 20 +++++ src/bin/agent/ca_controller.h | 19 ++++- src/bin/agent/ca_process.cc | 27 ++++-- src/bin/agent/ca_process.h | 20 ----- src/bin/d2/d2_process.cc | 13 --- src/bin/d2/d2_process.h | 14 ---- src/bin/d2/tests/d2_controller_unittests.cc | 29 ------- src/bin/d2/tests/d2_process_unittests.cc | 14 ---- src/bin/dhcp4/ctrl_dhcp4_srv.cc | 34 ++++++++ src/bin/dhcp4/ctrl_dhcp4_srv.h | 25 ++++++ src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc | 29 +++++++ src/bin/dhcp6/ctrl_dhcp6_srv.cc | 35 +++++++- src/bin/dhcp6/ctrl_dhcp6_srv.h | 25 ++++++ src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc | 26 ++++++ src/bin/shell/tests/shell_process_tests.sh.in | 2 +- src/lib/cc/command_interpreter.cc | 54 +++++++++++- src/lib/cc/command_interpreter.h | 17 ++++ src/lib/config/base_command_mgr.cc | 52 ------------ src/lib/config/base_command_mgr.h | 21 ----- src/lib/log/logger_impl.cc | 2 +- src/lib/process/d_controller.cc | 106 +++++++++++------------- src/lib/process/d_controller.h | 90 +++++++++----------- src/lib/process/d_process.h | 26 ++---- src/lib/process/tests/d_controller_unittests.cc | 64 -------------- src/lib/process/testutils/d_test_stubs.h | 9 +- 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
Commands Supported by Both the DHCPv4 and DHCPv6 Servers +
+ build-report + + The build-report command returns + on the control channel what the command line + -W argument displays, i.e. the embedded + content of the config.report file. + This command does not take any parameters. + + +{ + "command": "build-report" +} + +
+
config-get @@ -315,7 +331,21 @@ will be sent to Kea and the responses received from Kea printed to standard outp
- +
+ version-get + + The version-get command returns on the control + channel what the command line -v argument + displays with in arguments the extended version, i.e., what + the command line -V argument displays. This command + does not take any parameters. + + +{ + "command": "version-get" +} + +
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 Logging or -DhcpDns, but we omit them now for clarity. The Dhcp4 +DhcpDdns, but we omit them now for clarity. The Dhcp4 configuration starts with the "Dhcp4": { 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 false 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. @@ -3723,12 +3723,14 @@ src/lib/dhcpsrv/cfg_host_operations.cc --> The DHCPv4 server supports the following operational commands: + build-report config-get config-write leases-reclaim list-commands set-config shutdown + version-get as described in . 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 Logging or -DhcpDns, but we omit them now for clarity. The Dhcp6 +DhcpDdns, but we omit them now for clarity. The Dhcp6 configuration starts with the "Dhcp6": { 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: "option-data": [ { "name": "vendor-opts", - "data": 4491" + "data": 4491 }, { "name": "tftp-servers", @@ -4131,12 +4131,14 @@ If not specified, the default value is: The DHCPv6 server supports the following operational commands: + build-report config-get config-write leases-reclaim list-commands set-config shutdown + version-get as described in . 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 #include +#include #include 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 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 #include +#include #include #include #include @@ -47,13 +48,20 @@ CtrlAgentProcess::run() { try { + // Register commands. + CtrlAgentControllerPtr controller = + boost::dynamic_pointer_cast( + 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(base_ctx); + CtrlAgentCfgContextPtr ctx = + boost::dynamic_pointer_cast(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::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 #include #include +#include using namespace isc::data; using namespace isc::hooks; @@ -205,6 +206,25 @@ ControlledDhcpv4Srv::commandSetConfigHandler(const string&, return (result); } +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) { @@ -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 #include #include +#include using namespace isc::config; using namespace isc::data; @@ -211,6 +212,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) { @@ -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 #include -#include #include +#include +#include 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 vec1 = args1->listValue(); + const std::vector vec2 = args2->listValue(); + + // Storing command names in a set guarantees that the non-unique + // command names are aggregated. + std::set 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 #include #include -#include using namespace isc::data; @@ -87,57 +86,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 vec1 = args1->listValue(); - const std::vector vec2 = args2->listValue(); - - // Storing command names in a set guarantees that the non-unique - // command names are aggregated. - std::set 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) { 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 #include +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 #include +#include +#include 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. -- cgit v1.2.3