2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-22 18:08:16 +00:00

[#3315] use internal IOService for hooks

This commit is contained in:
Razvan Becheriu 2024-03-27 23:38:26 +02:00
parent 4f935d2b86
commit 4398fb6c4a
58 changed files with 1079 additions and 343 deletions

View File

@ -89,6 +89,7 @@ CtrlAgentProcess::run() {
size_t size_t
CtrlAgentProcess::runIO() { CtrlAgentProcess::runIO() {
getIOService()->pollExternalIOServices();
size_t cnt = getIOService()->poll(); size_t cnt = getIOService()->poll();
if (!cnt) { if (!cnt) {
cnt = getIOService()->runOne(); cnt = getIOService()->runOne();
@ -192,6 +193,17 @@ CtrlAgentProcess::configure(isc::data::ConstElementPtr config_set,
int rcode = 0; int rcode = 0;
config::parseAnswer(rcode, answer); config::parseAnswer(rcode, answer);
/// Let postponed hook initializations to run.
try {
getIOService()->pollExternalIOServices();
} catch (const std::exception& ex) {
std::ostringstream err;
err << "Error initializing hooks: "
<< ex.what();
return (isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str()));
}
return (answer); return (answer);
} }

View File

@ -55,12 +55,15 @@ to the end of this list.
- @b Description: this callout is executed when the server has completed - @b Description: this callout is executed when the server has completed
its (re)configuration. The server provides received and parsed configuration its (re)configuration. The server provides received and parsed configuration
structures to the hook library. It also provides a pointer to the IOService structures to the hook library.
object which is used by the server to run asynchronous operations. The hooks If the library uses any IO operations, it should create a local IOService
libraries can use this IOService object to schedule asynchronous tasks which object and register it to the main IOService which is also provided. This way
are triggered by the Kea DHCP DDNS's main loop. The hook library should hold the local IOService is used by the server to run asynchronous operations. The
the provided pointer until the library is unloaded. The D2CfgContext hooks library can use the local IOService object to schedule asynchronous
object provides access to the D2 running configuration. tasks which are triggered by the D2 server's main loop. The hook library
should hold the provided pointer until the library is unloaded at which stage
it must unregister the local IOService.
The D2CfgContext object provides access to the D2 running configuration.
- <b>Next step status</b>: If any callout sets the status to DROP, the server - <b>Next step status</b>: If any callout sets the status to DROP, the server
considers the configuration is incorrect and rejects it using the error considers the configuration is incorrect and rejects it using the error

View File

@ -129,6 +129,7 @@ D2Process::run() {
size_t size_t
D2Process::runIO() { D2Process::runIO() {
getIOService()->pollExternalIOServices();
// We want to block until at least one handler is called. We'll use // We want to block until at least one handler is called. We'll use
// boost::asio::io_service directly for two reasons. First off // boost::asio::io_service directly for two reasons. First off
// asiolink::IOService::runOne is a void and boost::asio::io_service::stopped // asiolink::IOService::runOne is a void and boost::asio::io_service::stopped
@ -148,7 +149,6 @@ D2Process::runIO() {
// service is stopped it will return immediately with a cnt of zero. // service is stopped it will return immediately with a cnt of zero.
cnt = getIOService()->runOne(); cnt = getIOService()->runOne();
} }
return (cnt); return (cnt);
} }
@ -301,6 +301,16 @@ D2Process::configure(isc::data::ConstElementPtr config_set, bool check_only) {
} }
} }
/// Let postponed hook initializations to run.
try {
getIOService()->pollExternalIOServices();
} catch (const std::exception& ex) {
std::ostringstream err;
err << "Error initializing hooks: "
<< ex.what();
return (isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str()));
}
// If we are here, configuration was valid, at least it parsed correctly // If we are here, configuration was valid, at least it parsed correctly
// and therefore contained no invalid values. // and therefore contained no invalid values.
// Return the success answer from above. // Return the success answer from above.

View File

@ -579,8 +579,7 @@ public:
// We don't use SimpleParser::setListDefaults() as this does // We don't use SimpleParser::setListDefaults() as this does
// not handle sub-lists or sub-maps // not handle sub-lists or sub-maps
for (auto const& domain : config->listValue()) { for (auto const& domain : config->listValue()) {
cnt += D2SimpleParser:: cnt += D2SimpleParser::setDdnsDomainDefaults(domain, D2SimpleParser::
setDdnsDomainDefaults(domain, D2SimpleParser::
DDNS_DOMAIN_DEFAULTS); DDNS_DOMAIN_DEFAULTS);
} }

View File

