// Check that the following command are really available.
checkCommandRegistered("build-report");
checkCommandRegistered("config-get");
+ checkCommandRegistered("config-hash-get");
checkCommandRegistered("config-reload");
checkCommandRegistered("config-set");
checkCommandRegistered("config-test");
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-hash-get\"") != string::npos);
EXPECT_TRUE(command_list.find("\"config-reload\"") != string::npos);
EXPECT_TRUE(command_list.find("\"config-set\"") != string::npos);
EXPECT_TRUE(command_list.find("\"config-test\"") != string::npos);
// We expect the server to report at least the following commands:
checkListCommands(rsp, "build-report");
checkListCommands(rsp, "config-get");
+ checkListCommands(rsp, "config-hash-get");
checkListCommands(rsp, "config-reload");
checkListCommands(rsp, "config-set");
checkListCommands(rsp, "config-test");
EXPECT_TRUE(cfg->get("DhcpDdns"));
}
+// Tests if the server returns the hash of its configuration using
+// config-hash-get.
+TEST_F(CtrlChannelD2Test, configHashGet) {
+ EXPECT_NO_THROW(createUnixChannelServer());
+ string response;
+
+ sendUnixCommand("{ \"command\": \"config-hash-get\" }", response);
+ ConstElementPtr rsp;
+
+ // The response should be a valid JSON.
+ EXPECT_NO_THROW(rsp = Element::fromJSON(response));
+ ASSERT_TRUE(rsp);
+
+ int status;
+ ConstElementPtr args = parseAnswer(status, rsp);
+ EXPECT_EQ(CONTROL_RESULT_SUCCESS, status);
+
+ // Ok, now roughly check if the response seems legit.
+ ASSERT_TRUE(args);
+ ASSERT_EQ(Element::map, args->getType());
+ ConstElementPtr hash = args->get("hash");
+ ASSERT_TRUE(hash);
+ ASSERT_EQ(Element::string, hash->getType());
+ // SHA-256 -> 64 hex digits.
+ EXPECT_EQ(64, hash->stringValue().size());
+}
+
// Verify that the "config-test" command will do what we expect.
TEST_F(CtrlChannelD2Test, configTest) {
/// - config-reload
/// - config-set
/// - config-get
+ /// - config-hash-get
/// - config-test
/// - dhcp-disable
/// - dhcp-enable
#include <cc/command_interpreter.h>
#include <cc/data.h>
#include <config/command_mgr.h>
+#include <cryptolink/crypto_hash.h>
#include <dhcp/libdhcp++.h>
#include <dhcp6/ctrl_dhcp6_srv.h>
#include <dhcp6/dhcp6_log.h>
#include <hooks/hooks_manager.h>
#include <process/cfgrpt/config_report.h>
#include <stats/stats_mgr.h>
+#include <util/encode/hex.h>
#include <util/multi_threading_mgr.h>
#include <signal.h>
return (createAnswer(CONTROL_RESULT_SUCCESS, config));
}
+ConstElementPtr
+ControlledDhcpv6Srv::commandConfigHashGetHandler(const string&,
+ ConstElementPtr /*args*/) {
+ ConstElementPtr config = CfgMgr::instance().getCurrentCfg()->toElement();
+ // Assume that config is never null.
+ string config_txt = config->str();
+ OutputBuffer hash_data(0);
+ isc::cryptolink::digest(config_txt.c_str(),
+ config_txt.size(),
+ isc::cryptolink::HashAlgorithm::SHA256,
+ hash_data);
+ vector<uint8_t> hash;
+ hash.resize(hash_data.getLength());
+ if (hash.size() > 0) {
+ memmove(&hash[0], hash_data.getData(), hash.size());
+ }
+ ElementPtr params = Element::createMap();
+ params->set("hash", Element::create(encode::encodeHex(hash)));
+ return (createAnswer(CONTROL_RESULT_SUCCESS, params));
+}
+
ConstElementPtr
ControlledDhcpv6Srv::commandConfigWriteHandler(const string&,
ConstElementPtr args) {
} else if (command == "config-get") {
return (srv->commandConfigGetHandler(command, args));
+ } else if (command == "config-hash-get") {
+ return (srv->commandConfigHashGetHandler(command, args));
+
} else if (command == "config-test") {
return (srv->commandConfigTestHandler(command, args));
CommandMgr::instance().registerCommand("config-get",
std::bind(&ControlledDhcpv6Srv::commandConfigGetHandler, this, ph::_1, ph::_2));
+ CommandMgr::instance().registerCommand("config-hash-get",
+ std::bind(&ControlledDhcpv6Srv::commandConfigHashGetHandler, this, ph::_1, ph::_2));
+
CommandMgr::instance().registerCommand("config-reload",
std::bind(&ControlledDhcpv6Srv::commandConfigReloadHandler, this, ph::_1, ph::_2));
CommandMgr::instance().deregisterCommand("build-report");
CommandMgr::instance().deregisterCommand("config-backend-pull");
CommandMgr::instance().deregisterCommand("config-get");
+ CommandMgr::instance().deregisterCommand("config-hash-get");
CommandMgr::instance().deregisterCommand("config-reload");
CommandMgr::instance().deregisterCommand("config-set");
CommandMgr::instance().deregisterCommand("config-test");
/// - config-reload
/// - config-set
/// - config-get
+ /// - config-hash-get
/// - config-test
/// - dhcp-disable
/// - dhcp-enable
commandConfigReloadHandler(const std::string& command,
isc::data::ConstElementPtr args);
- /// @brief handler for processing 'get-config' command
+ /// @brief handler for processing 'config-get' command
///
- /// This handler processes get-config command, which retrieves
+ /// This handler processes config-get command, which retrieves
/// the current configuration and returns it in response.
///
/// @param command (ignored)
commandConfigGetHandler(const std::string& command,
isc::data::ConstElementPtr args);
- /// @brief handler for processing 'write-config' command
+ /// @brief handler for processing 'config-hash-get' command
///
- /// This handle processes write-config command, which writes the
+ /// This handler processes config-hash-get command, which retrieves
+ /// the hash of the current configuration and returns it in response.
+ ///
+ /// @param command (ignored)
+ /// @param args (ignored)
+ /// @return hash of current configuration wrapped in a response
+ isc::data::ConstElementPtr
+ commandConfigHashGetHandler(const std::string& command,
+ isc::data::ConstElementPtr args);
+
+ /// @brief handler for processing 'config-write' command
+ ///
+ /// This handle processes config-write command, which writes the
/// current configuration to disk. This command takes one optional
/// parameter called filename. If specified, the current configuration
/// will be written to that file. If not specified, the file used during
EXPECT_TRUE(command_list.find("\"build-report\"") != string::npos);
EXPECT_TRUE(command_list.find("\"config-backend-pull\"") != string::npos);
EXPECT_TRUE(command_list.find("\"config-get\"") != string::npos);
+ EXPECT_TRUE(command_list.find("\"config-hash-get\"") != string::npos);
EXPECT_TRUE(command_list.find("\"config-set\"") != string::npos);
EXPECT_TRUE(command_list.find("\"config-write\"") != string::npos);
EXPECT_TRUE(command_list.find("\"leases-reclaim\"") != string::npos);
EXPECT_TRUE(cfg->get("Dhcp6")->get("loggers"));
}
+// Tests if the server returns the hash of its configuration using
+// config-hash-get.
+TEST_F(CtrlChannelDhcpv6SrvTest, configHashGet) {
+ createUnixChannelServer();
+ std::string response;
+
+ sendUnixCommand("{ \"command\": \"config-hash-get\" }", response);
+ ConstElementPtr rsp;
+
+ // The response should be a valid JSON.
+ EXPECT_NO_THROW(rsp = Element::fromJSON(response));
+ ASSERT_TRUE(rsp);
+
+ int status;
+ ConstElementPtr args = parseAnswer(status, rsp);
+ EXPECT_EQ(CONTROL_RESULT_SUCCESS, status);
+
+ // Ok, now roughly check if the response seems legit.
+ ASSERT_TRUE(args);
+ ASSERT_EQ(Element::map, args->getType());
+ ConstElementPtr hash = args->get("hash");
+ ASSERT_TRUE(hash);
+ ASSERT_EQ(Element::string, hash->getType());
+ // SHA-256 -> 64 hex digits.
+ EXPECT_EQ(64, hash->stringValue().size());
+}
+
// Verify that the "config-test" command will do what we expect.
TEST_F(CtrlChannelDhcpv6SrvTest, configTest) {
createUnixChannelServer();
checkListCommands(rsp, "build-report");
checkListCommands(rsp, "config-backend-pull");
checkListCommands(rsp, "config-get");
+ checkListCommands(rsp, "config-hash-get");
checkListCommands(rsp, "config-reload");
checkListCommands(rsp, "config-set");
checkListCommands(rsp, "config-test");