-// Copyright (C) 2017-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2017-2019 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
#include <ha_log.h>
#include <asiolink/io_service.h>
#include <cc/command_interpreter.h>
+#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/network_state.h>
+#include <exceptions/exceptions.h>
#include <hooks/hooks.h>
+#include <process/daemon.h>
namespace isc {
namespace ha {
using namespace isc::config;
using namespace isc::data;
+using namespace isc::dhcp;
using namespace isc::ha;
using namespace isc::hooks;
+using namespace isc::process;
extern "C" {
}
try {
+ // Make the hook library not loadable by d2 or ca.
+ uint16_t family = CfgMgr::instance().getFamily();
+ const std::string& proc_name = Daemon::getProcName();
+ if (family == AF_INET) {
+ if (proc_name != "kea-dhcp4") {
+ isc_throw(isc::Unexpected, "Bad process name: " << proc_name
+ << ", expected kea-dhcp4");
+ }
+ } else {
+ if (proc_name != "kea-dhcp6") {
+ isc_throw(isc::Unexpected, "Bad process name: " << proc_name
+ << ", expected kea-dhcp6");
+ }
+ }
+
impl = boost::make_shared<HAImpl>();
impl->configure(config);
--- /dev/null
+SUBDIRS = .
+
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+AM_CPPFLAGS += -I$(top_builddir)/src/hooks/dhcp/high_availability -I$(top_srcdir)/src/hooks/dhcp/high_availability
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CPPFLAGS += -DHA_LIB_SO=\"$(abs_top_builddir)/src/hooks/dhcp/high_availability/.libs/libdhcp_ha.so\"
+AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
+
+AM_CXXFLAGS = $(KEA_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+# Unit test data files need to get installed.
+EXTRA_DIST =
+
+CLEANFILES = *.gcno *.gcda
+
+# TESTS_ENVIRONMENT = $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
+LOG_COMPILER = $(LIBTOOL)
+AM_LOG_FLAGS = --mode=execute
+
+TESTS =
+if HAVE_GTEST
+TESTS += ha_unittests
+
+ha_unittests_SOURCES = run_unittests.cc
+ha_unittests_SOURCES += load_unload_unittests.cc
+
+ha_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES)
+
+ha_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) $(GTEST_LDFLAGS)
+
+ha_unittests_CXXFLAGS = $(AM_CXXFLAGS)
+
+ha_unittests_LDADD = $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la
+ha_unittests_LDADD += $(top_builddir)/src/lib/process/libkea-process.la
+ha_unittests_LDADD += $(top_builddir)/src/lib/eval/libkea-eval.la
+ha_unittests_LDADD += $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la
+ha_unittests_LDADD += $(top_builddir)/src/lib/stats/libkea-stats.la
+ha_unittests_LDADD += $(top_builddir)/src/lib/config/libkea-cfgclient.la
+ha_unittests_LDADD += $(top_builddir)/src/lib/http/libkea-http.la
+ha_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la
+ha_unittests_LDADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la
+ha_unittests_LDADD += $(top_builddir)/src/lib/cc/libkea-cc.la
+ha_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
+ha_unittests_LDADD += $(top_builddir)/src/lib/dns/libkea-dns++.la
+ha_unittests_LDADD += $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la
+ha_unittests_LDADD += $(top_builddir)/src/lib/log/libkea-log.la
+ha_unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la
+ha_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
+ha_unittests_LDADD += $(LOG4CPLUS_LIBS)
+ha_unittests_LDADD += $(CRYPTO_LIBS)
+ha_unittests_LDADD += $(BOOST_LIBS)
+ha_unittests_LDADD += $(GTEST_LDADD)
+endif
+noinst_PROGRAMS = $(TESTS)
--- /dev/null
+// Copyright (C) 2019 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+/// @file This file contains tests which exercise the load and unload
+/// functions in the high availability hook library. In order to test
+/// the load function, one must be able to pass it hook library
+/// parameters. The the only way to populate these parameters is by
+/// actually loading the library via HooksManager::loadLibraries().
+
+#include <config.h>
+
+#include <cc/data.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <hooks/hooks_manager.h>
+#include <process/daemon.h>
+
+#include <gtest/gtest.h>
+#include <errno.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::hooks;
+using namespace isc::data;
+using namespace isc::dhcp;
+using namespace isc::process;
+
+namespace {
+
+/// @brief Test fixture for testing loading and unloading the HA library
+class LibLoadTest : public ::testing::Test {
+public:
+ /// @brief Constructor
+ LibLoadTest() {
+ reset();
+ }
+
+ /// @brief Destructor
+ /// Removes files that may be left over from previous tests
+ virtual ~LibLoadTest() {
+ reset();
+ }
+
+ /// @brief Removes files that may be left over from previous tests
+ virtual void reset() {
+ HooksManager::unloadLibraries();
+ }
+
+ void addLib(const std::string& lib, ConstElementPtr params) {
+ libraries_.push_back(make_pair(lib, params));
+ }
+
+ bool loadLibs() {
+ return (HooksManager::loadLibraries(libraries_));
+ }
+
+ void unloadLibs() {
+ EXPECT_NO_THROW(HooksManager::unloadLibraries());
+ }
+
+ /// @brief Return HA configuration with three servers in JSON format.
+ ConstElementPtr createValidJsonConfiguration() const;
+
+ HookLibsCollection libraries_;
+};
+
+ConstElementPtr
+LibLoadTest::createValidJsonConfiguration() const {
+ std::string config_text =
+ "["
+ " {"
+ " \"this-server-name\": \"server1\","
+ " \"mode\": \"hot-standby\","
+ " \"sync-page-limit\": 3,"
+ " \"heartbeat-delay\": 1000,"
+ " \"max-response-delay\": 1000,"
+ " \"max-ack-delay\": 10000,"
+ " \"max-unacked-clients\": 10,"
+ " \"peers\": ["
+ " {"
+ " \"name\": \"server1\","
+ " \"url\": \"http://127.0.0.1:18123/\","
+ " \"role\": \"primary\","
+ " \"auto-failover\": true"
+ " },"
+ " {"
+ " \"name\": \"server2\","
+ " \"url\": \"http://127.0.0.1:18124/\","
+ " \"role\": \"standby\","
+ " \"auto-failover\": true"
+ " },"
+ " {"
+ " \"name\": \"server3\","
+ " \"url\": \"http://127.0.0.1:18125/\","
+ " \"role\": \"backup\","
+ " \"auto-failover\": false"
+ " }"
+ " ]"
+ " }"
+ "]";
+
+ return (Element::fromJSON(config_text));
+}
+
+// Simple test that checks the library can be loaded and unloaded several times.
+TEST_F(LibLoadTest, validLoad) {
+
+ // Prepare parameters,
+ ElementPtr params = Element::createMap();
+ params->set("high-availability", createValidJsonConfiguration());
+
+ // Set family and proc name.
+ CfgMgr::instance().setFamily(AF_INET);
+ Daemon::setProcName("kea-dhcp4");
+
+ addLib(HA_LIB_SO, params);
+
+ EXPECT_TRUE(loadLibs());
+ unloadLibs();
+
+ EXPECT_TRUE(loadLibs());
+ unloadLibs();
+}
+
+// Simple test that checks the library can be loaded in a DHCPv6 server.
+TEST_F(LibLoadTest, dhcpv6) {
+ // Prepare parameters,
+ ElementPtr params = Element::createMap();
+ params->set("high-availability", createValidJsonConfiguration());
+
+ // Set family and proc name.
+ CfgMgr::instance().setFamily(AF_INET6);
+ Daemon::setProcName("kea-dhcp4");
+
+ addLib(HA_LIB_SO, params);
+
+ // The process name must be kea-dhcp6 so load shall fail.
+ EXPECT_FALSE(loadLibs());
+
+ Daemon::setProcName("kea-dhcp6");
+ EXPECT_TRUE(loadLibs());
+}
+
+} // end of anonymous namespace