@ -241,6 +241,7 @@ ControlledDhcpv4Srv::commandLibReloadHandler(const string&, ConstElementPtr) {
HookLibsCollection loaded = HooksManager::getLibraryInfo(); HookLibsCollection loaded = HooksManager::getLibraryInfo();
HooksManager::prepareUnloadLibraries(); HooksManager::prepareUnloadLibraries();
static_cast<void>(HooksManager::unloadLibraries()); static_cast<void>(HooksManager::unloadLibraries());
getIOService()->clearExternalIOServices();
bool multi_threading_enabled = true; bool multi_threading_enabled = true;
uint32_t thread_count = 0; uint32_t thread_count = 0;
uint32_t queue_size = 0; uint32_t queue_size = 0;
@ -452,7 +453,7 @@ ControlledDhcpv4Srv::commandConfigSetHandler(const string&,
/// Let postponed hook initializations to run. /// Let postponed hook initializations to run.
try { try {
getIOService()->poll(); getIOService()->pollExternalIOServices();
} catch (const std::exception& ex) { } catch (const std::exception& ex) {
std::ostringstream err; std::ostringstream err;
err << "Error initializing hooks: " err << "Error initializing hooks: "

View File

@ -55,13 +55,17 @@ to the end of this list.
- @b Description: this callout is executed when the server has completed - @b Description: this callout is executed when the server has completed
its (re)configuration. The server provides received and parsed configuration its (re)configuration. The server provides received and parsed configuration
structures to the hook library. It also provides a pointer to the IOService structures to the hook library.
object which is used by the server to run asynchronous operations. The hooks If the library uses any IO operations, it should create a local IOService
libraries can use this IOService object to schedule asynchronous tasks which object and register it to the main IOService which is also provided. This way
are triggered by the DHCP server's main loop. The hook library should hold the the local IOService is used by the server to run asynchronous operations. The
provided pointer until the library is unloaded. The NetworkState object hooks library can use the local IOService object to schedule asynchronous
provides access to the DHCP service state of the server and allows for tasks which are triggered by the DHCP server's main loop. The hook library
enabling and disabling the DHCP service from the hooks libraries. should hold the provided pointer until the library is unloaded at which stage
it must unregister the local IOService.
The NetworkState object provides access to the DHCP service state of the
server and allows for enabling and disabling the DHCP service from the hooks
libraries.
- <b>Next step status</b>: If any callout sets the status to DROP, the server - <b>Next step status</b>: If any callout sets the status to DROP, the server
will interrupt the reconfiguration process. The hook callout is expected to will interrupt the reconfiguration process. The hook callout is expected to

View File

@ -706,6 +706,7 @@ Dhcpv4Srv::~Dhcpv4Srv() {
} }
LOG_ERROR(dhcp4_logger, DHCP4_SRV_UNLOAD_LIBRARIES_ERROR).arg(msg); LOG_ERROR(dhcp4_logger, DHCP4_SRV_UNLOAD_LIBRARIES_ERROR).arg(msg);
} }
getIOService()->clearExternalIOServices();
io_service_->stop(); io_service_->stop();
io_service_->restart(); io_service_->restart();
try { try {
@ -1132,6 +1133,7 @@ Dhcpv4Srv::run() {
#endif // ENABLE_AFL #endif // ENABLE_AFL
try { try {
runOne(); runOne();
getIOService()->pollExternalIOServices();
getIOService()->poll(); getIOService()->poll();
} catch (const std::exception& e) { } catch (const std::exception& e) {
// General catch-all exception that are not caught by more specific // General catch-all exception that are not caught by more specific

View File

@ -31,6 +31,9 @@ void start_service(void) {
isc_throw(isc::Unexpected, "start service failed"); isc_throw(isc::Unexpected, "start service failed");
}; };
IOServicePtr io_service;
IOServicePtr main_io_service;
} // end anonymous } // end anonymous
// Functions accessed by the hooks framework use C linkage to avoid the name // Functions accessed by the hooks framework use C linkage to avoid the name
@ -40,6 +43,7 @@ extern "C" {
int int
do_load_impl(LibraryHandle& handle) { do_load_impl(LibraryHandle& handle) {
io_service.reset(new IOService());
// Determine if this callout is configured to fail. // Determine if this callout is configured to fail.
isc::dhcp::SrvConfigPtr config; isc::dhcp::SrvConfigPtr config;
isc::data::ConstElementPtr const& parameters(handle.getParameters()); isc::data::ConstElementPtr const& parameters(handle.getParameters());
@ -51,9 +55,17 @@ do_load_impl(LibraryHandle& handle) {
return (0); return (0);
} }
int
do_unload_impl() {
if (main_io_service) {
main_io_service->unregisterExternalIOService(io_service);
}
return (0);
}
int (*do_load)(LibraryHandle& handle) = do_load_impl; int (*do_load)(LibraryHandle& handle) = do_load_impl;
int (*do_unload)(); int (*do_unload)() = do_unload_impl;
/// @brief Callout which appends library number and provided arguments to /// @brief Callout which appends library number and provided arguments to
/// the marker file for dhcp4_srv_configured callout. /// the marker file for dhcp4_srv_configured callout.
@ -79,13 +91,13 @@ dhcp4_srv_configured(CalloutHandle& handle) {
// Get the IO context to post start_service on it. // Get the IO context to post start_service on it.
std::string error(""); std::string error("");
IOServicePtr io_context;
try { try {
handle.getArgument("io_context", io_context); handle.getArgument("io_context", main_io_service);
if (!io_context) { if (!main_io_service) {
error = "null io_context"; error = "null io_context";
} }
io_context->post(start_service); main_io_service->registerExternalIOService(io_service);
io_service->post(start_service);
} catch (const std::exception& ex) { } catch (const std::exception& ex) {
error = "no io_context in arguments"; error = "no io_context in arguments";
} }

View File

@ -244,6 +244,7 @@ ControlledDhcpv6Srv::commandLibReloadHandler(const string&, ConstElementPtr) {
HookLibsCollection loaded = HooksManager::getLibraryInfo(); HookLibsCollection loaded = HooksManager::getLibraryInfo();
HooksManager::prepareUnloadLibraries(); HooksManager::prepareUnloadLibraries();
static_cast<void>(HooksManager::unloadLibraries()); static_cast<void>(HooksManager::unloadLibraries());
getIOService()->clearExternalIOServices();
bool multi_threading_enabled = true; bool multi_threading_enabled = true;
uint32_t thread_count = 0; uint32_t thread_count = 0;
uint32_t queue_size = 0; uint32_t queue_size = 0;
@ -454,7 +455,7 @@ ControlledDhcpv6Srv::commandConfigSetHandler(const string&,
/// Let postponed hook initializations to run. /// Let postponed hook initializations to run.
try { try {
getIOService()->poll(); getIOService()->pollExternalIOServices();
} catch (const std::exception& ex) { } catch (const std::exception& ex) {
std::ostringstream err; std::ostringstream err;
err << "Error initializing hooks: " err << "Error initializing hooks: "

View File

@ -55,14 +55,17 @@ to the end of this list.
- @b Description: this callout is executed when the server has completed - @b Description: this callout is executed when the server has completed
its (re)configuration. The server provides received and parsed configuration its (re)configuration. The server provides received and parsed configuration
structures to the hook library. It also provides a pointer to the IOService structures to the hook library.
object which is used by the server to run asynchronous operations. The hooks If the library uses any IO operations, it should create a local IOService
libraries can use this IOService object to schedule asynchronous tasks which object and register it to the main IOService which is also provided. This way
are triggered by the DHCP server's main loop. The hook library should hold the the local IOService is used by the server to run asynchronous operations. The
provided pointer until the library is unloaded. The NetworkState object hooks library can use the local IOService object to schedule asynchronous
provides access to the DHCP service state of the server and allows for tasks which are triggered by the DHCP server's main loop. The hook library
enabling and disabling the DHCP service from the hooks libraries. should hold the provided pointer until the library is unloaded at which stage
it must unregister the local IOService.
The NetworkState object provides access to the DHCP service state of the
server and allows for enabling and disabling the DHCP service from the hooks
libraries.
- <b>Next step status</b>: If any callout sets the status to DROP, the server - <b>Next step status</b>: If any callout sets the status to DROP, the server
will interrupt the reconfiguration process. The hook callout is expected to will interrupt the reconfiguration process. The hook callout is expected to

View File

@ -302,6 +302,7 @@ Dhcpv6Srv::~Dhcpv6Srv() {
} }
LOG_ERROR(dhcp6_logger, DHCP6_SRV_UNLOAD_LIBRARIES_ERROR).arg(msg); LOG_ERROR(dhcp6_logger, DHCP6_SRV_UNLOAD_LIBRARIES_ERROR).arg(msg);
} }
getIOService()->clearExternalIOServices();
io_service_->stop(); io_service_->stop();
io_service_->restart(); io_service_->restart();
try { try {
@ -613,6 +614,7 @@ Dhcpv6Srv::run() {
#endif // ENABLE_AFL #endif // ENABLE_AFL
try { try {
runOne(); runOne();
getIOService()->pollExternalIOServices();
getIOService()->poll(); getIOService()->poll();
} catch (const std::exception& e) { } catch (const std::exception& e) {
// General catch-all standard exceptions that are not caught by more // General catch-all standard exceptions that are not caught by more

View File

@ -31,6 +31,9 @@ void start_service(void) {
isc_throw(isc::Unexpected, "start service failed"); isc_throw(isc::Unexpected, "start service failed");
}; };
IOServicePtr io_service;
IOServicePtr main_io_service;
} // end anonymous } // end anonymous
// Functions accessed by the hooks framework use C linkage to avoid the name // Functions accessed by the hooks framework use C linkage to avoid the name
@ -40,6 +43,7 @@ extern "C" {
int int
do_load_impl(LibraryHandle& handle) { do_load_impl(LibraryHandle& handle) {
io_service.reset(new IOService());
// Determine if this callout is configured to fail. // Determine if this callout is configured to fail.
isc::dhcp::SrvConfigPtr config; isc::dhcp::SrvConfigPtr config;
isc::data::ConstElementPtr const& parameters(handle.getParameters()); isc::data::ConstElementPtr const& parameters(handle.getParameters());
@ -51,9 +55,17 @@ do_load_impl(LibraryHandle& handle) {
return (0); return (0);
} }
int
do_unload_impl() {
if (main_io_service) {
main_io_service->unregisterExternalIOService(io_service);
}
return (0);
}
int (*do_load)(LibraryHandle& handle) = do_load_impl; int (*do_load)(LibraryHandle& handle) = do_load_impl;
int (*do_unload)(); int (*do_unload)() = do_unload_impl;
/// @brief Callout which appends library number and provided arguments to /// @brief Callout which appends library number and provided arguments to
/// the marker file for dhcp6_srv_configured callout. /// the marker file for dhcp6_srv_configured callout.
@ -79,13 +91,13 @@ dhcp6_srv_configured(CalloutHandle& handle) {
// Get the IO context to post start_service on it. // Get the IO context to post start_service on it.
std::string error(""); std::string error("");
IOServicePtr io_context;
try { try {
handle.getArgument("io_context", io_context); handle.getArgument("io_context", main_io_service);
if (!io_context) { if (!main_io_service) {
error = "null io_context"; error = "null io_context";
} }
io_context->post(start_service); main_io_service->registerExternalIOService(io_service);
io_service->post(start_service);
} catch (const std::exception& ex) { } catch (const std::exception& ex) {
error = "no io_context in arguments"; error = "no io_context in arguments";
} }

View File

@ -65,6 +65,7 @@ NetconfProcess::run() {
size_t size_t
NetconfProcess::runIO() { NetconfProcess::runIO() {
getIOService()->pollExternalIOServices();
size_t cnt = getIOService()->poll(); size_t cnt = getIOService()->poll();
if (!cnt) { if (!cnt) {
cnt = getIOService()->runOne(); cnt = getIOService()->runOne();
@ -85,6 +86,17 @@ NetconfProcess::configure(isc::data::ConstElementPtr config_set,
getCfgMgr()->simpleParseConfig(config_set, check_only); getCfgMgr()->simpleParseConfig(config_set, check_only);
int rcode = 0; int rcode = 0;
config::parseAnswer(rcode, answer); config::parseAnswer(rcode, answer);
/// Let postponed hook initializations to run.
try {
getIOService()->pollExternalIOServices();
} catch (const std::exception& ex) {
std::ostringstream err;
err << "Error initializing hooks: "
<< ex.what();
return (isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str()));
}
return (answer); return (answer);
} }

View File

@ -12,12 +12,8 @@
#include <config.h> #include <config.h>
#include <cc/data.h> #include <dhcpsrv/testutils/lib_load_test_fixture.h>
#include <dhcpsrv/cfgmgr.h>
#include <hooks/hooks_manager.h>
#include <process/daemon.h>
#include <testutils/gtest_utils.h> #include <testutils/gtest_utils.h>
#include <testutils/lib_load_test_fixture.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <errno.h> #include <errno.h>

View File

@ -12,11 +12,8 @@
#include <config.h> #include <config.h>
#include <flex_option.h> #include <dhcpsrv/testutils/lib_load_test_fixture.h>
#include <dhcpsrv/cfgmgr.h> #include <testutils/gtest_utils.h>
#include <hooks/hooks_manager.h>
#include <process/daemon.h>
#include <testutils/lib_load_test_fixture.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <errno.h> #include <errno.h>

View File

@ -142,6 +142,9 @@ have been introduced. These hook points are used by the DHCPv4 and the
DHCPv6 servers respectively, to pass the instance of the IOService DHCPv6 servers respectively, to pass the instance of the IOService
(via "io_context" argument) to the hooks libraries which require to (via "io_context" argument) to the hooks libraries which require to
schedule asynchronous tasks. schedule asynchronous tasks.
The hook's IOService object must be registered on the server's main IOService by
calling registerExternalIOService and must unregister it on "unload" hook point
by calling unregisterExternalIOService.
It is also worth to note that the blocking reception of the DHCP packets It is also worth to note that the blocking reception of the DHCP packets
may cause up to 1 second delays in the asynchronous operations. This is may cause up to 1 second delays in the asynchronous operations. This is

View File

@ -46,9 +46,8 @@ extern "C" {
/// @param handle callout handle. /// @param handle callout handle.
int dhcp4_srv_configured(CalloutHandle& handle) { int dhcp4_srv_configured(CalloutHandle& handle) {
try { try {
isc::asiolink::IOServicePtr io_service; handle.getArgument("io_context", impl->getMainIOService());
handle.getArgument("io_context", io_service); if (!impl->getMainIOService()) {
if (!io_service) {
// Should not happen! // Should not happen!
handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP); handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP);
const string error("Error: io_context is null"); const string error("Error: io_context is null");
@ -57,7 +56,8 @@ int dhcp4_srv_configured(CalloutHandle& handle) {
} }
isc::dhcp::NetworkStatePtr network_state; isc::dhcp::NetworkStatePtr network_state;
handle.getArgument("network_state", network_state); handle.getArgument("network_state", network_state);
impl->startServices(io_service, network_state, HAServerType::DHCPv4); impl->startServices(network_state, HAServerType::DHCPv4);
impl->getMainIOService()->registerExternalIOService(impl->getIOService());
} catch (const std::exception& ex) { } catch (const std::exception& ex) {
LOG_ERROR(ha_logger, HA_DHCP4_START_SERVICE_FAILED) LOG_ERROR(ha_logger, HA_DHCP4_START_SERVICE_FAILED)
@ -164,9 +164,8 @@ int lease4_server_decline(CalloutHandle& handle) {
/// @param handle callout handle. /// @param handle callout handle.
int dhcp6_srv_configured(CalloutHandle& handle) { int dhcp6_srv_configured(CalloutHandle& handle) {
try { try {
isc::asiolink::IOServicePtr io_service; handle.getArgument("io_context", impl->getMainIOService());
handle.getArgument("io_context", io_service); if (!impl->getMainIOService()) {
if (!io_service) {
// Should not happen! // Should not happen!
handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP); handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP);
const string error("Error: io_context is null"); const string error("Error: io_context is null");
@ -175,7 +174,8 @@ int dhcp6_srv_configured(CalloutHandle& handle) {
} }
isc::dhcp::NetworkStatePtr network_state; isc::dhcp::NetworkStatePtr network_state;
handle.getArgument("network_state", network_state); handle.getArgument("network_state", network_state);
impl->startServices(io_service, network_state, HAServerType::DHCPv6); impl->startServices(network_state, HAServerType::DHCPv6);
impl->getMainIOService()->registerExternalIOService(impl->getIOService());
} catch (const std::exception& ex) { } catch (const std::exception& ex) {
LOG_ERROR(ha_logger, HA_DHCP6_START_SERVICE_FAILED) LOG_ERROR(ha_logger, HA_DHCP6_START_SERVICE_FAILED)
@ -442,6 +442,17 @@ int load(LibraryHandle& handle) {
/// ///
/// @return 0 if deregistration was successful, 1 otherwise /// @return 0 if deregistration was successful, 1 otherwise
int unload() { int unload() {
if (impl) {
if (impl->getMainIOService()) {
impl->getMainIOService()->unregisterExternalIOService(impl->getIOService());
}
impl->getIOService()->stop();
impl->getIOService()->restart();
try {
impl->getIOService()->poll();
} catch (...) {
}
}
impl.reset(); impl.reset();
LOG_INFO(ha_logger, HA_DEINIT_OK); LOG_INFO(ha_logger, HA_DEINIT_OK);
return (0); return (0);

View File

@ -31,7 +31,7 @@ namespace isc {
namespace ha { namespace ha {
HAImpl::HAImpl() HAImpl::HAImpl()
: config_(), services_(new HAServiceMapper()) { : io_service_(new IOService()), config_(), services_(new HAServiceMapper()) {
} }
void void
@ -40,13 +40,12 @@ HAImpl::configure(const ConstElementPtr& input_config) {
} }
void void
HAImpl::startServices(const IOServicePtr& io_service, HAImpl::startServices(const NetworkStatePtr& network_state,
const NetworkStatePtr& network_state,
const HAServerType& server_type) { const HAServerType& server_type) {
auto configs = config_->getAll(); auto configs = config_->getAll();
for (auto id = 0; id < configs.size(); ++id) { for (auto id = 0; id < configs.size(); ++id) {
// Create the HA service and crank up the state machine. // Create the HA service and crank up the state machine.
auto service = boost::make_shared<HAService>(id, io_service, network_state, auto service = boost::make_shared<HAService>(id, io_service_, network_state,
configs[id], server_type); configs[id], server_type);
for (auto const& peer_config : configs[id]->getAllServersConfig()) { for (auto const& peer_config : configs[id]->getAllServersConfig()) {
services_->map(peer_config.first, service); services_->map(peer_config.first, service);
@ -54,7 +53,7 @@ HAImpl::startServices(const IOServicePtr& io_service,
} }
// Schedule a start of the services. This ensures we begin after // Schedule a start of the services. This ensures we begin after
// the dust has settled and Kea MT mode has been firmly established. // the dust has settled and Kea MT mode has been firmly established.
io_service->post([&]() { io_service_->post([&]() {
for (auto const& service : services_->getAll()) { for (auto const& service : services_->getAll()) {
service->startClientAndListener(); service->startClientAndListener();
} }

View File

@ -45,13 +45,11 @@ public:
/// The caller must ensure that the HA configuration is valid before /// The caller must ensure that the HA configuration is valid before
/// calling this function. /// calling this function.
/// ///
/// @param io_service IO service object provided by the DHCP server.
/// @param network_state pointer to the object holding a state of the /// @param network_state pointer to the object holding a state of the
/// DHCP service (enabled/disabled). /// DHCP service (enabled/disabled).
/// @param server_type DHCP server type for which the HA service should /// @param server_type DHCP server type for which the HA service should
/// be created. /// be created.
void startServices(const asiolink::IOServicePtr& io_service, void startServices(const dhcp::NetworkStatePtr& network_state,
const dhcp::NetworkStatePtr& network_state,
const HAServerType& server_type); const HAServerType& server_type);
/// @brief Destructor. /// @brief Destructor.
@ -223,8 +221,42 @@ public:
HAServicePtr getHAServiceByServerName(const std::string& command_name, HAServicePtr getHAServiceByServerName(const std::string& command_name,
data::ConstElementPtr args) const; data::ConstElementPtr args) const;
/// @brief Get the hook I/O service.
///
/// @return the hook I/O service.
isc::asiolink::IOServicePtr& getIOService() {
return (io_service_);
}
/// @brief Set the hook I/O service.
///
/// @param io_service the hook I/O service.
void setIOService(isc::asiolink::IOServicePtr io_service) {
io_service_ = io_service;
}
/// @brief Get the main I/O service.
///
/// @return the main I/O service.
isc::asiolink::IOServicePtr& getMainIOService() {
return (main_io_service_);
}
/// @brief Set the main I/O service.
///
/// @param io_service the main I/O service.
void setMainIOService(isc::asiolink::IOServicePtr io_service) {
main_io_service_ = io_service;
}
protected: protected:
/// @brief The hook I/O service.
isc::asiolink::IOServicePtr io_service_;
/// @brief The main I/O service.
isc::asiolink::IOServicePtr main_io_service_;
/// @brief Holds parsed configuration. /// @brief Holds parsed configuration.
HAConfigMapperPtr config_; HAConfigMapperPtr config_;

View File

@ -12,11 +12,8 @@
#include <config.h> #include <config.h>
#include <cc/data.h> #include <dhcpsrv/testutils/lib_load_test_fixture.h>
#include <dhcpsrv/cfgmgr.h> #include <testutils/gtest_utils.h>
#include <hooks/hooks_manager.h>
#include <process/daemon.h>
#include <testutils/lib_load_test_fixture.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <errno.h> #include <errno.h>

View File

@ -127,11 +127,12 @@ public:
const std::string& expected_response) { const std::string& expected_response) {
io_service_.reset(new IOService()); io_service_.reset(new IOService());
ha_impl_.reset(new HAImpl()); ha_impl_.reset(new HAImpl());
ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON(ha_sync_command); ConstElementPtr command = Element::fromJSON(ha_sync_command);
@ -174,13 +175,14 @@ public:
TEST_F(HAImplTest, startServices) { TEST_F(HAImplTest, startServices) {
// Valid configuration must be provided prior to starting the service. // Valid configuration must be provided prior to starting the service.
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(createValidJsonConfiguration())); ASSERT_NO_THROW(test_ha_impl_->configure(createValidJsonConfiguration()));
// Network state is also required. // Network state is also required.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
// Start the service for DHCPv4 server. // Start the service for DHCPv4 server.
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
// Make sure that the HA service has been created for the requested // Make sure that the HA service has been created for the requested
@ -193,13 +195,14 @@ TEST_F(HAImplTest, startServices) {
TEST_F(HAImplTest, startServices6) { TEST_F(HAImplTest, startServices6) {
// Valid configuration must be provided prior to starting the service. // Valid configuration must be provided prior to starting the service.
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(createValidJsonConfiguration())); ASSERT_NO_THROW(test_ha_impl_->configure(createValidJsonConfiguration()));
// Network state is also required. // Network state is also required.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6));
// Start the service for DHCPv4 server. // Start the service for DHCPv4 server.
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv6)); HAServerType::DHCPv6));
// Make sure that the HA service has been created for the requested // Make sure that the HA service has been created for the requested
@ -216,11 +219,12 @@ TEST_F(HAImplTest, buffer4Receive) {
// Create implementation object and configure it. // Create implementation object and configure it.
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); ASSERT_NO_THROW(test_ha_impl_->configure(ha_config));
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
// Initially the HA service is in the waiting state and serves no scopes. // Initially the HA service is in the waiting state and serves no scopes.
@ -329,11 +333,12 @@ TEST_F(HAImplTest, subnet4Select) {
// Create implementation object and configure it. // Create implementation object and configure it.
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); ASSERT_NO_THROW(test_ha_impl_->configure(ha_config));
// Starting the service is required before any callouts. // Starting the service is required before any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
// The hub is a standby server and by default serves no scopes. Explicitly // The hub is a standby server and by default serves no scopes. Explicitly
@ -386,11 +391,12 @@ TEST_F(HAImplTest, subnet4SelectSharedNetwork) {
// Create implementation object and configure it. // Create implementation object and configure it.
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); ASSERT_NO_THROW(test_ha_impl_->configure(ha_config));
// Starting the service is required before any callouts. // Starting the service is required before any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
// The hub is a standby server and by default serves no scopes. Explicitly // The hub is a standby server and by default serves no scopes. Explicitly
@ -446,11 +452,12 @@ TEST_F(HAImplTest, subnet4SelectSingleRelationship) {
// Create implementation object and configure it. // Create implementation object and configure it.
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); ASSERT_NO_THROW(test_ha_impl_->configure(ha_config));
// Starting the service is required before any callouts. // Starting the service is required before any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
// Create callout handle to be used for passing arguments to the // Create callout handle to be used for passing arguments to the
@ -487,11 +494,12 @@ TEST_F(HAImplTest, subnet4SelectDropNoServerName) {
// Create implementation object and configure it. // Create implementation object and configure it.
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); ASSERT_NO_THROW(test_ha_impl_->configure(ha_config));
// Starting the service is required before any callouts. // Starting the service is required before any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
// The hub is a standby server and by default serves no scopes. Explicitly // The hub is a standby server and by default serves no scopes. Explicitly
@ -532,11 +540,12 @@ TEST_F(HAImplTest, subnet4SelectDropInvalidServerNameType) {
// Create implementation object and configure it. // Create implementation object and configure it.
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); ASSERT_NO_THROW(test_ha_impl_->configure(ha_config));
// Starting the service is required before any callouts. // Starting the service is required before any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
// The hub is a standby server and by default serves no scopes. Explicitly // The hub is a standby server and by default serves no scopes. Explicitly
@ -581,11 +590,12 @@ TEST_F(HAImplTest, subnet4SelectDropNotInScope) {
// Create implementation object and configure it. // Create implementation object and configure it.
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); ASSERT_NO_THROW(test_ha_impl_->configure(ha_config));
// Starting the service is required before any callouts. // Starting the service is required before any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
// This server serves server1/server2 scopes but not server3/server4 scopes. // This server serves server1/server2 scopes but not server3/server4 scopes.
@ -633,11 +643,12 @@ TEST_F(HAImplTest, subnet4SelectNoSubnet) {
// Create implementation object and configure it. // Create implementation object and configure it.
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); ASSERT_NO_THROW(test_ha_impl_->configure(ha_config));
// Starting the service is required before any callouts. // Starting the service is required before any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
test_ha_impl_->services_->get("server2")->serveFailoverScopes(); test_ha_impl_->services_->get("server2")->serveFailoverScopes();
@ -679,11 +690,12 @@ TEST_F(HAImplTest, buffer6Receive) {
// Create implementation object and configure it. // Create implementation object and configure it.
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); ASSERT_NO_THROW(test_ha_impl_->configure(ha_config));
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv6)); HAServerType::DHCPv6));
// Initially the HA service is in the waiting state and serves no scopes. // Initially the HA service is in the waiting state and serves no scopes.
@ -769,11 +781,12 @@ TEST_F(HAImplTest, subnet6Select) {
// Create implementation object and configure it. // Create implementation object and configure it.
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); ASSERT_NO_THROW(test_ha_impl_->configure(ha_config));
// Starting the service is required before any callouts. // Starting the service is required before any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv6)); HAServerType::DHCPv6));
// The hub is a standby server and by default serves no scopes. Explicitly // The hub is a standby server and by default serves no scopes. Explicitly
@ -823,11 +836,12 @@ TEST_F(HAImplTest, subnet6SelectSharedNetwork) {
// Create implementation object and configure it. // Create implementation object and configure it.
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); ASSERT_NO_THROW(test_ha_impl_->configure(ha_config));
// Starting the service is required before any callouts. // Starting the service is required before any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv6)); HAServerType::DHCPv6));
// The hub is a standby server and by default serves no scopes. Explicitly // The hub is a standby server and by default serves no scopes. Explicitly
@ -883,11 +897,12 @@ TEST_F(HAImplTest, subnet6SelectSingleRelationship) {
// Create implementation object and configure it. // Create implementation object and configure it.
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); ASSERT_NO_THROW(test_ha_impl_->configure(ha_config));
// Starting the service is required before any callouts. // Starting the service is required before any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv6)); HAServerType::DHCPv6));
// Create callout handle to be used for passing arguments to the // Create callout handle to be used for passing arguments to the
@ -924,11 +939,12 @@ TEST_F(HAImplTest, subnet6SelectDropNoServerName) {
// Create implementation object and configure it. // Create implementation object and configure it.
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); ASSERT_NO_THROW(test_ha_impl_->configure(ha_config));
// Starting the service is required before any callouts. // Starting the service is required before any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv6)); HAServerType::DHCPv6));
// The hub is a standby server and by default serves no scopes. Explicitly // The hub is a standby server and by default serves no scopes. Explicitly
@ -969,11 +985,12 @@ TEST_F(HAImplTest, subnet6SelectDropInvalidServerNameType) {
// Create implementation object and configure it. // Create implementation object and configure it.
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); ASSERT_NO_THROW(test_ha_impl_->configure(ha_config));
// Starting the service is required before any callouts. // Starting the service is required before any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv6)); HAServerType::DHCPv6));
// The hub is a standby server and by default serves no scopes. Explicitly // The hub is a standby server and by default serves no scopes. Explicitly
@ -1018,11 +1035,12 @@ TEST_F(HAImplTest, subnet6SelectDropNotInScope) {
// Create implementation object and configure it. // Create implementation object and configure it.
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); ASSERT_NO_THROW(test_ha_impl_->configure(ha_config));
// Starting the service is required before any callouts. // Starting the service is required before any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv6)); HAServerType::DHCPv6));
// This server serves server1/server2 scopes but not server3/server4 scopes. // This server serves server1/server2 scopes but not server3/server4 scopes.
@ -1070,11 +1088,12 @@ TEST_F(HAImplTest, subnet6SelectNoSubnet) {
// Create implementation object and configure it. // Create implementation object and configure it.
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(ha_config)); ASSERT_NO_THROW(test_ha_impl_->configure(ha_config));
// Starting the service is required before any callouts. // Starting the service is required before any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv6)); HAServerType::DHCPv6));
test_ha_impl_->services_->get("server2")->serveFailoverScopes(); test_ha_impl_->services_->get("server2")->serveFailoverScopes();
@ -1112,11 +1131,12 @@ TEST_F(HAImplTest, subnet6SelectNoSubnet) {
TEST_F(HAImplTest, leases4Committed) { TEST_F(HAImplTest, leases4Committed) {
// Create implementation object and configure it. // Create implementation object and configure it.
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(createValidJsonConfiguration())); ASSERT_NO_THROW(test_ha_impl_->configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
// Make sure we wait for the acks from the backup server to be able to // Make sure we wait for the acks from the backup server to be able to
@ -1198,11 +1218,12 @@ TEST_F(HAImplTest, leases4Committed) {
TEST_F(HAImplTest, leases4CommittedMultipleRelationships) { TEST_F(HAImplTest, leases4CommittedMultipleRelationships) {
// Create implementation object and configure it. // Create implementation object and configure it.
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(createValidHubJsonConfiguration())); ASSERT_NO_THROW(test_ha_impl_->configure(createValidHubJsonConfiguration()));
// Starting the service is required before running any callouts. // Starting the service is required before running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
// By enabling this setting we ensure that the lease updates are always // By enabling this setting we ensure that the lease updates are always
@ -1254,11 +1275,12 @@ TEST_F(HAImplTest, leases4CommittedMultipleRelationships) {
TEST_F(HAImplTest, leases4CommittedMultipleRelationshipsNoServerName) { TEST_F(HAImplTest, leases4CommittedMultipleRelationshipsNoServerName) {
// Create implementation object and configure it. // Create implementation object and configure it.
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(createValidHubJsonConfiguration())); ASSERT_NO_THROW(test_ha_impl_->configure(createValidHubJsonConfiguration()));
// Starting the service is required before running any callouts. // Starting the service is required before running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
// By enabling this setting we ensure that the lease updates are always // By enabling this setting we ensure that the lease updates are always
@ -1306,11 +1328,12 @@ TEST_F(HAImplTest, leases4CommittedMultipleRelationshipsNoServerName) {
TEST_F(HAImplTest, leases4CommittedMultipleRelationshipsInvalidServerName) { TEST_F(HAImplTest, leases4CommittedMultipleRelationshipsInvalidServerName) {
// Create implementation object and configure it. // Create implementation object and configure it.
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(createValidHubJsonConfiguration())); ASSERT_NO_THROW(test_ha_impl_->configure(createValidHubJsonConfiguration()));
// Starting the service is required before running any callouts. // Starting the service is required before running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
// By enabling this setting we ensure that the lease updates are always // By enabling this setting we ensure that the lease updates are always
@ -1360,11 +1383,12 @@ TEST_F(HAImplTest, leases4CommittedMultipleRelationshipsInvalidServerName) {
TEST_F(HAImplTest, leases6Committed) { TEST_F(HAImplTest, leases6Committed) {
// Create implementation object and configure it. // Create implementation object and configure it.
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(createValidJsonConfiguration())); ASSERT_NO_THROW(test_ha_impl_->configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv6)); HAServerType::DHCPv6));
// Make sure we wait for the acks from the backup server to be able to // Make sure we wait for the acks from the backup server to be able to
@ -1445,11 +1469,12 @@ TEST_F(HAImplTest, leases6Committed) {
TEST_F(HAImplTest, leases6CommittedMultipleRelationships) { TEST_F(HAImplTest, leases6CommittedMultipleRelationships) {
// Create implementation object and configure it. // Create implementation object and configure it.
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(createValidHubJsonConfiguration())); ASSERT_NO_THROW(test_ha_impl_->configure(createValidHubJsonConfiguration()));
// Starting the service is required before running any callouts. // Starting the service is required before running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv6)); HAServerType::DHCPv6));
// By enabling this setting we ensure that the lease updates are always // By enabling this setting we ensure that the lease updates are always
@ -1500,11 +1525,12 @@ TEST_F(HAImplTest, leases6CommittedMultipleRelationships) {
TEST_F(HAImplTest, leases6CommittedMultipleRelationshipsNoServerName) { TEST_F(HAImplTest, leases6CommittedMultipleRelationshipsNoServerName) {
// Create implementation object and configure it. // Create implementation object and configure it.
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(createValidHubJsonConfiguration())); ASSERT_NO_THROW(test_ha_impl_->configure(createValidHubJsonConfiguration()));
// Starting the service is required before running any callouts. // Starting the service is required before running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv6)); HAServerType::DHCPv6));
// By enabling this setting we ensure that the lease updates are always // By enabling this setting we ensure that the lease updates are always
@ -1551,11 +1577,12 @@ TEST_F(HAImplTest, leases6CommittedMultipleRelationshipsNoServerName) {
TEST_F(HAImplTest, leases6CommittedMultipleRelationshipsInvalidServerName) { TEST_F(HAImplTest, leases6CommittedMultipleRelationshipsInvalidServerName) {
// Create implementation object and configure it. // Create implementation object and configure it.
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(createValidHubJsonConfiguration())); ASSERT_NO_THROW(test_ha_impl_->configure(createValidHubJsonConfiguration()));
// Starting the service is required before running any callouts. // Starting the service is required before running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv6));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv6)); HAServerType::DHCPv6));
// By enabling this setting we ensure that the lease updates are always // By enabling this setting we ensure that the lease updates are always
@ -1682,11 +1709,12 @@ TEST_F(HAImplTest, synchronizeHandler) {
// Tests ha-continue command handler with a specified server name. // Tests ha-continue command handler with a specified server name.
TEST_F(HAImplTest, continueHandler) { TEST_F(HAImplTest, continueHandler) {
ha_impl_.reset(new HAImpl()); ha_impl_.reset(new HAImpl());
ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON("{" ConstElementPtr command = Element::fromJSON("{"
@ -1711,11 +1739,12 @@ TEST_F(HAImplTest, continueHandler) {
// Tests ha-continue command handler without a server name. // Tests ha-continue command handler without a server name.
TEST_F(HAImplTest, continueHandlerWithNoServerName) { TEST_F(HAImplTest, continueHandlerWithNoServerName) {
ha_impl_.reset(new HAImpl()); ha_impl_.reset(new HAImpl());
ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON("{ \"command\": \"ha-continue\" }"); ConstElementPtr command = Element::fromJSON("{ \"command\": \"ha-continue\" }");
@ -1735,11 +1764,12 @@ TEST_F(HAImplTest, continueHandlerWithNoServerName) {
// Tests ha-continue command handler with wrong server name. // Tests ha-continue command handler with wrong server name.
TEST_F(HAImplTest, continueHandlerWithWrongServerName) { TEST_F(HAImplTest, continueHandlerWithWrongServerName) {
ha_impl_.reset(new HAImpl()); ha_impl_.reset(new HAImpl());
ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON("{" ConstElementPtr command = Element::fromJSON("{"
@ -1764,11 +1794,12 @@ TEST_F(HAImplTest, continueHandlerWithWrongServerName) {
// Tests status-get command processed handler. // Tests status-get command processed handler.
TEST_F(HAImplTest, statusGet) { TEST_F(HAImplTest, statusGet) {
ha_impl_.reset(new HAImpl()); ha_impl_.reset(new HAImpl());
ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
std::string name = "status-get"; std::string name = "status-get";
@ -1825,12 +1856,13 @@ TEST_F(HAImplTest, statusGet) {
// Tests status-get command processed handler for backup server. // Tests status-get command processed handler for backup server.
TEST_F(HAImplTest, statusGetBackupServer) { TEST_F(HAImplTest, statusGetBackupServer) {
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(createValidJsonConfiguration())); ASSERT_NO_THROW(test_ha_impl_->configure(createValidJsonConfiguration()));
test_ha_impl_->config_->get()->setThisServerName("server3"); test_ha_impl_->config_->get()->setThisServerName("server3");
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
std::string name = "status-get"; std::string name = "status-get";
@ -1875,11 +1907,12 @@ TEST_F(HAImplTest, statusGetBackupServer) {
// passive-backup state. // passive-backup state.
TEST_F(HAImplTest, statusGetPassiveBackup) { TEST_F(HAImplTest, statusGetPassiveBackup) {
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(createValidPassiveBackupJsonConfiguration())); ASSERT_NO_THROW(test_ha_impl_->configure(createValidPassiveBackupJsonConfiguration()));
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
std::string name = "status-get"; std::string name = "status-get";
@ -1924,11 +1957,12 @@ TEST_F(HAImplTest, statusGetPassiveBackup) {
// hub-and-spoke mode. // hub-and-spoke mode.
TEST_F(HAImplTest, statusGetHubAndSpoke) { TEST_F(HAImplTest, statusGetHubAndSpoke) {
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(createValidHubJsonConfiguration())); ASSERT_NO_THROW(test_ha_impl_->configure(createValidHubJsonConfiguration()));
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
std::string name = "status-get"; std::string name = "status-get";
@ -2009,11 +2043,12 @@ TEST_F(HAImplTest, statusGetHubAndSpoke) {
// Test ha-maintenance-notify command handler with server name. // Test ha-maintenance-notify command handler with server name.
TEST_F(HAImplTest, maintenanceNotify) { TEST_F(HAImplTest, maintenanceNotify) {
ha_impl_.reset(new HAImpl()); ha_impl_.reset(new HAImpl());
ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON( ConstElementPtr command = Element::fromJSON(
@ -2041,11 +2076,12 @@ TEST_F(HAImplTest, maintenanceNotify) {
// Test ha-maintenance-notify command handler without server name. // Test ha-maintenance-notify command handler without server name.
TEST_F(HAImplTest, maintenanceNotifyNoServerName) { TEST_F(HAImplTest, maintenanceNotifyNoServerName) {
ha_impl_.reset(new HAImpl()); ha_impl_.reset(new HAImpl());
ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON( ConstElementPtr command = Element::fromJSON(
@ -2072,11 +2108,12 @@ TEST_F(HAImplTest, maintenanceNotifyNoServerName) {
// Test ha-maintenance-notify command handler without server name. // Test ha-maintenance-notify command handler without server name.
TEST_F(HAImplTest, maintenanceNotifyBadServerName) { TEST_F(HAImplTest, maintenanceNotifyBadServerName) {
ha_impl_.reset(new HAImpl()); ha_impl_.reset(new HAImpl());
ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON( ConstElementPtr command = Element::fromJSON(
@ -2104,11 +2141,12 @@ TEST_F(HAImplTest, maintenanceNotifyBadServerName) {
// Test ha-reset command handler with a specified server name. // Test ha-reset command handler with a specified server name.
TEST_F(HAImplTest, haReset) { TEST_F(HAImplTest, haReset) {
ha_impl_.reset(new HAImpl()); ha_impl_.reset(new HAImpl());
ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON( ConstElementPtr command = Element::fromJSON(
@ -2135,11 +2173,12 @@ TEST_F(HAImplTest, haReset) {
// Test ha-reset command handler without a specified server name. // Test ha-reset command handler without a specified server name.
TEST_F(HAImplTest, haResetNoServerName) { TEST_F(HAImplTest, haResetNoServerName) {
ha_impl_.reset(new HAImpl()); ha_impl_.reset(new HAImpl());
ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON( ConstElementPtr command = Element::fromJSON(
@ -2163,11 +2202,12 @@ TEST_F(HAImplTest, haResetNoServerName) {
// Test ha-reset command handler with a wrong server name. // Test ha-reset command handler with a wrong server name.
TEST_F(HAImplTest, haResetBadServerName) { TEST_F(HAImplTest, haResetBadServerName) {
ha_impl_.reset(new HAImpl()); ha_impl_.reset(new HAImpl());
ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON( ConstElementPtr command = Element::fromJSON(
@ -2194,11 +2234,12 @@ TEST_F(HAImplTest, haResetBadServerName) {
// Test ha-heartbeat command handler with a specified server name. // Test ha-heartbeat command handler with a specified server name.
TEST_F(HAImplTest, haHeartbeat) { TEST_F(HAImplTest, haHeartbeat) {
ha_impl_.reset(new HAImpl()); ha_impl_.reset(new HAImpl());
ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON( ConstElementPtr command = Element::fromJSON(
@ -2225,11 +2266,12 @@ TEST_F(HAImplTest, haHeartbeat) {
// Test ha-heartbeat command handler without a specified server name. // Test ha-heartbeat command handler without a specified server name.
TEST_F(HAImplTest, haHeartbeatNoServerName) { TEST_F(HAImplTest, haHeartbeatNoServerName) {
ha_impl_.reset(new HAImpl()); ha_impl_.reset(new HAImpl());
ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON( ConstElementPtr command = Element::fromJSON(
@ -2253,11 +2295,12 @@ TEST_F(HAImplTest, haHeartbeatNoServerName) {
// Test ha-heartbeat command handler with a wrong server name. // Test ha-heartbeat command handler with a wrong server name.
TEST_F(HAImplTest, haHeartbeatBadServerName) { TEST_F(HAImplTest, haHeartbeatBadServerName) {
ha_impl_.reset(new HAImpl()); ha_impl_.reset(new HAImpl());
ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON( ConstElementPtr command = Element::fromJSON(
@ -2284,11 +2327,12 @@ TEST_F(HAImplTest, haHeartbeatBadServerName) {
// Test ha-sync-complete-notify command handler with a specified server name. // Test ha-sync-complete-notify command handler with a specified server name.
TEST_F(HAImplTest, haSyncCompleteNotify) { TEST_F(HAImplTest, haSyncCompleteNotify) {
ha_impl_.reset(new HAImpl()); ha_impl_.reset(new HAImpl());
ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON( ConstElementPtr command = Element::fromJSON(
@ -2316,11 +2360,12 @@ TEST_F(HAImplTest, haSyncCompleteNotify) {
// Test ha-sync-complete-notify command handler without a specified server name. // Test ha-sync-complete-notify command handler without a specified server name.
TEST_F(HAImplTest, haSyncCompleteNotifyNoServerName) { TEST_F(HAImplTest, haSyncCompleteNotifyNoServerName) {
ha_impl_.reset(new HAImpl()); ha_impl_.reset(new HAImpl());
ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON( ConstElementPtr command = Element::fromJSON(
@ -2345,11 +2390,12 @@ TEST_F(HAImplTest, haSyncCompleteNotifyNoServerName) {
// Test ha-sync-complete-notify command handler with a wrong server name. // Test ha-sync-complete-notify command handler with a wrong server name.
TEST_F(HAImplTest, haSyncCompleteNotifyBadServerName) { TEST_F(HAImplTest, haSyncCompleteNotifyBadServerName) {
ha_impl_.reset(new HAImpl()); ha_impl_.reset(new HAImpl());
ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON( ConstElementPtr command = Element::fromJSON(
@ -2376,11 +2422,12 @@ TEST_F(HAImplTest, haSyncCompleteNotifyBadServerName) {
// Test ha-scopes command handler with a specified server name. // Test ha-scopes command handler with a specified server name.
TEST_F(HAImplTest, haScopes) { TEST_F(HAImplTest, haScopes) {
ha_impl_.reset(new HAImpl()); ha_impl_.reset(new HAImpl());
ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON( ConstElementPtr command = Element::fromJSON(
@ -2408,11 +2455,12 @@ TEST_F(HAImplTest, haScopes) {
// Test ha-scopes command handler without a specified server name. // Test ha-scopes command handler without a specified server name.
TEST_F(HAImplTest, haScopesNoServerName) { TEST_F(HAImplTest, haScopesNoServerName) {
ha_impl_.reset(new HAImpl()); ha_impl_.reset(new HAImpl());
ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON( ConstElementPtr command = Element::fromJSON(
@ -2439,11 +2487,12 @@ TEST_F(HAImplTest, haScopesNoServerName) {
// Test ha-scopes command handler with a wrong server name. // Test ha-scopes command handler with a wrong server name.
TEST_F(HAImplTest, haScopesBadServerName) { TEST_F(HAImplTest, haScopesBadServerName) {
ha_impl_.reset(new HAImpl()); ha_impl_.reset(new HAImpl());
ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration())); ASSERT_NO_THROW(ha_impl_->configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON( ConstElementPtr command = Element::fromJSON(
@ -2472,11 +2521,12 @@ TEST_F(HAImplTest, haScopesBadServerName) {
TEST_F(HAImplTest, lease4ServerDecline) { TEST_F(HAImplTest, lease4ServerDecline) {
// Create implementation object and configure it. // Create implementation object and configure it.
test_ha_impl_.reset(new TestHAImpl()); test_ha_impl_.reset(new TestHAImpl());
test_ha_impl_->setIOService(io_service_);
ASSERT_NO_THROW(test_ha_impl_->configure(createValidJsonConfiguration())); ASSERT_NO_THROW(test_ha_impl_->configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts. // Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4)); NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(test_ha_impl_->startServices(io_service_, network_state, ASSERT_NO_THROW(test_ha_impl_->startServices(network_state,
HAServerType::DHCPv4)); HAServerType::DHCPv4));
// Make sure we wait for the acks from the backup server to be able to // Make sure we wait for the acks from the backup server to be able to

View File

@ -12,12 +12,8 @@
#include <config.h> #include <config.h>
#include <cc/data.h> #include <dhcpsrv/testutils/lib_load_test_fixture.h>
#include <dhcpsrv/cfgmgr.h>
#include <hooks/hooks_manager.h>
#include <process/daemon.h>
#include <testutils/gtest_utils.h> #include <testutils/gtest_utils.h>
#include <testutils/lib_load_test_fixture.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <errno.h> #include <errno.h>

View File

@ -12,12 +12,8 @@
#include <config.h> #include <config.h>
#include <cc/data.h> #include <dhcpsrv/testutils/lib_load_test_fixture.h>
#include <dhcpsrv/cfgmgr.h>
#include <hooks/hooks_manager.h>
#include <process/daemon.h>
#include <testutils/gtest_utils.h> #include <testutils/gtest_utils.h>
#include <testutils/lib_load_test_fixture.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <errno.h> #include <errno.h>

View File

@ -22,6 +22,7 @@
#include <sstream> #include <sstream>
#include <string> #include <string>
using namespace isc::asiolink;
using namespace isc::cb; using namespace isc::cb;
using namespace isc::dhcp; using namespace isc::dhcp;
using namespace isc::hooks; using namespace isc::hooks;
@ -67,15 +68,15 @@ int load(LibraryHandle& /* handle */) {
/// @param handle callout handle passed to the callout. /// @param handle callout handle passed to the callout.
/// @return 0 on success, 1 otherwise. /// @return 0 on success, 1 otherwise.
int dhcp4_srv_configured(CalloutHandle& handle) { int dhcp4_srv_configured(CalloutHandle& handle) {
isc::asiolink::IOServicePtr io_service; handle.getArgument("io_context", isc::dhcp::MySqlConfigBackendImpl::getMainIOService());
handle.getArgument("io_context", io_service); if (!isc::dhcp::MySqlConfigBackendImpl::getMainIOService()) {
if (!io_service) {
const string error("Error: io_context is null"); const string error("Error: io_context is null");
handle.setArgument("error", error); handle.setArgument("error", error);
handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP); handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP);
return (1); return (1);
} }
isc::dhcp::MySqlConfigBackendImpl::setIOService(io_service); isc::dhcp::MySqlConfigBackendImpl::getIOService().reset(new IOService());
isc::dhcp::MySqlConfigBackendImpl::getMainIOService()->registerExternalIOService(isc::dhcp::MySqlConfigBackendImpl::getIOService());
return (0); return (0);
} }
@ -86,15 +87,15 @@ int dhcp4_srv_configured(CalloutHandle& handle) {
/// @param handle callout handle passed to the callout. /// @param handle callout handle passed to the callout.
/// @return 0 on success, 1 otherwise. /// @return 0 on success, 1 otherwise.
int dhcp6_srv_configured(CalloutHandle& handle) { int dhcp6_srv_configured(CalloutHandle& handle) {
isc::asiolink::IOServicePtr io_service; handle.getArgument("io_context", isc::dhcp::MySqlConfigBackendImpl::getMainIOService());
handle.getArgument("io_context", io_service); if (!isc::dhcp::MySqlConfigBackendImpl::getMainIOService()) {
if (!io_service) {
const string error("Error: io_context is null"); const string error("Error: io_context is null");
handle.setArgument("error", error); handle.setArgument("error", error);
handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP); handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP);
return (1); return (1);
} }
isc::dhcp::MySqlConfigBackendImpl::setIOService(io_service); isc::dhcp::MySqlConfigBackendImpl::getIOService().reset(new IOService());
isc::dhcp::MySqlConfigBackendImpl::getMainIOService()->registerExternalIOService(isc::dhcp::MySqlConfigBackendImpl::getIOService());
return (0); return (0);
} }
@ -106,6 +107,17 @@ int unload() {
// Unregister the factories and remove MySQL backends // Unregister the factories and remove MySQL backends
isc::dhcp::MySqlConfigBackendDHCPv4::unregisterBackendType(); isc::dhcp::MySqlConfigBackendDHCPv4::unregisterBackendType();
isc::dhcp::MySqlConfigBackendDHCPv6::unregisterBackendType(); isc::dhcp::MySqlConfigBackendDHCPv6::unregisterBackendType();
if (isc::dhcp::MySqlConfigBackendImpl::getMainIOService()) {
isc::dhcp::MySqlConfigBackendImpl::getMainIOService()->unregisterExternalIOService(isc::dhcp::MySqlConfigBackendImpl::getIOService());
}
if (isc::dhcp::MySqlConfigBackendImpl::getIOService()) {
isc::dhcp::MySqlConfigBackendImpl::getIOService()->stop();
isc::dhcp::MySqlConfigBackendImpl::getIOService()->restart();
try {
isc::dhcp::MySqlConfigBackendImpl::getIOService()->poll();
} catch (...) {
}
}
return (0); return (0);
} }

View File

@ -29,7 +29,8 @@ using namespace isc::util;
namespace isc { namespace isc {
namespace dhcp { namespace dhcp {
isc::asiolink::IOServicePtr MySqlConfigBackendImpl::io_service_ = isc::asiolink::IOServicePtr(); isc::asiolink::IOServicePtr MySqlConfigBackendImpl::io_service_;
isc::asiolink::IOServicePtr MySqlConfigBackendImpl::main_io_service_;
MySqlConfigBackendImpl:: MySqlConfigBackendImpl::
ScopedAuditRevision::ScopedAuditRevision(MySqlConfigBackendImpl* impl, ScopedAuditRevision::ScopedAuditRevision(MySqlConfigBackendImpl* impl,
@ -86,6 +87,11 @@ MySqlConfigBackendImpl(const std::string& space,
} }
} }
MySqlConfigBackendImpl::~MySqlConfigBackendImpl() {
/// nothing to do there. The conn_ connection will be deleted and its dtor
/// will take care of releasing the compiled statements and similar.
}
MySqlBindingPtr MySqlBindingPtr
MySqlConfigBackendImpl::createBinding(const Triplet<uint32_t>& triplet) { MySqlConfigBackendImpl::createBinding(const Triplet<uint32_t>& triplet) {
if (triplet.unspecified()) { if (triplet.unspecified()) {

View File

@ -115,7 +115,7 @@ public:
const db::DbCallback db_reconnect_callback); const db::DbCallback db_reconnect_callback);
/// @brief Destructor. /// @brief Destructor.
virtual ~MySqlConfigBackendImpl() {}; virtual ~MySqlConfigBackendImpl();
/// @brief Creates MySQL binding from an @c Optional of integer type. /// @brief Creates MySQL binding from an @c Optional of integer type.
/// ///
@ -836,16 +836,32 @@ public:
return (parameters_); return (parameters_);
} }
/// @brief Sets IO service to be used by the MySQL config backend. /// @brief Get the hook I/O service.
/// ///
/// @param IOService object, used for all ASIO operations. /// @return the hook I/O service.
static void setIOService(const isc::asiolink::IOServicePtr& io_service) { static isc::asiolink::IOServicePtr& getIOService() {
return (io_service_);
}
/// @brief Set the hook I/O service.
///
/// @param io_service the hook I/O service.
static void setIOService(isc::asiolink::IOServicePtr io_service) {
io_service_ = io_service; io_service_ = io_service;
} }
/// @brief Returns pointer to the IO service. /// @brief Get the main I/O service.
static isc::asiolink::IOServicePtr& getIOService() { ///
return (io_service_); /// @return the main I/O service.
static isc::asiolink::IOServicePtr& getMainIOService() {
return (main_io_service_);
}
/// @brief Set the main I/O service.
///
/// @param io_service the main I/O service.
static void setMainIOService(isc::asiolink::IOServicePtr io_service) {
main_io_service_ = io_service;
} }
/// @brief Represents connection to the MySQL database. /// @brief Represents connection to the MySQL database.
@ -864,8 +880,11 @@ private:
/// @brief Connection parameters /// @brief Connection parameters
isc::db::DatabaseConnection::ParameterMap parameters_; isc::db::DatabaseConnection::ParameterMap parameters_;
/// @brief The IOService object, used for all ASIO operations. /// @brief The hook I/O service.
static isc::asiolink::IOServicePtr io_service_; static isc::asiolink::IOServicePtr io_service_;
/// @brief The main I/O service.
static isc::asiolink::IOServicePtr main_io_service_;
}; };
} // end of namespace isc::dhcp } // end of namespace isc::dhcp

View File

@ -12,12 +12,8 @@
#include <config.h> #include <config.h>
#include <cc/data.h> #include <dhcpsrv/testutils/lib_load_test_fixture.h>
#include <dhcpsrv/cfgmgr.h>
#include <hooks/hooks_manager.h>
#include <process/daemon.h>
#include <testutils/gtest_utils.h> #include <testutils/gtest_utils.h>
#include <testutils/lib_load_test_fixture.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <errno.h> #include <errno.h>

View File

@ -12,12 +12,8 @@
#include <config.h> #include <config.h>
#include <cc/data.h> #include <dhcpsrv/testutils/lib_load_test_fixture.h>
#include <dhcpsrv/cfgmgr.h>
#include <hooks/hooks_manager.h>
#include <process/daemon.h>
#include <testutils/gtest_utils.h> #include <testutils/gtest_utils.h>
#include <testutils/lib_load_test_fixture.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <errno.h> #include <errno.h>

View File

@ -22,6 +22,7 @@
#include <sstream> #include <sstream>
#include <string> #include <string>
using namespace isc::asiolink;
using namespace isc::cb; using namespace isc::cb;
using namespace isc::dhcp; using namespace isc::dhcp;
using namespace isc::hooks; using namespace isc::hooks;
@ -67,15 +68,15 @@ int load(LibraryHandle& /* handle */) {
/// @param handle callout handle passed to the callout. /// @param handle callout handle passed to the callout.
/// @return 0 on success, 1 otherwise. /// @return 0 on success, 1 otherwise.
int dhcp4_srv_configured(CalloutHandle& handle) { int dhcp4_srv_configured(CalloutHandle& handle) {
isc::asiolink::IOServicePtr io_service; handle.getArgument("io_context", isc::dhcp::PgSqlConfigBackendImpl::getMainIOService());
handle.getArgument("io_context", io_service); if (!isc::dhcp::PgSqlConfigBackendImpl::getMainIOService()) {
if (!io_service) {
const string error("Error: io_context is null"); const string error("Error: io_context is null");
handle.setArgument("error", error); handle.setArgument("error", error);
handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP); handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP);
return (1); return (1);
} }
isc::dhcp::PgSqlConfigBackendImpl::setIOService(io_service); isc::dhcp::PgSqlConfigBackendImpl::getIOService().reset(new IOService());
isc::dhcp::PgSqlConfigBackendImpl::getMainIOService()->registerExternalIOService(isc::dhcp::PgSqlConfigBackendImpl::getIOService());
return (0); return (0);
} }
@ -86,15 +87,15 @@ int dhcp4_srv_configured(CalloutHandle& handle) {
/// @param handle callout handle passed to the callout. /// @param handle callout handle passed to the callout.
/// @return 0 on success, 1 otherwise. /// @return 0 on success, 1 otherwise.
int dhcp6_srv_configured(CalloutHandle& handle) { int dhcp6_srv_configured(CalloutHandle& handle) {
isc::asiolink::IOServicePtr io_service; handle.getArgument("io_context", isc::dhcp::PgSqlConfigBackendImpl::getMainIOService());
handle.getArgument("io_context", io_service); if (!isc::dhcp::PgSqlConfigBackendImpl::getMainIOService()) {
if (!io_service) {
const string error("Error: io_context is null"); const string error("Error: io_context is null");
handle.setArgument("error", error); handle.setArgument("error", error);
handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP); handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP);
return (1); return (1);
} }
isc::dhcp::PgSqlConfigBackendImpl::setIOService(io_service); isc::dhcp::PgSqlConfigBackendImpl::getIOService().reset(new IOService());
isc::dhcp::PgSqlConfigBackendImpl::getMainIOService()->registerExternalIOService(isc::dhcp::PgSqlConfigBackendImpl::getIOService());
return (0); return (0);
} }
@ -106,6 +107,17 @@ int unload() {
// Unregister the factories and remove PostgreSQL backends // Unregister the factories and remove PostgreSQL backends
isc::dhcp::PgSqlConfigBackendDHCPv4::unregisterBackendType(); isc::dhcp::PgSqlConfigBackendDHCPv4::unregisterBackendType();
isc::dhcp::PgSqlConfigBackendDHCPv6::unregisterBackendType(); isc::dhcp::PgSqlConfigBackendDHCPv6::unregisterBackendType();
if (isc::dhcp::PgSqlConfigBackendImpl::getMainIOService()) {
isc::dhcp::PgSqlConfigBackendImpl::getMainIOService()->unregisterExternalIOService(isc::dhcp::PgSqlConfigBackendImpl::getIOService());
}
if (isc::dhcp::PgSqlConfigBackendImpl::getIOService()) {
isc::dhcp::PgSqlConfigBackendImpl::getIOService()->stop();
isc::dhcp::PgSqlConfigBackendImpl::getIOService()->restart();
try {
isc::dhcp::PgSqlConfigBackendImpl::getIOService()->poll();
} catch (...) {
}
}
return (0); return (0);
} }

View File

@ -28,7 +28,8 @@ using namespace isc::util;
namespace isc { namespace isc {
namespace dhcp { namespace dhcp {
isc::asiolink::IOServicePtr PgSqlConfigBackendImpl::io_service_ = isc::asiolink::IOServicePtr(); isc::asiolink::IOServicePtr PgSqlConfigBackendImpl::io_service_;
isc::asiolink::IOServicePtr PgSqlConfigBackendImpl::main_io_service_;
PgSqlTaggedStatement& PgSqlTaggedStatement&
PgSqlConfigBackendImpl::getStatement(size_t /* index */) const { PgSqlConfigBackendImpl::getStatement(size_t /* index */) const {

View File

@ -800,18 +800,6 @@ public:
return (parameters_); return (parameters_);
} }
/// @brief Sets IO service to be used by the PostgreSQL config backend.
///
/// @param IOService object, used for all ASIO operations.
static void setIOService(const isc::asiolink::IOServicePtr& io_service) {
io_service_ = io_service;
}
/// @brief Returns pointer to the IO service.
static isc::asiolink::IOServicePtr& getIOService() {
return (io_service_);
}
/// @brief Fetches the SQL statement for a given statement index. /// @brief Fetches the SQL statement for a given statement index.
/// ///
/// Derivations must override the implementation. The reference /// Derivations must override the implementation. The reference
@ -872,6 +860,34 @@ public:
/// @return Number of affected rows. /// @return Number of affected rows.
uint64_t updateDeleteQuery(size_t index, const db::PsqlBindArray& in_bindings); uint64_t updateDeleteQuery(size_t index, const db::PsqlBindArray& in_bindings);
/// @brief Get the hook I/O service.
///
/// @return the hook I/O service.
static isc::asiolink::IOServicePtr& getIOService() {
return (io_service_);
}
/// @brief Set the hook I/O service.
///
/// @param io_service the hook I/O service.
static void setIOService(isc::asiolink::IOServicePtr io_service) {
io_service_ = io_service;
}
/// @brief Get the main I/O service.
///
/// @return the main I/O service.
static isc::asiolink::IOServicePtr& getMainIOService() {
return (main_io_service_);
}
/// @brief Set the main I/O service.
///
/// @param io_service the main I/O service.
static void setMainIOService(isc::asiolink::IOServicePtr io_service) {
main_io_service_ = io_service;
}
/// @brief Represents connection to the PostgreSQL database. /// @brief Represents connection to the PostgreSQL database.
db::PgSqlConnection conn_; db::PgSqlConnection conn_;
@ -888,9 +904,12 @@ private:
/// @brief Connection parameters /// @brief Connection parameters
isc::db::DatabaseConnection::ParameterMap parameters_; isc::db::DatabaseConnection::ParameterMap parameters_;
/// @brief The IOService object, used for all ASIO operations. /// @brief The hook I/O service.
static isc::asiolink::IOServicePtr io_service_; static isc::asiolink::IOServicePtr io_service_;
/// @brief The main I/O service.
static isc::asiolink::IOServicePtr main_io_service_;
/// @brief Statement index of the SQL statement to use for fetching /// @brief Statement index of the SQL statement to use for fetching
/// last inserted id in a given table. /// last inserted id in a given table.
size_t last_insert_id_index_; size_t last_insert_id_index_;

View File

@ -12,11 +12,8 @@
#include <config.h> #include <config.h>
#include <cc/data.h> #include <dhcpsrv/testutils/lib_load_test_fixture.h>
#include <dhcpsrv/cfgmgr.h> #include <testutils/gtest_utils.h>
#include <hooks/hooks_manager.h>
#include <process/daemon.h>
#include <testutils/lib_load_test_fixture.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <errno.h> #include <errno.h>

View File

@ -19,8 +19,9 @@ namespace isc {
namespace run_script { namespace run_script {
IOServicePtr RunScriptImpl::io_service_; IOServicePtr RunScriptImpl::io_service_;
IOServicePtr RunScriptImpl::main_io_service_;
RunScriptImpl::RunScriptImpl() : name_(), sync_(false) { RunScriptImpl::RunScriptImpl() : io_context_(new IOService()), name_(), sync_(false) {
} }
void void

View File

@ -30,20 +30,6 @@ public:
/// @brief Destructor. /// @brief Destructor.
~RunScriptImpl() = default; ~RunScriptImpl() = default;
/// @brief Sets IO service to be used by the @ref ProcessSpawn instance.
///
/// @param io_service The IOService object, used for all ASIO operations.
static void setIOService(const isc::asiolink::IOServicePtr& io_service) {
io_service_ = io_service;
}
/// @brief Gets IO service to be used by the @ref ProcessSpawn instance.
///
/// @return The IOService object, used for all ASIO operations.
static isc::asiolink::IOServicePtr getIOService() {
return (io_service_);
}
/// @brief Extract boolean data and append to environment. /// @brief Extract boolean data and append to environment.
/// ///
/// @param value The value to be exported to target script environment. /// @param value The value to be exported to target script environment.
@ -256,7 +242,53 @@ public:
/// @brief This function parses and applies configuration parameters. /// @brief This function parses and applies configuration parameters.
void configure(isc::hooks::LibraryHandle& handle); void configure(isc::hooks::LibraryHandle& handle);
/// @brief Get the hook I/O service.
///
/// @return the hook I/O service.
isc::asiolink::IOServicePtr& getIOContext() {
return (io_context_);
}
/// @brief Set the hook I/O service.
///
/// @param io_service the hook I/O service.
void setIOContext(isc::asiolink::IOServicePtr io_service) {
io_context_ = io_service;
}
/// @brief Get the hook I/O service.
///
/// @return the hook I/O service.
static isc::asiolink::IOServicePtr& getIOService() {
return (io_service_);
}
/// @brief Set the hook I/O service.
///
/// @param io_service the hook I/O service.
static void setIOService(isc::asiolink::IOServicePtr io_service) {
io_service_ = io_service;
}
/// @brief Get the main I/O service.
///
/// @return the main I/O service.
static isc::asiolink::IOServicePtr& getMainIOService() {
return (main_io_service_);
}
/// @brief Set the main I/O service.
///
/// @param io_service the main I/O service.
static void setMainIOService(isc::asiolink::IOServicePtr io_service) {
main_io_service_ = io_service;
}
private: private:
/// @brief The IOService object, used for all ASIO operations.
isc::asiolink::IOServicePtr io_context_;
/// @brief Script name. /// @brief Script name.
std::string name_; std::string name_;
@ -267,8 +299,11 @@ private:
/// started. /// started.
bool sync_; bool sync_;
/// @brief The IOService object, used for all ASIO operations. /// @brief The hook I/O service.
static isc::asiolink::IOServicePtr io_service_; static isc::asiolink::IOServicePtr io_service_;
/// @brief The main I/O service.
static isc::asiolink::IOServicePtr main_io_service_;
}; };
/// @brief The type of shared pointers to Run Script implementations. /// @brief The type of shared pointers to Run Script implementations.

View File

@ -80,7 +80,18 @@ int load(LibraryHandle& handle) {
/// ///
/// @return always 0. /// @return always 0.
int unload() { int unload() {
if (RunScriptImpl::getMainIOService()) {
RunScriptImpl::getMainIOService()->unregisterExternalIOService(impl->getIOContext());
}
impl.reset(); impl.reset();
if (RunScriptImpl::getIOService()) {
RunScriptImpl::getIOService()->stop();
RunScriptImpl::getIOService()->restart();
try {
RunScriptImpl::getIOService()->poll();
} catch (...) {
}
}
RunScriptImpl::setIOService(IOServicePtr()); RunScriptImpl::setIOService(IOServicePtr());
LOG_INFO(run_script_logger, RUN_SCRIPT_UNLOAD); LOG_INFO(run_script_logger, RUN_SCRIPT_UNLOAD);
return (0); return (0);
@ -91,16 +102,16 @@ int unload() {
/// @param handle callout handle. /// @param handle callout handle.
int dhcp4_srv_configured(CalloutHandle& handle) { int dhcp4_srv_configured(CalloutHandle& handle) {
try { try {
isc::asiolink::IOServicePtr io_service; handle.getArgument("io_context", RunScriptImpl::getMainIOService());
handle.getArgument("io_context", io_service); if (!RunScriptImpl::getMainIOService()) {
if (!io_service) {
// Should not happen! // Should not happen!
handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP); handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP);
const string error("Error: io_context is null"); const string error("Error: io_context is null");
handle.setArgument("error", error); handle.setArgument("error", error);
return (1); return (1);
} }
RunScriptImpl::setIOService(io_service); RunScriptImpl::setIOService(impl->getIOContext());
RunScriptImpl::getMainIOService()->registerExternalIOService(impl->getIOContext());
} catch (const exception& ex) { } catch (const exception& ex) {
LOG_ERROR(run_script_logger, RUN_SCRIPT_LOAD_ERROR) LOG_ERROR(run_script_logger, RUN_SCRIPT_LOAD_ERROR)
@ -116,16 +127,16 @@ int dhcp4_srv_configured(CalloutHandle& handle) {
/// @param handle callout handle. /// @param handle callout handle.
int dhcp6_srv_configured(CalloutHandle& handle) { int dhcp6_srv_configured(CalloutHandle& handle) {
try { try {
isc::asiolink::IOServicePtr io_service; handle.getArgument("io_context", RunScriptImpl::getMainIOService());
handle.getArgument("io_context", io_service); if (!RunScriptImpl::getMainIOService()) {
if (!io_service) {
// Should not happen! // Should not happen!
handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP); handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_DROP);
const string error("Error: io_context is null"); const string error("Error: io_context is null");
handle.setArgument("error", error); handle.setArgument("error", error);
return (1); return (1);
} }
RunScriptImpl::setIOService(io_service); RunScriptImpl::setIOService(impl->getIOContext());
RunScriptImpl::getMainIOService()->registerExternalIOService(impl->getIOContext());
} catch (const exception& ex) { } catch (const exception& ex) {
LOG_ERROR(run_script_logger, RUN_SCRIPT_LOAD_ERROR) LOG_ERROR(run_script_logger, RUN_SCRIPT_LOAD_ERROR)

View File

@ -12,12 +12,8 @@
#include <config.h> #include <config.h>
#include <cc/data.h> #include <dhcpsrv/testutils/lib_load_test_fixture.h>
#include <dhcpsrv/cfgmgr.h>
#include <hooks/hooks_manager.h>
#include <process/daemon.h>
#include <testutils/gtest_utils.h> #include <testutils/gtest_utils.h>
#include <testutils/lib_load_test_fixture.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <errno.h> #include <errno.h>

View File

@ -18,98 +18,102 @@ namespace isc {
namespace asiolink { namespace asiolink {
class IOServiceImpl { class IOServiceImpl {
/// @brief Constructors and Destructor.
///
/// @note The copy constructor and the assignment operator are
/// intentionally defined as private, making this class non-copyable.
//@{
private: private:
IOServiceImpl(const IOService& source); IOServiceImpl(const IOService& source);
IOServiceImpl& operator=(const IOService& source); IOServiceImpl& operator=(const IOService& source);
public: public:
/// \brief The constructor /// @brief The constructor.
IOServiceImpl() : IOServiceImpl() :
io_service_(), io_service_(),
work_(new boost::asio::io_service::work(io_service_)) { work_(new boost::asio::io_service::work(io_service_)) {
}; };
/// \brief The destructor. /// @brief The destructor.
~IOServiceImpl() { ~IOServiceImpl() = default;
};
//@} //@}
/// \brief Start the underlying event loop. /// @brief Start the underlying event loop.
/// ///
/// This method does not return control to the caller until /// This method does not return control to the caller until
/// the \c stop() method is called via some handler. /// the @ref stop() method is called via some handler.
void run() { void run() {
io_service_.run(); io_service_.run();
}; };
/// \brief Run the underlying event loop for a single event. /// @brief Run the underlying event loop for a single event.
/// ///
/// This method return control to the caller as soon as the /// This method return control to the caller as soon as the
/// first handler has completed. (If no handlers are ready when /// first handler has completed. (If no handlers are ready when
/// it is run, it will block until one is.) /// it is run, it will block until one is.)
/// ///
/// \return The number of handlers that were executed. /// @return The number of handlers that were executed.
size_t runOne() { size_t runOne() {
return (static_cast<size_t>(io_service_.run_one())); return (static_cast<size_t>(io_service_.run_one()));
}; };
/// \brief Run the underlying event loop for a ready events. /// @brief Run the underlying event loop for a ready events.
/// ///
/// This method executes handlers for all ready events and returns. /// This method executes handlers for all ready events and returns.
/// It will return immediately if there are no ready events. /// It will return immediately if there are no ready events.
/// ///
/// \return The number of handlers that were executed. /// @return The number of handlers that were executed.
size_t poll() { size_t poll() {
return (static_cast<size_t>(io_service_.poll())); return (static_cast<size_t>(io_service_.poll()));
}; };
/// \brief Run the underlying event loop for a ready events. /// @brief Run the underlying event loop for a ready events.
/// ///
/// This method executes handlers for all ready events and returns. /// This method executes handlers for all ready events and returns.
/// It will return immediately if there are no ready events. /// It will return immediately if there are no ready events.
/// ///
/// \return The number of handlers that were executed. /// @return The number of handlers that were executed.
size_t pollOne() { size_t pollOne() {
return (static_cast<size_t>(io_service_.poll_one())); return (static_cast<size_t>(io_service_.poll_one()));
}; };
/// \brief Stop the underlying event loop. /// @brief Stop the underlying event loop.
/// ///
/// This will return the control to the caller of the \c run() method. /// This will return the control to the caller of the @ref run() method.
void stop() { void stop() {
io_service_.stop(); io_service_.stop();
} }
/// \brief Indicates if the IOService has been stopped. /// @brief Indicates if the IOService has been stopped.
/// ///
/// \return true if the IOService has been stopped, false otherwise. /// @return true if the IOService has been stopped, false otherwise.
bool stopped() const { bool stopped() const {
return (io_service_.stopped()); return (io_service_.stopped());
} }
/// \brief Restarts the IOService in preparation for a subsequent \c run() invocation. /// @brief Restarts the IOService in preparation for a subsequent @ref run() invocation.
void restart() { void restart() {
io_service_.reset(); io_service_.reset();
} }
/// \brief Removes IO service work object to let it finish running /// @brief Removes IO service work object to let it finish running
/// when all handlers have been invoked. /// when all handlers have been invoked.
void stopWork() { void stopWork() {
work_.reset(); work_.reset();
} }
/// \brief Return the native \c io_service object used in this wrapper. /// @brief Return the native @ref io_service object used in this wrapper.
/// ///
/// This is a short term work around to support other Kea modules /// This is a short term work around to support other Kea modules
/// that share the same \c io_service with the authoritative server. /// that share the same @ref io_service with the authoritative server.
/// It will eventually be removed once the wrapper interface is /// It will eventually be removed once the wrapper interface is
/// generalized. /// generalized.
boost::asio::io_service& getInternalIOService() { boost::asio::io_service& getInternalIOService() {
return (io_service_); return (io_service_);
} }
/// \brief Post a callback on the IO service /// @brief Post a callback on the IO service.
/// ///
/// \param callback The callback to be run on the IO service. /// @param callback The callback to be run on the IO service.
void post(const std::function<void ()>& callback) { void post(const std::function<void ()>& callback) {
io_service_.post(callback); io_service_.post(callback);
} }
@ -175,5 +179,25 @@ IOService::post(const std::function<void ()>& callback) {
return (io_impl_->post(callback)); return (io_impl_->post(callback));
} }
void
IOService::registerExternalIOService(IOServicePtr io_service) {
external_io_services_.push_back(io_service);
}
void
IOService::unregisterExternalIOService(IOServicePtr io_service) {
auto it = std::find(external_io_services_.begin(), external_io_services_.end(), io_service);
if (it != external_io_services_.end()) {
external_io_services_.erase(it);
}
}
void
IOService::pollExternalIOServices() {
for (auto& io_service : external_io_services_) {
io_service->poll();
}
}
} // namespace asiolink } // namespace asiolink
} // namespace isc } // namespace isc

View File

@ -10,6 +10,7 @@
#include <boost/version.hpp> #include <boost/version.hpp>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <functional> #include <functional>
#include <list>
namespace boost { namespace boost {
namespace asio { namespace asio {
@ -26,84 +27,89 @@ namespace isc {
namespace asiolink { namespace asiolink {
class IOServiceImpl; class IOServiceImpl;
class IOService;
/// \brief The \c IOService class is a wrapper for the ASIO \c io_service /// @brief Defines a smart pointer to an IOService instance.
typedef boost::shared_ptr<IOService> IOServicePtr;
/// @brief The @ref IOService class is a wrapper for the ASIO @ref io_service
/// class. /// class.
///
class IOService { class IOService {
/// @brief Constructors and Destructor.
/// ///
/// \name Constructors and Destructor /// @note The copy constructor and the assignment operator are
///
/// Note: The copy constructor and the assignment operator are
/// intentionally defined as private, making this class non-copyable. /// intentionally defined as private, making this class non-copyable.
//@{ //@{
private: private:
IOService(const IOService& source); IOService(const IOService& source);
IOService& operator=(const IOService& source); IOService& operator=(const IOService& source);
public: public:
/// \brief The constructor /// @brief The constructor.
IOService(); IOService();
/// \brief The destructor.
/// @brief The destructor.
~IOService(); ~IOService();
//@} //@}
/// \brief Start the underlying event loop. /// @brief Start the underlying event loop.
/// ///
/// This method does not return control to the caller until /// This method does not return control to the caller until
/// the \c stop() method is called via some handler. /// the @ref stop() method is called via some handler.
void run(); void run();
/// \brief Run the underlying event loop for a single event. /// @brief Run the underlying event loop for a single event.
/// ///
/// This method return control to the caller as soon as the /// This method return control to the caller as soon as the
/// first handler has completed. (If no handlers are ready when /// first handler has completed. (If no handlers are ready when
/// it is run, it will block until one is.) /// it is run, it will block until one is.)
/// ///
/// \return The number of handlers that were executed. /// @return The number of handlers that were executed.
size_t runOne(); size_t runOne();
/// \brief Run the underlying event loop for a ready events. /// @brief Run the underlying event loop for a ready events.
/// ///
/// This method executes handlers for all ready events and returns. /// This method executes handlers for all ready events and returns.
/// It will return immediately if there are no ready events. /// It will return immediately if there are no ready events.
/// ///
/// \return The number of handlers that were executed. /// @return The number of handlers that were executed.
size_t poll(); size_t poll();
/// \brief Run the underlying event loop for a ready events. /// @brief Run the underlying event loop for a ready events.
/// ///
/// This method executes handlers for all ready events and returns. /// This method executes handlers for all ready events and returns.
/// It will return immediately if there are no ready events. /// It will return immediately if there are no ready events.
/// ///
/// \return The number of handlers that were executed. /// @return The number of handlers that were executed.
size_t pollOne(); size_t pollOne();
/// \brief Stop the underlying event loop. /// @brief Stop the underlying event loop.
/// ///
/// This will return the control to the caller of the \c run() method. /// This will return the control to the caller of the @ref run() method.
void stop(); void stop();
/// \brief Indicates if the IOService has been stopped. /// @brief Indicates if the IOService has been stopped.
/// ///
/// \return true if the IOService has been stopped, false otherwise. /// @return true if the IOService has been stopped, false otherwise.
bool stopped() const; bool stopped() const;
/// \brief Restarts the IOService in preparation for a subsequent \c run() invocation. /// @brief Restarts the IOService in preparation for a subsequent @ref run() invocation.
void restart(); void restart();
/// \brief Removes IO service work object to let it finish running /// @brief Removes IO service work object to let it finish running
/// when all handlers have been invoked. /// when all handlers have been invoked.
void stopWork(); void stopWork();
/// \brief Return the native \c io_service object used in this wrapper. /// @brief Return the native @ref io_service object used in this wrapper.
/// ///
/// This is a short term work around to support other Kea modules /// This is a short term work around to support other Kea modules
/// that share the same \c io_service with the authoritative server. /// that share the same @ref io_service with the authoritative server.
/// It will eventually be removed once the wrapper interface is /// It will eventually be removed once the wrapper interface is
/// generalized. /// generalized.
///
/// @return The internal io_service object.
boost::asio::io_service& getInternalIOService(); boost::asio::io_service& getInternalIOService();
/// \brief Post a callback to the end of the queue. /// @brief Post a callback to the end of the queue.
/// ///
/// Requests the callback be called sometime later. It is not guaranteed /// Requests the callback be called sometime later. It is not guaranteed
/// by the underlying asio, but it can reasonably be expected the callback /// by the underlying asio, but it can reasonably be expected the callback
@ -114,12 +120,39 @@ public:
/// by small bits that are called from time to time). /// by small bits that are called from time to time).
void post(const std::function<void ()>& callback); void post(const std::function<void ()>& callback);
private: /// @brief Register external IOService.
boost::shared_ptr<IOServiceImpl> io_impl_; ///
}; /// @param io_service The external IOService to be registered.
void registerExternalIOService(IOServicePtr io_service);
/// @brief Defines a smart pointer to an IOService instance. /// @brief Unregister external IOService.
typedef boost::shared_ptr<IOService> IOServicePtr; ///
/// @param io_service The external IOService to be unregistered.
void unregisterExternalIOService(IOServicePtr io_service);
/// @brief Clear the list of external IOService objects.
void clearExternalIOServices() {
external_io_services_.clear();
}
/// @brief The count of external IOService objects.
///
// @return The count of external IOService objects.
size_t externalIOServiceCount() {
return (external_io_services_.size());
}
/// @brief Poll external IOService objects.
void pollExternalIOServices();
private:
/// @brief The implementation.
boost::shared_ptr<IOServiceImpl> io_impl_;
/// @brief The list of external IOService objects.
std::list<IOServicePtr> external_io_services_;
};
} // namespace asiolink } // namespace asiolink
} // namespace isc } // namespace isc

View File

@ -45,4 +45,105 @@ TEST(IOService, post) {
EXPECT_EQ(3, called[2]); EXPECT_EQ(3, called[2]);
} }
TEST(IOService, externalIOService) {
IOServicePtr main_io_service(new IOService());
EXPECT_EQ(main_io_service->externalIOServiceCount(), 0);
int one_io_callback_count = 0;
auto one_f = [&one_io_callback_count] () {
one_io_callback_count++;
};
int two_io_callback_count = 0;
auto two_f = [&two_io_callback_count] () {
two_io_callback_count++;
};
{
IOServicePtr one_io_service(new IOService());
one_io_service->post(one_f);
IOServicePtr two_io_service(new IOService());
two_io_service->post(two_f);
main_io_service->pollExternalIOServices();
EXPECT_EQ(one_io_callback_count, 0);
EXPECT_EQ(two_io_callback_count, 0);
main_io_service->registerExternalIOService(one_io_service);
EXPECT_EQ(main_io_service->externalIOServiceCount(), 1);
main_io_service->registerExternalIOService(two_io_service);
EXPECT_EQ(main_io_service->externalIOServiceCount(), 2);
main_io_service->pollExternalIOServices();
EXPECT_EQ(one_io_callback_count, 1);
EXPECT_EQ(two_io_callback_count, 1);
one_io_service->post(one_f);
two_io_service->post(two_f);
}
EXPECT_EQ(main_io_service->externalIOServiceCount(), 2);
main_io_service->pollExternalIOServices();
EXPECT_EQ(one_io_callback_count, 2);
EXPECT_EQ(two_io_callback_count, 2);
main_io_service->clearExternalIOServices();
EXPECT_EQ(main_io_service->externalIOServiceCount(), 0);
IOServicePtr one_io_service(new IOService());
one_io_service->post(one_f);
IOServicePtr two_io_service(new IOService());
two_io_service->post(two_f);
main_io_service->pollExternalIOServices();
EXPECT_EQ(one_io_callback_count, 2);
EXPECT_EQ(two_io_callback_count, 2);
main_io_service->registerExternalIOService(one_io_service);
EXPECT_EQ(main_io_service->externalIOServiceCount(), 1);
main_io_service->pollExternalIOServices();
EXPECT_EQ(one_io_callback_count, 3);
EXPECT_EQ(two_io_callback_count, 2);
one_io_service->post(one_f);
two_io_service->post(two_f);
main_io_service->registerExternalIOService(two_io_service);
EXPECT_EQ(main_io_service->externalIOServiceCount(), 2);
main_io_service->pollExternalIOServices();
EXPECT_EQ(one_io_callback_count, 4);
EXPECT_EQ(two_io_callback_count, 4);
one_io_service->post(one_f);
two_io_service->post(two_f);
main_io_service->unregisterExternalIOService(one_io_service);
EXPECT_EQ(main_io_service->externalIOServiceCount(), 1);
main_io_service->pollExternalIOServices();
EXPECT_EQ(one_io_callback_count, 4);
EXPECT_EQ(two_io_callback_count, 5);
one_io_service->post(one_f);
two_io_service->post(two_f);
main_io_service->unregisterExternalIOService(two_io_service);
EXPECT_EQ(main_io_service->externalIOServiceCount(), 0);
main_io_service->pollExternalIOServices();
EXPECT_EQ(one_io_callback_count, 4);
EXPECT_EQ(two_io_callback_count, 5);
EXPECT_NO_THROW(main_io_service->registerExternalIOService(main_io_service));
EXPECT_EQ(main_io_service->externalIOServiceCount(), 1);
main_io_service->post(one_f);
main_io_service->pollExternalIOServices();
EXPECT_EQ(one_io_callback_count, 5);
EXPECT_EQ(two_io_callback_count, 5);
EXPECT_NO_THROW(main_io_service->unregisterExternalIOService(main_io_service));
EXPECT_EQ(main_io_service->externalIOServiceCount(), 0);
main_io_service->pollExternalIOServices();
EXPECT_EQ(one_io_callback_count, 5);
EXPECT_EQ(two_io_callback_count, 5);
}
} }

View File

@ -16,6 +16,7 @@ libdhcpsrvtest_la_SOURCES = concrete_lease_mgr.cc concrete_lease_mgr.h
libdhcpsrvtest_la_SOURCES += config_result_check.cc config_result_check.h libdhcpsrvtest_la_SOURCES += config_result_check.cc config_result_check.h
libdhcpsrvtest_la_SOURCES += dhcp4o6_test_ipc.cc dhcp4o6_test_ipc.h libdhcpsrvtest_la_SOURCES += dhcp4o6_test_ipc.cc dhcp4o6_test_ipc.h
libdhcpsrvtest_la_SOURCES += host_data_source_utils.cc host_data_source_utils.h libdhcpsrvtest_la_SOURCES += host_data_source_utils.cc host_data_source_utils.h
libdhcpsrvtest_la_SOURCES += lib_load_test_fixture.h
libdhcpsrvtest_la_SOURCES += memory_host_data_source.cc memory_host_data_source.h libdhcpsrvtest_la_SOURCES += memory_host_data_source.cc memory_host_data_source.h
libdhcpsrvtest_la_SOURCES += test_utils.cc test_utils.h libdhcpsrvtest_la_SOURCES += test_utils.cc test_utils.h
libdhcpsrvtest_la_SOURCES += generic_backend_unittest.cc generic_backend_unittest.h libdhcpsrvtest_la_SOURCES += generic_backend_unittest.cc generic_backend_unittest.h

View File

@ -9,7 +9,9 @@
#include <cc/data.h> #include <cc/data.h>
#include <dhcpsrv/cfgmgr.h> #include <dhcpsrv/cfgmgr.h>
#include <hooks/hooks_manager.h>
#include <process/daemon.h> #include <process/daemon.h>
#include <testutils/gtest_utils.h> #include <testutils/gtest_utils.h>
namespace isc { namespace isc {

View File

@ -415,6 +415,8 @@ DControllerBase::configFromFile() {
// case of problems. // case of problems.
storage->applyLoggingCfg(); storage->applyLoggingCfg();
getIOService()->clearExternalIOServices();
answer = updateConfig(module_config); answer = updateConfig(module_config);
// In all cases the right logging configuration is in the context. // In all cases the right logging configuration is in the context.
process_->getCfgMgr()->getContext()->applyLoggingCfg(); process_->getCfgMgr()->getContext()->applyLoggingCfg();
@ -655,6 +657,8 @@ DControllerBase::configSetHandler(const std::string&, ConstElementPtr args) {
// case of problems. // case of problems.
storage->applyLoggingCfg(); storage->applyLoggingCfg();
getIOService()->clearExternalIOServices();
ConstElementPtr answer = updateConfig(module_config); ConstElementPtr answer = updateConfig(module_config);
int rcode = 0; int rcode = 0;
parseAnswer(rcode, answer); parseAnswer(rcode, answer);
@ -844,6 +848,8 @@ DControllerBase::~DControllerBase() {
LOG_ERROR(dctl_logger, DCTL_UNLOAD_LIBRARIES_ERROR).arg(msg); LOG_ERROR(dctl_logger, DCTL_UNLOAD_LIBRARIES_ERROR).arg(msg);
} }
getIOService()->clearExternalIOServices();
io_signal_set_.reset(); io_signal_set_.reset();
try { try {
getIOService()->poll(); getIOService()->poll();

View File

@ -16,7 +16,6 @@ libkea_testutils_la_SOURCES += unix_control_client.cc unix_control_client.h
libkea_testutils_la_SOURCES += user_context_utils.cc user_context_utils.h libkea_testutils_la_SOURCES += user_context_utils.cc user_context_utils.h
libkea_testutils_la_SOURCES += gtest_utils.h libkea_testutils_la_SOURCES += gtest_utils.h
libkea_testutils_la_SOURCES += multi_threading_utils.h libkea_testutils_la_SOURCES += multi_threading_utils.h
libkea_testutils_la_SOURCES += lib_load_test_fixture.h
libkea_testutils_la_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) libkea_testutils_la_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
libkea_testutils_la_LIBADD = $(top_builddir)/src/lib/asiolink/libkea-asiolink.la libkea_testutils_la_LIBADD = $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
libkea_testutils_la_LIBADD += $(top_builddir)/src/lib/dns/libkea-dns++.la libkea_testutils_la_LIBADD += $(top_builddir)/src/lib/dns/libkea-dns++.la

319
tools/check-lib-dependencies.sh Executable file
View File

@ -0,0 +1,319 @@
#!/bin/bash
# extract folder name containing file
#
# param ${1} file name
# return folder name
extract_folder_name() {
# return name of the file until last '/'
echo "$(echo "${1}" | rev | cut -d '/' -f 2- | rev)"
}
# extract all includes found in source files found in the same folder as specified Makefile.am
#
# param ${1} path to a Makefile.am
# return all dependencies libs in the order of compilation
extract_includes() {
# extract folder name from current library Makefile.am
CURRENT_FOLDER=$(extract_folder_name "${1}")"/"
# select only files in current folder
SEARCH_FILES=$(echo "${FILE_LIST}" | grep "${CURRENT_FOLDER}")
# select all lines containing '#include ' directive
RAW_INCLUDES_LIST=$(echo "${SEARCH_FILES}" | xargs grep "^#include " 2>/dev/null)
# filter only included dependencies found in other libraries by using the form 'other_lib_name/header_file.h'
# to do this it is required to select the string between '<' and '>', searching for '/' character and returning the name until last '/'
RAW_INCLUDES_LIST=$(echo "${RAW_INCLUDES_LIST}" | cut -d "#" -f 2 | tr "\"" " " | cut -d "<" -f 2 | cut -d ">" -f 1 | grep "\/" | rev | cut -d "/" -f 2 | rev | sort | uniq)
# filter includes that are not compiled by the project's Makefiles
INCLUDES_LIST=
for i in ${LIBRARIES_LIST}; do
for j in ${RAW_INCLUDES_LIST}; do
if test "${j}" = "${i}"; then
INCLUDES_LIST="${i} ${INCLUDES_LIST}"
break
fi
done
done
# remove empty spaces
INCLUDES_LIST=$(echo ${INCLUDES_LIST} | tr -s " ")
# order dependencies in the order of compilation
FILTERED_INCLUDES_LIST=
for i in ${LIBRARIES_LIST}; do
if test $(echo "${INCLUDES_LIST}" | grep "\b${i}\b" | wc -l) -ne 0; then
FILTERED_INCLUDES_LIST="${i} ${FILTERED_INCLUDES_LIST}"
fi
done
echo "${FILTERED_INCLUDES_LIST}"
}
# extract all header only files and headers and source files found in the external library required by specified library
# param ${1} name of the current library
# param ${2} name of the external dependency library required by current library
# return the list of header only files as 'HEADERS: heaser1.h header2.h' and header and source files as 'HEADERS_AND_SOURCES: source1.h source1.cc source2.h source2.cpp'
extract_non_include_files() {
# extract folder name for current library Makefile.am
CURRENT_FOLDER=$(extract_folder_name "src/lib/${1}/Makefile.am")"/"
# extract folder name for external dependency library Makefile.am
EXTERNAL_FOLDER=$(extract_folder_name "src/lib/${2}/Makefile.am")"/"
# select only files in current folder
SEARCH_FILES=$(echo "${FILE_LIST}" | grep "${CURRENT_FOLDER}")
HEADERS_LIST=
NON_HEADERS_LIST=
# select all lines containing '#include ' directive
RAW_INCLUDES_LIST=$(echo "${SEARCH_FILES}" | xargs grep "^#include " 2>/dev/null)
# filter only included headers found in other libraries by using the form 'other_lib_name/header_file.h'
# to do this it is required to select the string between '<' and '>', searching for '/' character, search for the extension marker '.' and returning the name after last '/'
RAW_INCLUDES_LIST=$(echo "${RAW_INCLUDES_LIST}" | cut -d "#" -f 2 | tr "\"" " " | cut -d "<" -f 2 | cut -d ">" -f 1 | grep "\/" | grep "\b${2}\b" | cut -d "/" -f 2 | grep "\." | sort | uniq)
# select only files in dependency library folder and strip full path
RELATIVE_SEARCH_FILES=$(echo "${FILE_LIST}" | grep "${EXTERNAL_FOLDER}" | sed -e "s#${REPO_FOLDER}${EXTERNAL_FOLDER}##g")
# search for the header file but also for source files
for i in ${RAW_INCLUDES_LIST}; do
# filter by name only (no extension)
FILTER=$(echo "${i}" | cut -d "." -f 1)
# filter non header files with exact name of the header file without the extension
NON_HEADER=$(echo "${RELATIVE_SEARCH_FILES}" | grep "\b${FILTER}\." | grep -v "${i}")
if test $(echo "${NON_HEADER}" | wc -w) -ne 0; then
# append header and source file names
NON_HEADERS_LIST="${i} ${NON_HEADER} ${NON_HEADERS_LIST}"
else
# append header only file name
HEADERS_LIST="${i} ${HEADERS_LIST}"
fi
done
# sort header only files
HEADERS_LIST=$(echo ${HEADERS_LIST} | tr -s " " | sort | uniq)
# sort header and source files
NON_HEADERS_LIST=$(echo ${NON_HEADERS_LIST} | tr -s " " | sort | uniq)
echo "HEADERS_AND_SOURCES:${NON_HEADERS_LIST}"
echo "HEADERS:${HEADERS_LIST}"
}
# extract all valid dependencies of a specified library
#
# param ${1} list of all libraries in the reverse compilation order
# param ${2} library name for which the dependency list is computed
# return the list of dependencies for specified library in the reverse compilation order
extract_dependencies() {
echo "${1}" | grep -Eo "\b${2}\b.*$"
}
# extract computed dependency for specified library
#
# param ${1} library name for which the dependency list is retrieved
# param ${2} library path for which the dependency list is retrieved
# return stored value of computed dependencies or 'NONE' if dependencies have not been computed yet
extract_computed_dependencies() {
PATH_TO_NAME=$(echo "${2}" | tr -s "/" "_")
NAME="COMPUTED_DEPENDENCIES_${PATH_TO_NAME}_${1}"
if test -n "${!NAME+x}"; then
echo "${!NAME}"
else
echo "NONE"
fi
}
# extract library directive
#
# param ${1} artifact path
extract_library_directive() {
ARTIFACT_PATH="${1}"
echo `cat ${ARTIFACT_PATH}/Makefile.am | grep "LIBADD\|LDADD" | sort | tr -s ' ' | cut -d " " -f 1 | sort -u`
}
# extract library name
#
# param ${1} artifact path
extract_library_name() {
ARTIFACT_PATH="${1}"
echo `cat ${ARTIFACT_PATH}/Makefile.am | grep "LIBRARIES" | tr -s ' ' | cut -d " " -f 3`
}
# compute artifact dependencies
#
# param ${1} artifact name
# param ${2} artifact path
compute_dependencies() {
ARTIFACT="${1}"
ARTIFACT_PATH="${2}"
echo ""
echo "########################################"
echo "### ${ARTIFACT_PATH}/${ARTIFACT}"
echo "########################################"
echo ""
# all valid dependencies that can be added by each dependency library
echo "${ARTIFACT_PATH}/${ARTIFACT} valid dependencies:"
echo "${VALID_LIST}"
# detect dependencies errors by searching for dependencies that are compiled after the current library and can generate missing symbols
NON_RECURSIVE_BASE_DEPENDENCIES=
for j in ${BASE_DEPENDENCIES}; do
# only add the dependency if it is in the valid dependencies list to prevent infinite recursion and log the error otherwise
if test $(echo "${VALID_LIST}" | grep "\b${j}\b" | wc -l) -eq 0; then
# search for external header and source files
INVALID_EXTERNAL_DEPENDENCIES=$(extract_non_include_files "${ARTIFACT}" "${j}")
# filter header only external files
EXTERNAL_HEADERS=$(echo "${INVALID_EXTERNAL_DEPENDENCIES}" | grep "HEADERS:" | cut -d ":" -f 2)
# filter header and source external files
EXTERNAL_ALL=$(echo "${INVALID_EXTERNAL_DEPENDENCIES}" | grep "HEADERS_AND_SOURCES:" | cut -d ":" -f 2)
echo "### ERROR ### dependencies ERROR for ${ARTIFACT_PATH}/${ARTIFACT} on ${j} with:"
# if there are any header only external files
if test $(echo "${EXTERNAL_ALL}" | wc -w) -ne 0; then
echo "non header only files: ${EXTERNAL_ALL}"
fi
# if there are any header and source external files
if test $(echo "${EXTERNAL_HEADERS}" | wc -w) -ne 0; then
echo "header only files: ${EXTERNAL_HEADERS}"
fi
else
# don't add current library to it's dependencies list
if test ${j} != ${ARTIFACT}; then
NON_RECURSIVE_BASE_DEPENDENCIES="${NON_RECURSIVE_BASE_DEPENDENCIES} ${j}"
fi
fi
done
# all found dependencies in the reverse compilation order
BASE_DEPENDENCIES=$(echo "${BASE_DEPENDENCIES}" | xargs)
# all found and valid dependencies in the reverse compilation order
NON_RECURSIVE_BASE_DEPENDENCIES=$(echo "${NON_RECURSIVE_BASE_DEPENDENCIES}" | xargs)
echo "${ARTIFACT_PATH}/${ARTIFACT} base dependencies:"
echo "${BASE_DEPENDENCIES}"
echo "${ARTIFACT_PATH}/${ARTIFACT} non recursive dependencies:"
echo "${NON_RECURSIVE_BASE_DEPENDENCIES}"
# minimum set of dependencies for current library
DEPENDENCIES=
for j in ${NON_RECURSIVE_BASE_DEPENDENCIES}; do
NEW_DEPENDENCIES=$(extract_computed_dependencies "${j}" "src/lib")
if test "${NEW_DEPENDENCIES}" == "NONE"; then
echo "### ERROR ### computed dependency not found for ${j}"
else
DEPENDENCIES="${NEW_DEPENDENCIES} ${DEPENDENCIES}"
fi
done
DEPENDENCIES=$(echo "${DEPENDENCIES} ${NON_RECURSIVE_BASE_DEPENDENCIES}" | tr -s " " "\n" | sort | uniq | xargs)
# order dependencies in the order of compilation
SORTED_DEPENDENCIES=
for j in ${LIBRARIES_LIST}; do
if test $(echo "${DEPENDENCIES}" | grep "\b${j}\b" | wc -l) -ne 0; then
SORTED_DEPENDENCIES="${j} ${SORTED_DEPENDENCIES}"
fi
done
echo "${ARTIFACT_PATH}/${ARTIFACT} minimum dependencies:"
echo "${SORTED_DEPENDENCIES}"
echo ""
echo "++++++++++++++++++++++++++++++++++++++++"
ARTIFACT_DIRECTIVE=$(extract_library_directive ${ARTIFACT_PATH}/${ARTIFACT})
for j in ${SORTED_DEPENDENCIES}; do
DEPENDENCY_LIBRARY_NAME=$(extract_library_name "src/lib/${j}")
echo "${ARTIFACT_DIRECTIVE} += \$(top_builddir)/src/lib/${j}/${DEPENDENCY_LIBRARY_NAME}"
done
echo "++++++++++++++++++++++++++++++++++++++++"
echo "########################################"
echo ""
}
# if wrong number of parameters print usage
if test ${#} -ne 1; then
echo "Usage: ${0} path/to/kea/repo"
exit
fi
# folder containing full repo
REPO_FOLDER=${1}
if test $(echo -n ${REPO_FOLDER} | tail -c 1) != "/"; then
REPO_FOLDER="${REPO_FOLDER}/"
fi
# filter all Makefile.am files
MAKEFILES_LIST=$(find ${REPO_FOLDER} | grep "Makefile\.am" | sed -e "s#${REPO_FOLDER}##g" | grep "src\/" | sort)
# if no Makefile.am found exit
if test -z "${MAKEFILES_LIST}"; then
echo "invalid repo path: no Makefile.am file found"
exit
fi
echo "list of Makefile.am:"
echo "${MAKEFILES_LIST}"
# base Makefile.am for all sources is in src/lib/Makefile.am
BASE_MAKEFILE=$(echo "${MAKEFILES_LIST}" | grep "src\/lib\/Makefile.am")
# if no src/lib/Makefile.am found exit
if test -z ${BASE_MAKEFILE}; then
echo "invalid repo path: no src/lib/Makefile.am file found"
exit
fi
echo "base Makefile.am:"
echo "${BASE_MAKEFILE}"
# generate the list of libraries in the compilation order
LIBRARIES_LIST=
RAW_LIBRARIES_LIST=$(cat "${REPO_FOLDER}${BASE_MAKEFILE}" | grep "SUBDIRS")
for i in ${RAW_LIBRARIES_LIST}; do
LIBRARIES_LIST="${LIBRARIES_LIST} $(echo ${i} | grep -v "SUBDIRS" | grep -v '=')"
done
# remove empty spaces
LIBRARIES_LIST=$(echo "${LIBRARIES_LIST}" | tr -s ' ' | xargs)
# generate the list of libraries in the reverse compilation order
REVERSE_LIBRARIES_LIST=
for i in ${LIBRARIES_LIST}; do
REVERSE_LIBRARIES_LIST="${i} ${REVERSE_LIBRARIES_LIST}"
done
echo "list of libraries:"
echo "${LIBRARIES_LIST}"
echo "reverse list of libraries:"
echo "${REVERSE_LIBRARIES_LIST}"
# filter all files of interest ignoring irrelevant ones
# ignore .git, .libs, .deps doc folders and .o .lo .Plo .Po .gcno .gcda .m4 .dox .json .mes files
FILE_LIST=$(find "${REPO_FOLDER}" 2>/dev/null | grep -v "\.git" | grep -v "\/\.libs\/" | grep -v "\.o$" | grep -v "\/\.deps\/" | grep -v "\.lo$" | grep -v "\.Plo$" | grep -v "\.Po$" | grep -v "\.gcno$" | grep -v "gcda" | grep -v "\.m4$" | grep -v "\.dox$" | grep -v "\.json$" | grep -v "\/doc\/" | grep -v "\.mes$" | sort)
#echo "files:"
#echo "${FILE_LIST}"
BASE_LIBRARIES_MAKEFILES=
# generate the list of dependencies for all libraries in src/lib
for i in ${LIBRARIES_LIST}; do
# generate current library Makefile.am path
BASE_LIBRARIES_MAKEFILES="${BASE_LIBRARIES_MAKEFILES} src/lib/${i}/Makefile.am"
# extract dependencies found in the library folder
BASE_DEPENDENCIES=$(extract_includes "src/lib/${i}/Makefile.am")
# generate the list of valid dependencies for the current library (take compilation order into account)
VALID_LIST=$(extract_dependencies "${REVERSE_LIBRARIES_LIST}" "${i}")
compute_dependencies "${i}" "src/lib"
PATH_TO_NAME=$(echo "src/lib" | tr -s "/" "_")
declare COMPUTED_DEPENDENCIES_${PATH_TO_NAME}_${i}="${SORTED_DEPENDENCIES}"
done
# remove empty spaces
BASE_LIBRARIES_MAKEFILES=$(echo "${BASE_LIBRARIES_MAKEFILES}" | xargs | tr -s " " "\n")
echo "base Makefiles.am files:"
echo "${BASE_LIBRARIES_MAKEFILES}"
OTHER_MAKEFILES=$(echo "${MAKEFILES_LIST}" | tr -s " " "\n" | grep -v "src/lib/" | grep -v "src/share/" | grep -v "src/Makefile.am")
# remove empty spaces
OTHER_MAKEFILES=$(echo "${OTHER_MAKEFILES}" | xargs | tr -s " " "\n")
echo "remaining Makefile.am files:"
echo "${OTHER_MAKEFILES}"
for i in ${OTHER_MAKEFILES}; do
# extract dependencies found in the artifact folder
BASE_DEPENDENCIES=$(extract_includes "${i}")
# generate the list of valid dependencies for the current artifact (take compilation order into account)
VALID_LIST="${REVERSE_LIBRARIES_LIST}"
ARTIFACT=$(echo "${i}" | rev | cut -d "/" -f 2 | rev)
ARTIFACT_PATH=$(echo "${i}" | rev | cut -d "/" -f 3- | rev)
compute_dependencies "${ARTIFACT}" "${ARTIFACT_PATH}"
PATH_TO_NAME=$(echo "${ARTIFACT_PATH}" | tr -s "/" "_")
declare COMPUTED_DEPENDENCIES_${PATH_TO_NAME}_${ARTIFACT}="${SORTED_DEPENDENCIES}"
done
exit