--- /dev/null
+[func] fdupont
+ Made reconfig commands which triggered a fatal error not to
+ return a success answer when the server is shutting down.
+ (Gitlab #4507)
namespace isc {
namespace dhcp {
-ControlledDhcpv4Srv* ControlledDhcpv4Srv::server_ = NULL;
+ControlledDhcpv4Srv* ControlledDhcpv4Srv::server_ = 0;
void
ControlledDhcpv4Srv::init(const std::string& file_name) {
return (result);
}
+bool
+ControlledDhcpv4Srv::getShutdown() const {
+ return (Dhcpv4Srv::shutdown_);
+}
+
ConstElementPtr
ControlledDhcpv4Srv::commandShutdownHandler(const string&, ConstElementPtr args) {
if (!ControlledDhcpv4Srv::getInstance()) {
// the logging first in case there's a configuration failure.
int rcode = 0;
isc::config::parseAnswer(rcode, result);
+ if (getShutdown() && (rcode == CONTROL_RESULT_SUCCESS)) {
+ // Do not return success when a fatal error was triggered.
+ rcode = CONTROL_RESULT_FATAL_ERROR;
+ message = "Reconfiguration triggered a fatal error: shutting down.";
+ result = isc::config::createAnswer(rcode, message);
+ }
if (rcode == CONTROL_RESULT_SUCCESS) {
CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
ostringstream msg;
if (!error) {
+ if (getShutdown()) {
+ return (isc::config::createAnswer(CONTROL_RESULT_FATAL_ERROR, "Interface configuration uodate triggered a fatal error: shutting down."));
+ }
return (isc::config::createAnswer(CONTROL_RESULT_SUCCESS, "Interface configuration successfully updated."));
} else {
msg << "Updating used interfaces failed: " << message;
/// @param exit_value integer value to the process should exit with.
virtual void shutdownServer(int exit_value);
+ /// @brief Return the server shutdown flag value.
+ bool getShutdown() const;
+
/// @brief Configuration processor
///
/// This is a method for handling incoming configuration updates.
EXPECT_EQ(response, expected);
}
+// Tests if interface-add can trigger a fatal failure.
+TEST_F(CtrlChannelDhcpv4SrvTest, interfaceAddFatal) {
+ interfaces_ = "";
+ IfacePtr eth0 = IfaceMgrTestConfig::createIface("eth0", ETH0_INDEX,
+ "11:22:33:44:55:66");
+ auto detectIfaces = [&](bool update_only) {
+ if (!update_only) {
+ // No IPv4 address: will trigger an error.
+ eth0->addAddress(IOAddress("fe80::3a60:77ff:fed5:cdef"));
+ eth0->addAddress(IOAddress("2001:db8:1::1"));
+ IfaceMgr::instance().addInterface(eth0);
+ }
+ return (false);
+ };
+ IfaceMgr::instance().setDetectCallback(detectIfaces);
+ IfaceMgr::instance().clearIfaces();
+ IfaceMgr::instance().closeSockets();
+ IfaceMgr::instance().detectIfaces();
+ createUnixChannelServer();
+ PktFilterPtr filter(new PktFilterTestStub());
+ IfaceMgr::instance().setPacketFilter(filter);
+ SKIP_IF(skipped_);
+ // Override the on fail callback to unconditionally make the error fatal.
+ CfgIface::open_sockets_failed_callback_ =
+ [](ReconnectCtlPtr) {
+ ControlledDhcpv4Srv::getInstance()->shutdownServer(EXIT_FAILURE);
+ };
+ std::string response;
+
+ std::string command = "{ \"command\": \"interface-add\", \"arguments\": { \"interfaces\": [ \"eth0\" ] } }";
+
+ sendUnixCommand(command, response);
+ EXPECT_EQ(response, "{ \"result\": 5, \"text\": \"Interface configuration uodate triggered a fatal error: shutting down.\" }");
+}
+
// This test verifies that disable DHCP service command performs sanity check on
// parameters.
TEST_F(CtrlChannelDhcpv4SrvTest, dhcpDisableBadParam) {
namespace isc {
namespace dhcp {
-ControlledDhcpv6Srv* ControlledDhcpv6Srv::server_ = NULL;
+ControlledDhcpv6Srv* ControlledDhcpv6Srv::server_ = 0;
void
ControlledDhcpv6Srv::init(const std::string& file_name) {
return (result);
}
+bool
+ControlledDhcpv6Srv::getShutdown() const {
+ return (Dhcpv6Srv::shutdown_);
+}
+
ConstElementPtr
ControlledDhcpv6Srv::commandShutdownHandler(const string&, ConstElementPtr args) {
if (!ControlledDhcpv6Srv::getInstance()) {
// the logging first in case there's a configuration failure.
int rcode = 0;
isc::config::parseAnswer(rcode, result);
+ if (getShutdown() && (rcode == CONTROL_RESULT_SUCCESS)) {
+ // Do not return success when a fatal error was triggered.
+ rcode = CONTROL_RESULT_FATAL_ERROR;
+ message = "Reconfiguration triggered a fatal error: shutting down.";
+ result = isc::config::createAnswer(rcode, message);
+ }
if (rcode == CONTROL_RESULT_SUCCESS) {
CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
ostringstream msg;
if (!error) {
+ if (getShutdown()) {
+ return (isc::config::createAnswer(CONTROL_RESULT_FATAL_ERROR, "Interface configuration uodate triggered a fatal error: shutting down."));
+ }
return (isc::config::createAnswer(CONTROL_RESULT_SUCCESS, "Interface configuration successfully updated."));
} else {
msg << "Updating used interfaces failed: " << message;
/// @param exit_value integer value to the process should exit with.
virtual void shutdownServer(int exit_value);
+ /// @brief Return the server shutdown flag value.
+ bool getShutdown() const;
+
/// @brief Configuration processor
///
/// This is a method for handling incoming configuration updates.
EXPECT_EQ(response, expected);
}
+// Tests if interface-add can trigger a fatal failure.
+TEST_F(CtrlChannelDhcpv6SrvTest, interfaceAddFatal) {
+ interfaces_ = "";
+ IfacePtr eth0 = IfaceMgrTestConfig::createIface("eth0", ETH0_INDEX,
+ "11:22:33:44:55:66");
+ auto detectIfaces = [&](bool update_only) {
+ if (!update_only) {
+ eth0->addAddress(IOAddress("10.0.0.1"));
+ eth0->addAddress(IOAddress("fe80::3a60:77ff:fed5:cdef"));
+ eth0->addAddress(IOAddress("2001:db8:1::1"));
+ IfaceMgr::instance().addInterface(eth0);
+ } else {
+ // Trigger an error on interface-add.
+ eth0->flag_running_ = false;
+ }
+ return (false);
+ };
+ IfaceMgr::instance().setDetectCallback(detectIfaces);
+ IfaceMgr::instance().clearIfaces();
+ IfaceMgr::instance().closeSockets();
+ IfaceMgr::instance().detectIfaces();
+ createUnixChannelServer();
+ PktFilter6Ptr filter(new PktFilter6TestStub());
+ IfaceMgr::instance().setPacketFilter(filter);
+ SKIP_IF(skipped_);
+ // Override the on fail callback to unconditionally make the error fatal.
+ CfgIface::open_sockets_failed_callback_ =
+ [](ReconnectCtlPtr) {
+ ControlledDhcpv6Srv::getInstance()->shutdownServer(EXIT_FAILURE);
+ };
+ std::string response;
+
+ std::string command = "{ \"command\": \"interface-add\", \"arguments\": { \"interfaces\": [ \"eth0\" ] } }";
+
+ sendUnixCommand(command, response);
+ EXPECT_EQ(response, "{ \"result\": 5, \"text\": \"Interface configuration uodate triggered a fatal error: shutting down.\" }");
+}
+
// This test verifies that disable DHCP service command performs sanity check on
// parameters.
TEST_F(CtrlChannelDhcpv6SrvTest, dhcpDisableBadParam) {