Commit 5f9e7c54 authored by Thomas Markwalder's avatar Thomas Markwalder

[master] Merge branch 'master' of gitlab.isc.org:isc-projects/kea

    Fixed ChangeLog
parents 880ca111 109b9dd2
1627. [func] tmark
1629. [func] tmark
High Availaiblity logging now also emits server and partner system
times when reporting clock skew issues. Prior to this it reported
only the skew between the two servers.
(Gitlab #174,!414, git 9715ddecb0143d997a57edea564f5c180a7f8577)
1628. [bug] fdupont
Improved the error message from MySQL CB -set commands when
a specified server does not exist.
(Gitlab #732,!429, git 82f34e60363eec72a117939a5526bdb1ececb53c)
1627. [func] fdupont
Added new command server-tag-get to DHCPv4 and DHCPv6 servers.
(Gitlab #470,!386, git 3cb43f112662ba3f9d2fc7152dfa1639401b1491)
1626. [bug] marcin
Automatically delete embedded options as a result of deleting
a subnet, pool or shared network from the MySQL Configuration
......
......@@ -155,7 +155,8 @@ EXTRA_DIST += api/remote-subnet6-list.json
EXTRA_DIST += api/remote-subnet6-set.json
EXTRA_DIST += api/reservation-add.json api/reservation-del.json
EXTRA_DIST += api/reservation-get.json api/reservation-get-all.json
EXTRA_DIST += api/reservation-get-page.json api/shutdown.json
EXTRA_DIST += api/reservation-get-page.json
EXTRA_DIST += api/server-tag-get.json api/shutdown.json
EXTRA_DIST += api/remote-server4-del.json
EXTRA_DIST += api/remote-server4-get.json
EXTRA_DIST += api/remote-server4-get-all.json
......
{
"name": "server-tag-get",
"brief": "The server-tag-get command returns the server tag.",
"description": "See <xref linkend=\"command-server-tag-get\"/>",
"support": [ "kea-dhcp4", "kea-dhcp6" ],
"avail": "1.6.0",
"cmd-syntax": "{
\"command\": \"server-tag-get\"
}"
}
......@@ -9,7 +9,7 @@
<!-- autogenerated using cmd_docgen. Do not edit by hand! -->
<appendix xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="api">
<title>API Reference</title>
<para>Kea currently supports 130 commands:
<para>Kea currently supports 131 commands:
<command><link linkend="ref-build-report">build-report</link></command>
, <command><link linkend="ref-cache-clear">cache-clear</link></command>
, <command><link linkend="ref-cache-get">cache-get</link></command>
......@@ -120,6 +120,7 @@
, <command><link linkend="ref-reservation-get">reservation-get</link></command>
, <command><link linkend="ref-reservation-get-all">reservation-get-all</link></command>
, <command><link linkend="ref-reservation-get-page">reservation-get-page</link></command>
, <command><link linkend="ref-server-tag-get">server-tag-get</link></command>
, <command><link linkend="ref-shutdown">shutdown</link></command>
, <command><link linkend="ref-stat-lease4-get">stat-lease4-get</link></command>
, <command><link linkend="ref-stat-lease6-get">stat-lease6-get</link></command>
......@@ -232,6 +233,7 @@
, <command><link linkend="ref-reservation-get">reservation-get</link></command>
, <command><link linkend="ref-reservation-get-all">reservation-get-all</link></command>
, <command><link linkend="ref-reservation-get-page">reservation-get-page</link></command>
, <command><link linkend="ref-server-tag-get">server-tag-get</link></command>
, <command><link linkend="ref-shutdown">shutdown</link></command>
, <command><link linkend="ref-stat-lease4-get">stat-lease4-get</link></command>
, <command><link linkend="ref-statistic-get">statistic-get</link></command>
......@@ -319,6 +321,7 @@
, <command><link linkend="ref-reservation-get">reservation-get</link></command>
, <command><link linkend="ref-reservation-get-all">reservation-get-all</link></command>
, <command><link linkend="ref-reservation-get-page">reservation-get-page</link></command>
, <command><link linkend="ref-server-tag-get">server-tag-get</link></command>
, <command><link linkend="ref-shutdown">shutdown</link></command>
, <command><link linkend="ref-stat-lease6-get">stat-lease6-get</link></command>
, <command><link linkend="ref-statistic-get">statistic-get</link></command>
......@@ -5427,6 +5430,41 @@ Result is an integer representation of the status. Currently supported statuses
</section>
<!-- end of reservation-get-page -->
<!-- start of server-tag-get -->
<section xml:id="reference-server-tag-get">
<title>server-tag-get reference</title>
<para xml:id="ref-server-tag-get"><command>server-tag-get</command> - The server-tag-get command returns the server tag.</para>
<para>Supported by: <command><link linkend="commands-kea-dhcp4">kea-dhcp4</link></command>, <command><link linkend="commands-kea-dhcp6">kea-dhcp6</link></command></para>
<para>Availability: 1.6.0 (built-in)</para>
<para>Description and examples: See <xref linkend="command-server-tag-get"/></para>
<para>Command syntax:
<screen>{
"command": "server-tag-get"
}</screen>
</para>
<para>Response syntax:
<screen>{
"result": &lt;integer&gt;,
"text": &lt;string&gt;
}
</screen>
Result is an integer representation of the status. Currently supported statuses are:
<itemizedlist>
<listitem><para>0 - success</para></listitem>
<listitem><para>1 - error</para></listitem>
<listitem><para>2 - unsupported</para></listitem>
<listitem><para>3 - empty (command was completed successfully, but no data was affected or returned)</para></listitem>
</itemizedlist>
</para>
</section>
<!-- end of server-tag-get -->
<!-- start of shutdown -->
<section xml:id="reference-shutdown">
<title>shutdown reference</title>
......
......@@ -590,6 +590,19 @@ $ curl -X POST -H "Content-Type: application/json" -d '{ "command": "config-get"
</screen>
</section> <!-- end of command-version-get -->
<section xml:id="command-server-tag-get">
<title>server-tag-get</title>
<para>
The <emphasis>server-tag-get</emphasis> command returns
the server tag. This command does not take any parameters.
</para>
<screen>
{
"command": "server-tag-get"
}
</screen>
</section> <!-- end of command-server-tag-get -->
</section> <!-- end of commands supported by both servers -->
<section>
......
......@@ -5445,6 +5445,7 @@ autogenerated IDs are not stable across configuration changes.</para>
<listitem>dhcp-enable</listitem>
<listitem>leases-reclaim</listitem>
<listitem>list-commands</listitem>
<listitem>server-tag-get</listitem>
<listitem>shutdown</listitem>
<listitem>version-get</listitem>
</itemizedlist>
......
......@@ -5480,6 +5480,7 @@ autogenerated IDs are not stable across configuration changes.
<listitem>dhcp-enable</listitem>
<listitem>leases-reclaim</listitem>
<listitem>list-commands</listitem>
<listitem>server-tag-get</listitem>
<listitem>shutdown</listitem>
<listitem>version-get</listitem>
</itemizedlist>
......
......@@ -538,6 +538,17 @@ ControlledDhcpv4Srv::commandLeasesReclaimHandler(const string&,
return (answer);
}
ConstElementPtr
ControlledDhcpv4Srv::commandServerTagGetHandler(const std::string&,
ConstElementPtr) {
const std::string& tag =
CfgMgr::instance().getCurrentCfg()->getServerTag();
ElementPtr response = Element::createMap();
response->set("server-tag", Element::create(tag));
return (createAnswer(CONTROL_RESULT_SUCCESS, response));
}
ConstElementPtr
ControlledDhcpv4Srv::processCommand(const string& command,
ConstElementPtr args) {
......@@ -592,6 +603,9 @@ ControlledDhcpv4Srv::processCommand(const string& command,
} else if (command == "config-write") {
return (srv->commandConfigWriteHandler(command, args));
} else if (command == "server-tag-get") {
return (srv->commandServerTagGetHandler(command, args));
}
ConstElementPtr answer = isc::config::createAnswer(1,
"Unrecognized command:" + command);
......@@ -822,6 +836,9 @@ ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t server_port /*= DHCP4_SERVER_P
CommandMgr::instance().registerCommand("leases-reclaim",
boost::bind(&ControlledDhcpv4Srv::commandLeasesReclaimHandler, this, _1, _2));
CommandMgr::instance().registerCommand("server-tag-get",
boost::bind(&ControlledDhcpv4Srv::commandServerTagGetHandler, this, _1, _2));
CommandMgr::instance().registerCommand("shutdown",
boost::bind(&ControlledDhcpv4Srv::commandShutdownHandler, this, _1, _2));
......@@ -878,6 +895,7 @@ ControlledDhcpv4Srv::~ControlledDhcpv4Srv() {
CommandMgr::instance().deregisterCommand("config-set");
CommandMgr::instance().deregisterCommand("dhcp-disable");
CommandMgr::instance().deregisterCommand("dhcp-enable");
CommandMgr::instance().deregisterCommand("server-tag-get");
CommandMgr::instance().deregisterCommand("shutdown");
CommandMgr::instance().deregisterCommand("statistic-get");
CommandMgr::instance().deregisterCommand("statistic-get-all");
......
......@@ -292,6 +292,18 @@ private:
commandLeasesReclaimHandler(const std::string& command,
isc::data::ConstElementPtr args);
/// @brief handler for server-tag-get command
///
/// This method handles the server-tag-get command, which retrieves
/// the current server tag and returns it in response.
///
/// @param command (ignored)
/// @param args (ignored)
/// @return current configuration wrapped in a response
isc::data::ConstElementPtr
commandServerTagGetHandler(const std::string& command,
isc::data::ConstElementPtr args);
/// @brief Reclaims expired IPv4 leases and reschedules timer.
///
/// This is a wrapper method for @c AllocEngine::reclaimExpiredLeases4.
......
......@@ -483,6 +483,7 @@ TEST_F(CtrlChannelDhcpv4SrvTest, commandsRegistration) {
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("\"server-tag-get\"") != 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);
......@@ -604,6 +605,26 @@ TEST_F(CtrlChannelDhcpv4SrvTest, getversion) {
EXPECT_TRUE(response.find("GTEST_VERSION") != string::npos);
}
// This test verifies that the DHCP server handles server-tag-get command
TEST_F(CtrlChannelDhcpv4SrvTest, serverTagGet) {
createUnixChannelServer();
std::string response;
std::string expected;
// Send the server-tag-get command
sendUnixCommand("{ \"command\": \"server-tag-get\" }", response);
expected = "{ \"arguments\": { \"server-tag\": \"\" }, \"result\": 0 }";
EXPECT_EQ(expected, response);
// Set a value to the server tag
CfgMgr::instance().getCurrentCfg()->setServerTag("foobar");
// Retry...
sendUnixCommand("{ \"command\": \"server-tag-get\" }", response);
expected = "{ \"arguments\": { \"server-tag\": \"foobar\" }, \"result\": 0 }";
}
// 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
......@@ -854,6 +875,7 @@ TEST_F(CtrlChannelDhcpv4SrvTest, listCommands) {
checkListCommands(rsp, "list-commands");
checkListCommands(rsp, "leases-reclaim");
checkListCommands(rsp, "libreload");
checkListCommands(rsp, "server-tag-get");
checkListCommands(rsp, "shutdown");
checkListCommands(rsp, "statistic-get");
checkListCommands(rsp, "statistic-get-all");
......
......@@ -539,6 +539,17 @@ ControlledDhcpv6Srv::commandLeasesReclaimHandler(const string&,
return (answer);
}
ConstElementPtr
ControlledDhcpv6Srv::commandServerTagGetHandler(const std::string&,
ConstElementPtr) {
const std::string& tag =
CfgMgr::instance().getCurrentCfg()->getServerTag();
ElementPtr response = Element::createMap();
response->set("server-tag", Element::create(tag));
return (createAnswer(CONTROL_RESULT_SUCCESS, response));
}
isc::data::ConstElementPtr
ControlledDhcpv6Srv::processCommand(const std::string& command,
isc::data::ConstElementPtr args) {
......@@ -593,6 +604,9 @@ ControlledDhcpv6Srv::processCommand(const std::string& command,
} else if (command == "config-write") {
return (srv->commandConfigWriteHandler(command, args));
} else if (command == "server-tag-get") {
return (srv->commandServerTagGetHandler(command, args));
}
return (isc::config::createAnswer(1, "Unrecognized command:"
......@@ -840,6 +854,9 @@ ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t server_port,
CommandMgr::instance().registerCommand("leases-reclaim",
boost::bind(&ControlledDhcpv6Srv::commandLeasesReclaimHandler, this, _1, _2));
CommandMgr::instance().registerCommand("server-tag-get",
boost::bind(&ControlledDhcpv6Srv::commandServerTagGetHandler, this, _1, _2));
CommandMgr::instance().registerCommand("libreload",
boost::bind(&ControlledDhcpv6Srv::commandLibReloadHandler, this, _1, _2));
......@@ -901,6 +918,7 @@ ControlledDhcpv6Srv::~ControlledDhcpv6Srv() {
CommandMgr::instance().deregisterCommand("dhcp-enable");
CommandMgr::instance().deregisterCommand("leases-reclaim");
CommandMgr::instance().deregisterCommand("libreload");
CommandMgr::instance().deregisterCommand("server-tag-get");
CommandMgr::instance().deregisterCommand("shutdown");
CommandMgr::instance().deregisterCommand("statistic-get");
CommandMgr::instance().deregisterCommand("statistic-get-all");
......
......@@ -291,6 +291,18 @@ private:
commandLeasesReclaimHandler(const std::string& command,
isc::data::ConstElementPtr args);
/// @brief handler for server-tag-get command
///
/// This method handles the server-tag-get command, which retrieves
/// the current server tag and returns it in response.
///
/// @param command (ignored)
/// @param args (ignored)
/// @return current configuration wrapped in a response
isc::data::ConstElementPtr
commandServerTagGetHandler(const std::string& command,
isc::data::ConstElementPtr args);
/// @brief Reclaims expired IPv6 leases and reschedules timer.
///
/// This is a wrapper method for @c AllocEngine::reclaimExpiredLeases6.
......
......@@ -790,6 +790,7 @@ TEST_F(CtrlDhcpv6SrvTest, commandsRegistration) {
EXPECT_TRUE(command_list.find("\"leases-reclaim\"") != string::npos);
EXPECT_TRUE(command_list.find("\"libreload\"") != string::npos);
EXPECT_TRUE(command_list.find("\"config-set\"") != string::npos);
EXPECT_TRUE(command_list.find("\"server-tag-get\"") != 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);
......@@ -853,6 +854,26 @@ TEST_F(CtrlChannelDhcpv6SrvTest, getversion) {
EXPECT_TRUE(response.find("GTEST_VERSION") != string::npos);
}
// This test verifies that the DHCP server handles server-tag-get command
TEST_F(CtrlChannelDhcpv6SrvTest, serverTagGet) {
createUnixChannelServer();
std::string response;
std::string expected;
// Send the server-tag-get command
sendUnixCommand("{ \"command\": \"server-tag-get\" }", response);
expected = "{ \"arguments\": { \"server-tag\": \"\" }, \"result\": 0 }";
EXPECT_EQ(expected, response);
// Set a value to the server tag
CfgMgr::instance().getCurrentCfg()->setServerTag("foobar");
// Retry...
sendUnixCommand("{ \"command\": \"server-tag-get\" }", response);
expected = "{ \"arguments\": { \"server-tag\": \"foobar\" }, \"result\": 0 }";
}
// This test verifies that the DHCP server immediately reclaims expired
// leases on leases-reclaim command
TEST_F(CtrlChannelDhcpv6SrvTest, controlLeasesReclaim) {
......@@ -1025,6 +1046,7 @@ TEST_F(CtrlChannelDhcpv6SrvTest, commandsList) {
checkListCommands(rsp, "leases-reclaim");
checkListCommands(rsp, "libreload");
checkListCommands(rsp, "version-get");
checkListCommands(rsp, "server-tag-get");
checkListCommands(rsp, "shutdown");
checkListCommands(rsp, "statistic-get");
checkListCommands(rsp, "statistic-get-all");
......
......@@ -906,7 +906,14 @@ MySqlConfigBackendImpl::attachElementToServers(const int index,
MySqlBindingCollection in_server_bindings = { first_binding, in_bindings };
for (auto tag : server_selector.getTags()) {
in_server_bindings.push_back(MySqlBinding::createString(tag.get()));
conn_.insertQuery(index, in_server_bindings);
// Handles the case where the server does not exists.
try {
conn_.insertQuery(index, in_server_bindings);
} catch (const NullKeyError&) {
// The message should give the tag value.
isc_throw(NullKeyError,
"server '" << tag.get() << "' does not exist");
}
in_server_bindings.pop_back();
}
}
......
......@@ -765,7 +765,7 @@ TEST_F(MySqlConfigBackendDHCPv4Test, globalParameters4WithServerTags) {
// This should fail because the server must be inserted first.
EXPECT_THROW(cbptr_->createUpdateGlobalParameter4(ServerSelector::ONE("server1"),
global_parameter1),
DbOperationError);
NullKeyError);
// Create two servers.
EXPECT_NO_THROW(cbptr_->createUpdateServer4(test_servers_[1]));
......@@ -1058,6 +1058,25 @@ TEST_F(MySqlConfigBackendDHCPv4Test, getModifiedGlobalParameters4) {
EXPECT_EQ(1, parameters.size());
}
// Test that the NullKeyError message is correctly updated.
TEST_F(MySqlConfigBackendDHCPv4Test, nullKeyError) {
// Create a global parameter (it should work with any object type).
StampedValuePtr global_parameter = StampedValue::create("global", "value");
// Try to insert it and associate with non-existing server.
std::string msg;
try {
cbptr_->createUpdateGlobalParameter4(ServerSelector::ONE("server1"),
global_parameter);
msg = "got no exception";
} catch (const NullKeyError& ex) {
msg = ex.what();
} catch (const std::exception&) {
msg = "got another exception";
}
EXPECT_EQ("server 'server1' does not exist", msg);
}
// Test that ceateUpdateSubnet4 throws appropriate exceptions for various
// server selectors.
TEST_F(MySqlConfigBackendDHCPv4Test, createUpdateSubnet4Selectors) {
......@@ -1102,7 +1121,7 @@ TEST_F(MySqlConfigBackendDHCPv4Test, getSubnet4) {
// An attempt to add a subnet to a non-existing server (server1) should fail.
EXPECT_THROW(cbptr_->createUpdateSubnet4(ServerSelector::MULTIPLE({ "server1", "server2" }),
subnet2),
DbOperationError);
NullKeyError);
// The subnet shouldn't have been added, even though one of the servers exists.
Subnet4Ptr returned_subnet;
......@@ -2128,7 +2147,7 @@ TEST_F(MySqlConfigBackendDHCPv4Test, createUpdateSharedNetwork4) {
// An attempto insert the shared network for non-existing server should fail.
EXPECT_THROW(cbptr_->createUpdateSharedNetwork4(ServerSelector::ONE("server1"),
shared_network),
DbOperationError);
NullKeyError);
// Insert the server1 into the database.
EXPECT_NO_THROW(cbptr_->createUpdateServer4(test_servers_[0]));
......@@ -2880,7 +2899,7 @@ TEST_F(MySqlConfigBackendDHCPv4Test, optionDefs4WithServerTags) {
// fail.
EXPECT_THROW(cbptr_->createUpdateOptionDef4(ServerSelector::ONE("server1"),
option1),
DbOperationError);
NullKeyError);
// Create two servers.
EXPECT_NO_THROW(cbptr_->createUpdateServer4(test_servers_[1]));
......@@ -3272,7 +3291,7 @@ TEST_F(MySqlConfigBackendDHCPv4Test, globalOptions4WithServerTags) {
EXPECT_THROW(cbptr_->createUpdateOption4(ServerSelector::ONE("server1"),
opt_boot_file_name1),
DbOperationError);
NullKeyError);
// Create two servers.
EXPECT_NO_THROW(cbptr_->createUpdateServer4(test_servers_[1]));
......
......@@ -796,6 +796,12 @@ TEST_F(MySqlConfigBackendDHCPv6Test, globalParameters6WithServerTags) {
StampedValuePtr global_parameter2 = StampedValue::create("global", "value2");
StampedValuePtr global_parameter3 = StampedValue::create("global", "value3");
// Try to insert one of them and associate with non-existing server.
// This should fail because the server must be inserted first.
EXPECT_THROW(cbptr_->createUpdateGlobalParameter6(ServerSelector::ONE("server1"),
global_parameter1),
NullKeyError);
// Create two servers.
EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[1]));
{
......@@ -1087,6 +1093,25 @@ TEST_F(MySqlConfigBackendDHCPv6Test, getModifiedGlobalParameters6) {
EXPECT_EQ(1, parameters.size());
}
// Test that the NullKeyError message is correctly updated.
TEST_F(MySqlConfigBackendDHCPv6Test, nullKeyError) {
// Create a global parameter (it should work with any object type).
StampedValuePtr global_parameter = StampedValue::create("global", "value");
// Try to insert it and associate with non-existing server.
std::string msg;
try {
cbptr_->createUpdateGlobalParameter6(ServerSelector::ONE("server1"),
global_parameter);
msg = "got no exception";
} catch (const NullKeyError& ex) {
msg = ex.what();
} catch (const std::exception&) {
msg = "got another exception";
}
EXPECT_EQ("server 'server1' does not exist", msg);
}
// Test that ceateUpdateSubnet6 throws appropriate exceptions for various
// server selectors.
TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateSubnet6Selectors) {
......@@ -1131,7 +1156,7 @@ TEST_F(MySqlConfigBackendDHCPv6Test, getSubnet6) {
// An attempt to add a subnet to a non-existing server (server1) should fail.
EXPECT_THROW(cbptr_->createUpdateSubnet6(ServerSelector::MULTIPLE({ "server1", "server2" }),
subnet2),
DbOperationError);
NullKeyError);
// The subnet shouldn't have been added, even though one of the servers exists.
Subnet6Ptr returned_subnet;
......@@ -2146,7 +2171,7 @@ TEST_F(MySqlConfigBackendDHCPv6Test, createUpdateSharedNetwork6) {
// An attempto insert the shared network for non-existing server should fail.
EXPECT_THROW(cbptr_->createUpdateSharedNetwork6(ServerSelector::ONE("server1"),
shared_network),
DbOperationError);
NullKeyError);
// Insert the server1 into the database.
EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[0]));
......@@ -2900,7 +2925,7 @@ TEST_F(MySqlConfigBackendDHCPv6Test, optionDefs6WithServerTags) {
// fail.
EXPECT_THROW(cbptr_->createUpdateOptionDef6(ServerSelector::ONE("server1"),
option1),
DbOperationError);
NullKeyError);
// Create two servers.
EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[1]));
......@@ -3296,7 +3321,7 @@ TEST_F(MySqlConfigBackendDHCPv6Test, globalOptions6WithServerTags) {
EXPECT_THROW(cbptr_->createUpdateOption6(ServerSelector::ONE("server1"),
opt_timezone1),
DbOperationError);
NullKeyError);
// Create two servers.
EXPECT_NO_THROW(cbptr_->createUpdateServer6(test_servers_[1]));
......
// Copyright (C) 2015-2018 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2015-2019 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
......@@ -45,6 +45,13 @@ public:
isc::Exception(file, line, what) {}
};
/// @brief Key is NULL but was specified NOT NULL
class NullKeyError : public Exception {
public:
NullKeyError(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) {}
};
/// @brief Attempt to modify data in read-only database.
class ReadOnlyDb : public Exception {
public:
......
......@@ -443,6 +443,10 @@ public:
if (mysql_errno(mysql_) == ER_DUP_ENTRY) {
isc_throw(DuplicateEntry, "Database duplicate entry error");
}
// Failure: check for the special case of WHERE returning NULL.
if (mysql_errno(mysql_) == ER_BAD_NULL_ERROR) {
isc_throw(NullKeyError, "Database bad NULL error");
}
checkError(status, index, "unable to execute");
}
}
......
......@@ -627,6 +627,15 @@ DControllerBase::configSetHandler(const std::string&, ConstElementPtr args) {
}
}
ConstElementPtr
DControllerBase::serverTagGetHandler(const std::string&, ConstElementPtr) {
const std::string& tag = process_->getCfgMgr()->getContext()->getServerTag();
ElementPtr response = Element::createMap();
response->set("server-tag", Element::create(tag));
return (createAnswer(COMMAND_SUCCESS, response));
}
ConstElementPtr
DControllerBase::versionGetHandler(const std::string&, ConstElementPtr) {
ConstElementPtr answer;
......
......@@ -307,7 +307,7 @@ public:
/// @brief handler for config-set command
///
/// This method handles the config-set command, which checks
/// This method handles the config-set command, which loads
/// configuration specified in args parameter.
///
/// @param command (ignored)
......@@ -328,6 +328,18 @@ public:
shutdownHandler(const std::string& command,
isc::data::ConstElementPtr args);
/// @brief handler for server-tag-get command
///
/// This method handles the server-tag-get command, which retrieves
/// the current server tag and returns it in response.
///
/// @param command (ignored)
/// @param args (ignored)
/// @return current configuration wrapped in a response
isc::data::ConstElementPtr
serverTagGetHandler(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
......