]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#1671] the -t parameter now loads and checks hook libraries config
authorRazvan Becheriu <razvan@isc.org>
Thu, 16 Mar 2023 19:16:22 +0000 (21:16 +0200)
committerRazvan Becheriu <razvan@isc.org>
Fri, 17 Mar 2023 21:00:39 +0000 (23:00 +0200)
31 files changed:
doc/sphinx/arm/agent.rst
doc/sphinx/arm/ddns.rst
doc/sphinx/arm/dhcp4-srv.rst
doc/sphinx/arm/dhcp6-srv.rst
doc/sphinx/arm/ext-netconf.rst
doc/sphinx/man/kea-dhcp4.8.rst
doc/sphinx/man/kea-dhcp6.8.rst
src/bin/dhcp4/ctrl_dhcp4_srv.cc
src/bin/dhcp4/ctrl_dhcp4_srv.h
src/bin/dhcp4/json_config_parser.cc
src/bin/dhcp4/json_config_parser.h
src/bin/dhcp4/main.cc
src/bin/dhcp4/tests/callout_library_1.cc
src/bin/dhcp4/tests/callout_library_2.cc
src/bin/dhcp4/tests/callout_library_3.cc
src/bin/dhcp4/tests/callout_library_common.h
src/bin/dhcp4/tests/dhcp4_process_tests.sh.in
src/bin/dhcp6/ctrl_dhcp6_srv.cc
src/bin/dhcp6/ctrl_dhcp6_srv.h
src/bin/dhcp6/json_config_parser.cc
src/bin/dhcp6/json_config_parser.h
src/bin/dhcp6/main.cc
src/bin/dhcp6/tests/callout_library_1.cc
src/bin/dhcp6/tests/callout_library_2.cc
src/bin/dhcp6/tests/callout_library_3.cc
src/bin/dhcp6/tests/callout_library_common.h
src/bin/dhcp6/tests/dhcp6_process_tests.sh.in
src/hooks/dhcp/high_availability/ha_messages.mes
src/hooks/dhcp/mysql_cb/mysql_cb_messages.mes
src/hooks/dhcp/pgsql_cb/pgsql_cb_messages.mes
src/lib/testutils/dhcp_test_lib.sh.in

index 1b827086d660d9769872557e1d43c7eb16959f11..3dc0118d24c30f29b5ae1d3bc9a305d64043708a 100644 (file)
@@ -357,8 +357,56 @@ Since Kea 1.9.6, the ``kea-shell`` tool supports TLS.
 
 .. _agent-launch:
 
-Starting the Control Agent
-==========================
+Starting and Stopping the Control Agent
+=======================================
+
+``kea-ctrl-agent`` accepts the following command-line switches:
+
+-  ``-c file`` - specifies the configuration file.
+
+-  ``-d`` - specifies whether the agent logging should be switched to
+   debug/verbose mode. In verbose mode, the logging severity and
+   debuglevel specified in the configuration file are ignored and
+   "debug" severity and the maximum debuglevel (99) are assumed. The
+   flag is convenient for temporarily switching the server into maximum
+   verbosity, e.g. when debugging.
+
+-  ``-t file`` - specifies the configuration file to be tested.
+   ``kea-netconf`` attempts to load it and conducts sanity checks;
+   certain checks are possible only while running the actual server. The
+   actual status is reported with exit code (0 = configuration appears valid,
+   1 = error encountered). Kea prints out log messages to standard
+   output and error to standard error when testing the configuration.
+
+-  ``-v`` - displays the version of ``kea-ctrl-agent`` and exits.
+
+-  ``-V`` - displays the extended version information for ``kea-ctrl-agent``
+   and exits. The listing includes the versions of the libraries
+   dynamically linked to Kea.
+
+-  ``-W`` - displays the Kea configuration report and exits. The report
+   is a copy of the ``config.report`` file produced by ``./configure``;
+   it is embedded in the executable binary.
+
+The ``config.report`` file may also be accessed directly, via the
+following command. The binary ``path`` may be found in the install
+directory or in the ``.libs`` subdirectory in the source tree. For
+example: ``kea/src/lib/process/.libs/``.
+
+::
+
+   strings path/libkea-process.so | sed -n 's/;;;; //p'
+
+::
+
+   strings path/libkea-process.a | sed -n 's/;;;; //p'
+
+The libcfgrpt.a library can also be used from the source tree with path:
+``src/lib/process/cfgrpt/.libs/``.
+
+::
+
+   strings path/libcfgrpt.a | sed -n 's/;;;; //p'
 
 The CA is started by running its binary and specifying the configuration
 file it should use. For example:
index 214cdf9c35cd4a9686b0eb8b82e940d01ef6cfdd..8e2bd844aea31d8dd429e55878626b11e82ba123 100644 (file)
@@ -141,11 +141,22 @@ directly. It accepts the following command-line switches:
 The ``config.report`` file may also be accessed directly, via the
 following command. The binary ``path`` may be found in the install
 directory or in the ``.libs`` subdirectory in the source tree. For
-example: ``kea/src/bin/d2/.libs/kea-dhcp-ddns``.
+example: ``kea/src/lib/process/.libs/``.
 
 ::
 
-   strings path/kea-dhcp-ddns | sed -n 's/;;;; //p'
+   strings path/libkea-process.so | sed -n 's/;;;; //p'
+
+::
+
+   strings path/libkea-process.a | sed -n 's/;;;; //p'
+
+The libcfgrpt.a library can also be used from the source tree with path:
+``src/lib/process/cfgrpt/.libs/``.
+
+::
+
+   strings path/libcfgrpt.a | sed -n 's/;;;; //p'
 
 Upon startup, the module loads its configuration and begins listening
 for NCRs based on that configuration.
index 7723cd71ed93e7857f38a89628745a3408e1ceee..ee74e38b39be9a7d856ab0d12762158d1cd3dbe8 100644 (file)
@@ -42,6 +42,14 @@ the following command-line switches:
    comprehensive; certain checks are possible only when running the
    server.
 
+-  ``-T file`` - specifies a configuration file to be tested. ``kea-dhcp4``
+   loads it, checks it, and exits. It performs extra checks beside ``-t`` is
+   doing, like establising database connections (lease db, host db, CB db,
+   forensic logging db), hook libraries loading and configuration parsing, etc.
+   It does not open unix or TCP/UDP sockets, neither does it open or rotate
+   files, as all these actions could interfere with a running process on the
+   same machine.
+
 -  ``-v`` - displays the Kea version and exits.
 
 -  ``-V`` - displays the Kea extended version with additional parameters
@@ -52,6 +60,26 @@ the following command-line switches:
    is a copy of the ``config.report`` file produced by ``./configure``;
    it is embedded in the executable binary.
 
+The ``config.report`` file may also be accessed directly, via the
+following command. The binary ``path`` may be found in the install
+directory or in the ``.libs`` subdirectory in the source tree. For
+example: ``kea/src/lib/process/.libs/``.
+
+::
+
+   strings path/libkea-process.so | sed -n 's/;;;; //p'
+
+::
+
+   strings path/libkea-process.a | sed -n 's/;;;; //p'
+
+The libcfgrpt.a library can also be used from the source tree with path:
+``src/lib/process/cfgrpt/.libs/``.
+
+::
+
+   strings path/libcfgrpt.a | sed -n 's/;;;; //p'
+
 On startup, the server detects available network interfaces and
 attempts to open UDP sockets on all interfaces listed in the
 configuration file. Since the DHCPv4 server opens privileged ports, it
index e21535ecea5092ccf91c42b500344a5119fbff24..d8ca1203a844f80f3910e59b5c67fdfa30a38a0a 100644 (file)
@@ -42,6 +42,14 @@ the following command-line switches:
    comprehensive; certain checks are possible only when running the
    server.
 
+-  ``-T file`` - specifies a configuration file to be tested. ``kea-dhcp4``
+   loads it, checks it, and exits. It performs extra checks beside ``-t`` is
+   doing, like establising database connections (lease db, host db, CB db,
+   forensic logging db), hook libraries loading and configuration parsing, etc.
+   It does not open unix or TCP/UDP sockets, neither does it open or rotate
+   files, as all these actions could interfere with a running process on the
+   same machine.
+
 -  ``-v`` - displays the Kea version and exits.
 
 -  ``-V`` - displays the Kea extended version with additional parameters
@@ -52,6 +60,26 @@ the following command-line switches:
    is a copy of the ``config.report`` file produced by ``./configure``;
    it is embedded in the executable binary.
 
+The ``config.report`` file may also be accessed directly, via the
+following command. The binary ``path`` may be found in the install
+directory or in the ``.libs`` subdirectory in the source tree. For
+example: ``kea/src/lib/process/.libs/``.
+
+::
+
+   strings path/libkea-process.so | sed -n 's/;;;; //p'
+
+::
+
+   strings path/libkea-process.a | sed -n 's/;;;; //p'
+
+The libcfgrpt.a library can also be used from the source tree with path:
+``src/lib/process/cfgrpt/.libs/``.
+
+::
+
+   strings path/libcfgrpt.a | sed -n 's/;;;; //p'
+
 On startup, the server detects available network interfaces and
 attempts to open UDP sockets on all interfaces listed in the
 configuration file. Since the DHCPv6 server opens privileged ports, it
index a1c9ce382205518ed68b6a7e5d42b64dddadf229..f4bc9922cf4636d75841df4131da136a09182596 100644 (file)
@@ -686,6 +686,26 @@ Starting and Stopping the NETCONF Agent
    is a copy of the ``config.report`` file produced by ``./configure``;
    it is embedded in the executable binary.
 
+The ``config.report`` file may also be accessed directly, via the
+following command. The binary ``path`` may be found in the install
+directory or in the ``.libs`` subdirectory in the source tree. For
+example: ``kea/src/lib/process/.libs/``.
+
+::
+
+   strings path/libkea-process.so | sed -n 's/;;;; //p'
+
+::
+
+   strings path/libkea-process.a | sed -n 's/;;;; //p'
+
+The libcfgrpt.a library can also be used from the source tree with path:
+``src/lib/process/cfgrpt/.libs/``.
+
+::
+
+   strings path/libcfgrpt.a | sed -n 's/;;;; //p'
+
 .. _operation-example:
 
 A Step-by-Step NETCONF Agent Operation Example
index be59b0f3d109784592d403e0de395b1004a8a62d..1061720dd0a873d163db52b882eaf37e0dbfa2cc 100644 (file)
@@ -49,6 +49,14 @@ The arguments are as follows:
    service and control channel sockets are not opened, and hook
    libraries are not loaded.
 
+``-T config-file``
+   Checks the configuration file and reports the first error, if any.
+   It performs extra checks beside ``-t`` is doing, like establising database
+   connections (lease db, host db, CB db, forensic logging db), hook libraries
+   loading and configuration parsing, etc. It does not open unix or TCP/UDP
+   sockets, neither does it open or rotate files, as all these actions could
+   interfere with a running process on the same machine.
+
 ``-p server-port-number``
    Specifies the server port number (1-65535) on which the server listens. This is
    useful for testing purposes only.
index 19ec5e881644eaf855736d4091760945c13d067d..86e2dc1d4fcc65bbb0ba8066c5c63794d9e38d61 100644 (file)
@@ -49,6 +49,14 @@ The arguments are as follows:
    service and control channel sockets are not opened, and hook
    libraries are not loaded.
 
+``-T config-file``
+   Checks the configuration file and reports the first error, if any.
+   It performs extra checks beside ``-t`` is doing, like establising database
+   connections (lease db, host db, CB db, forensic logging db), hook libraries
+   loading and configuration parsing, etc. It does not open unix or TCP/UDP
+   sockets, neither does it open or rotate files, as all these actions could
+   interfere with a running process on the same machine.
+
 ``-p server-port-number``
    Specifies the server port number (1-65535) on which the server listens. This is
    useful for testing purposes only.
index e5f626188718f7eab2dbe6c5f11b87389c292c08..66a369b118c483561383d5b4245e1a68441de5c7 100644 (file)
@@ -1025,6 +1025,29 @@ ControlledDhcpv4Srv::processConfig(isc::data::ConstElementPtr config) {
     // exception free.
     LibDHCP::commitRuntimeOptionDefs();
 
+    auto notify_libraries = ControlledDhcpv4Srv::finishConfigHookLibraries(config);
+    if (notify_libraries) {
+        return (notify_libraries);
+    }
+
+    // Apply multi threading settings.
+    // @note These settings are applied/updated only if no errors occur while
+    // applying the new configuration.
+    // @todo This should be fixed.
+    try {
+        CfgMultiThreading::apply(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading());
+    } catch (const std::exception& ex) {
+        err << "Error applying multi threading settings: "
+            << ex.what();
+        return (isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str()));
+    }
+
+    return (answer);
+}
+
+isc::data::ConstElementPtr
+ControlledDhcpv4Srv::finishConfigHookLibraries(isc::data::ConstElementPtr config) {
+    ControlledDhcpv4Srv* srv = ControlledDhcpv4Srv::getInstance();
     // This hook point notifies hooks libraries that the configuration of the
     // DHCPv4 server has completed. It provides the hook library with the pointer
     // to the common IO service object, new server configuration in the JSON
@@ -1053,27 +1076,11 @@ ControlledDhcpv4Srv::processConfig(isc::data::ConstElementPtr config) {
         }
     }
 
-    // Apply multi threading settings.
-    // @note These settings are applied/updated only if no errors occur while
-    // applying the new configuration.
-    // @todo This should be fixed.
-    try {
-        CfgMultiThreading::apply(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading());
-    } catch (const std::exception& ex) {
-        err << "Error applying multi threading settings: "
-            << ex.what();
-        return (isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str()));
-    }
-
-    return (answer);
+    return (ConstElementPtr());
 }
 
 isc::data::ConstElementPtr
 ControlledDhcpv4Srv::checkConfig(isc::data::ConstElementPtr config) {
-
-    LOG_DEBUG(dhcp4_logger, DBG_DHCP4_COMMAND, DHCP4_CONFIG_RECEIVED)
-        .arg(redactConfig(config)->str());
-
     ControlledDhcpv4Srv* srv = ControlledDhcpv4Srv::getInstance();
 
     if (!srv) {
@@ -1082,6 +1089,9 @@ ControlledDhcpv4Srv::checkConfig(isc::data::ConstElementPtr config) {
         return (no_srv);
     }
 
+    LOG_DEBUG(dhcp4_logger, DBG_DHCP4_COMMAND, DHCP4_CONFIG_RECEIVED)
+        .arg(srv->redactConfig(config)->str());
+
     return (configureDhcp4Server(*srv, config, true));
 }
 
index 2c34610b963081567974fdacaba7645f8c7595da..83b339f73e96de46996dac5965efd54ff9a5761f 100644 (file)
@@ -105,21 +105,32 @@ public:
     /// As pointer to this method is used a callback in ASIO used in
     /// ModuleCCSession, it has to be static.
     ///
-    /// @param new_config textual representation of the new configuration
+    /// @param config textual representation of the new configuration
     ///
     /// @return status of the config update
     static isc::data::ConstElementPtr
-    processConfig(isc::data::ConstElementPtr new_config);
+    processConfig(isc::data::ConstElementPtr config);
 
     /// @brief Configuration checker
     ///
     /// This is a method for checking incoming configuration.
     ///
-    /// @param new_config JSON representation of the new configuration
+    /// @param config JSON representation of the new configuration
     ///
     /// @return status of the config check
-    isc::data::ConstElementPtr
-    checkConfig(isc::data::ConstElementPtr new_config);
+    static isc::data::ConstElementPtr
+    checkConfig(isc::data::ConstElementPtr config);
+
+    /// @brief Configuration checker for hook libraries
+    ///
+    /// This is a method for checking incoming configuration in the hooks
+    /// libraries. It calls dhcp4_srv_configured hook point for all hooks.
+    ///
+    /// @param config JSON representation of the new configuration
+    ///
+    /// @return status of the config check
+    static isc::data::ConstElementPtr
+    finishConfigHookLibraries(isc::data::ConstElementPtr config);
 
     /// @brief Returns pointer to the sole instance of Dhcpv4Srv
     ///
index 3d6c48ce41e31712ced3e06959dbd330c044e478..b60f0d033c52da1ebc2f38156e1d1efa99fe7892 100644 (file)
@@ -11,6 +11,7 @@
 #include <database/dbaccess_parser.h>
 #include <database/backend_selector.h>
 #include <database/server_selector.h>
+#include <dhcp4/ctrl_dhcp4_srv.h>
 #include <dhcp4/dhcp4_log.h>
 #include <dhcp4/dhcp4_srv.h>
 #include <dhcp4/json_config_parser.h>
@@ -738,7 +739,7 @@ processDhcp4Config(isc::data::ConstElementPtr config_set) {
 
 isc::data::ConstElementPtr
 configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
-                     bool check_only) {
+                     bool check_only, bool extra_checks) {
     if (!config_set) {
         ConstElementPtr answer = isc::config::createAnswer(CONTROL_RESULT_ERROR,
                                                            "Can't parse NULL config");
@@ -748,21 +749,14 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
     LOG_DEBUG(dhcp4_logger, DBG_DHCP4_COMMAND, DHCP4_CONFIG_START)
         .arg(server.redactConfig(config_set)->str());
 
-    // Rollback informs whether error occurred and original data
-    // have to be restored to global storages.
-    bool rollback = false;
-
     auto answer = processDhcp4Config(config_set);
 
-    int status_code = 0;
+    int status_code = CONTROL_RESULT_SUCCESS;
     isc::config::parseAnswer(status_code, answer);
-    if (status_code != CONTROL_RESULT_SUCCESS) {
-        rollback = true;
-    }
 
     SrvConfigPtr srv_config;
 
-    if (!rollback) {
+    if (status_code == CONTROL_RESULT_SUCCESS) {
         if (!check_only) {
             string parameter_name;
             ElementPtr mutable_cfg;
@@ -803,20 +797,33 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
                 LOG_ERROR(dhcp4_logger, DHCP4_PARSER_FAIL)
                           .arg(parameter_name).arg(ex.what());
                 answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, ex.what());
-
-                // An error occurred, so make sure that we restore original data.
-                rollback = true;
+                status_code = CONTROL_RESULT_ERROR;
             } catch (...) {
                 // For things like bad_cast in boost::lexical_cast
                 LOG_ERROR(dhcp4_logger, DHCP4_PARSER_EXCEPTION).arg(parameter_name);
                 answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, "undefined configuration"
                                                    " processing error");
-
-                // An error occurred, so make sure that we restore original data.
-                rollback = true;
+                status_code = CONTROL_RESULT_ERROR;
             }
         } else {
-            rollback = true;
+            if (extra_checks) {
+                // Re-open lease and host database with new parameters.
+                try {
+                    // Get the staging configuration.
+                    srv_config = CfgMgr::instance().getStagingCfg();
+
+                    CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
+                    string params = "universe=4 persist=false";
+                    if (cfg_db->getExtendedInfoTablesEnabled()) {
+                        params += " extended-info-tables=true";
+                    }
+                    cfg_db->setAppendedParameters(params);
+                    cfg_db->createManagers();
+                } catch (const std::exception& ex) {
+                    answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, ex.what());
+                    status_code = CONTROL_RESULT_ERROR;
+                }
+            }
         }
     }
 
@@ -824,12 +831,26 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
     // configuration. This will add created subnets and option values into
     // the server's configuration.
     // This operation should be exception safe but let's make sure.
-    if (!rollback) {
+    if (status_code == CONTROL_RESULT_SUCCESS && !check_only) {
         try {
 
             // Setup the command channel.
             configureCommandChannel();
+        } catch (const isc::Exception& ex) {
+            LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_FAIL).arg(ex.what());
+            answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, ex.what());
+            status_code = CONTROL_RESULT_ERROR;
+        } catch (...) {
+            // For things like bad_cast in boost::lexical_cast
+            LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_EXCEPTION);
+            answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, "undefined configuration"
+                                               " parsing error");
+            status_code = CONTROL_RESULT_ERROR;
+        }
+    }
 
+    if (status_code == CONTROL_RESULT_SUCCESS && (!check_only || extra_checks)) {
+        try {
             // No need to commit interface names as this is handled by the
             // CfgMgr::commit() function.
 
@@ -837,7 +858,21 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
             D2ClientConfigPtr cfg;
             cfg = CfgMgr::instance().getStagingCfg()->getD2ClientConfig();
             CfgMgr::instance().setD2ClientConfig(cfg);
+        } catch (const isc::Exception& ex) {
+            LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_FAIL).arg(ex.what());
+            answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, ex.what());
+            status_code = CONTROL_RESULT_ERROR;
+        } catch (...) {
+            // For things like bad_cast in boost::lexical_cast
+            LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_EXCEPTION);
+            answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, "undefined configuration"
+                                               " parsing error");
+            status_code = CONTROL_RESULT_ERROR;
+        }
+    }
 
+    if (status_code == CONTROL_RESULT_SUCCESS && (!check_only || extra_checks)) {
+        try {
             // This occurs last as if it succeeds, there is no easy way to
             // revert it.  As a result, the failure to commit a subsequent
             // change causes problems when trying to roll back.
@@ -849,35 +884,32 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
         } catch (const isc::Exception& ex) {
             LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_FAIL).arg(ex.what());
             answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, ex.what());
-
-            // An error occurred, so make sure to restore the original data.
-            rollback = true;
+            status_code = CONTROL_RESULT_ERROR;
         } catch (...) {
             // For things like bad_cast in boost::lexical_cast
             LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_EXCEPTION);
             answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, "undefined configuration"
                                                " parsing error");
-
-            // An error occurred, so make sure to restore the original data.
-            rollback = true;
+            status_code = CONTROL_RESULT_ERROR;
         }
     }
 
     // Moved from the commit block to add the config backend indication.
-    if (!rollback) {
+    if (status_code == CONTROL_RESULT_SUCCESS && (!check_only || extra_checks)) {
         try {
-
-            // If there are config backends, fetch and merge into staging config
-            server.getCBControl()->databaseConfigFetch(srv_config,
-                                                       CBControlDHCPv4::FetchMode::FETCH_ALL);
+            if (extra_checks) {
+                server.getCBControl()->databaseConfigConnect(srv_config);
+            } else {
+                // If there are config backends, fetch and merge into staging config
+                server.getCBControl()->databaseConfigFetch(srv_config,
+                                                           CBControlDHCPv4::FetchMode::FETCH_ALL);
+            }
         } catch (const isc::Exception& ex) {
             std::ostringstream err;
             err << "during update from config backend database: " << ex.what();
             LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_FAIL).arg(err.str());
             answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str());
-
-            // An error occurred, so make sure to restore the original data.
-            rollback = true;
+            status_code = CONTROL_RESULT_ERROR;
         } catch (...) {
             // For things like bad_cast in boost::lexical_cast
             std::ostringstream err;
@@ -885,17 +917,23 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
                 << "undefined configuration parsing error";
             LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_FAIL).arg(err.str());
             answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str());
-
-            // An error occurred, so make sure to restore the original data.
-            rollback = true;
+            status_code = CONTROL_RESULT_ERROR;
         }
     }
 
     // Rollback changes as the configuration parsing failed.
-    if (rollback) {
+    if (check_only || status_code != CONTROL_RESULT_SUCCESS) {
         // Revert to original configuration of runtime option definitions
         // in the libdhcp++.
         LibDHCP::revertRuntimeOptionDefs();
+
+        if (status_code == CONTROL_RESULT_SUCCESS && extra_checks) {
+            auto notify_libraries = ControlledDhcpv4Srv::finishConfigHookLibraries(config_set);
+            if (notify_libraries) {
+                return (notify_libraries);
+            }
+        }
+
         return (answer);
     }
 
index 34b14197003436385085cbafbe81743b787bf2a0..fba72d1e484fe268c796461969c5daa39938d7ea 100644 (file)
@@ -8,15 +8,13 @@
 #define DHCP4_CONFIG_PARSER_H
 
 #include <cc/data.h>
-#include <cc/stamped_value.h>
 #include <dhcpsrv/parsers/dhcp_parsers.h>
 #include <exceptions/exceptions.h>
 
-#include <stdint.h>
 #include <string>
 
 /// @todo: This header file and its .cc counterpart are very similar between
-/// DHCPv4 and DHCPv6. They should be merged. A ticket #2355.
+/// DHCPv4 and DHCPv6. They should be merged.
 
 namespace isc {
 namespace dhcp {
@@ -41,9 +39,9 @@ class Dhcpv4Srv;
 /// extra parameter is a reference to DHCPv4 server component. It is currently
 /// not used and CfgMgr::instance() is accessed instead.
 ///
-/// Test-only mode added. If check_only flag is set to true, the configuration
-/// is parsed, but the actual change is not applied. The goal is to have
-/// the ability to test configuration.
+/// Test-only mode is supported. If check_only flag is set to true, the
+/// configuration is parsed, but the actual change is not applied. The goal is
+/// to have the ability to test configuration.
 ///
 /// This method does not throw. It catches all exceptions and returns them as
 /// reconfiguration statuses. It may return the following response codes:
@@ -52,13 +50,16 @@ class Dhcpv4Srv;
 /// 2 - commit failed (parsing was successful, but failed to store the
 /// values in to server's configuration)
 ///
-/// @param server the server object
-/// @param config_set a new configuration (JSON) for DHCPv4 server
-/// @param check_only whether this configuration is for testing only
-/// @return answer that contains result of reconfiguration
+/// @param server DHCPv4 server object.
+/// @param config_set a new configuration (JSON) for DHCPv4 server.
+/// @param check_only whether this configuration is for testing only.
+/// @param extra_checks load hooks and perform extra checks if this flag is true
+///        and check_only is also true, otherwise perform simple check if
+///        check_only is true.
+/// @return answer that contains result of the reconfiguration.
 isc::data::ConstElementPtr
 configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
-                     bool check_only = false);
+                     bool check_only = false, bool extra_checks = false);
 
 }  // namespace dhcp
 }  // namespace isc
index dfafb96772f0b03399d1d2276dd56904da846b7d..7979a0466642a0dc407c21b64659e50ee8540e96 100644 (file)
@@ -52,13 +52,15 @@ usage() {
          << endl;
     cerr << endl;
     cerr << "Usage: " << DHCP4_NAME
-         << " -[v|V|W] [-d] [-{c|t} cfgfile] [-p number] [-P number]" << endl;
+         << " -[v|V|W] [-d] [-{c|t|T} cfgfile] [-p number] [-P number]" << endl;
     cerr << "  -v: print version number and exit" << endl;
     cerr << "  -V: print extended version and exit" << endl;
     cerr << "  -W: display the configuration report and exit" << endl;
     cerr << "  -d: debug mode with extra verbosity (former -v)" << endl;
     cerr << "  -c file: specify configuration file" << endl;
     cerr << "  -t file: check the configuration file syntax and exit" << endl;
+    cerr << "  -T file: check the configuration file doing hooks load and extra "
+         << "checks and exit" << endl;
     cerr << "  -p number: specify non-standard server port number 1-65535 "
          << "(useful for testing only)" << endl;
     cerr << "  -P number: specify non-standard client port number 1-65535 "
@@ -76,11 +78,12 @@ main(int argc, char* argv[]) {
     int client_port_number = 0;
     bool verbose_mode = false; // Should server be verbose?
     bool check_mode = false;   // Check syntax
+    bool load_hooks = false;   // Check hooks config
 
     // The standard config file
     std::string config_file("");
 
-    while ((ch = getopt(argc, argv, "dvVWc:p:P:t:")) != -1) {
+    while ((ch = getopt(argc, argv, "dvVWc:p:P:t:T:")) != -1) {
         switch (ch) {
         case 'd':
             verbose_mode = true;
@@ -98,9 +101,16 @@ main(int argc, char* argv[]) {
             cout << isc::detail::getConfigReport() << endl;
             return (EXIT_SUCCESS);
 
+        case 'T':
+            load_hooks = true;
+            check_mode = true;
+            config_file = optarg;
+            break;
+
         case 't':
             check_mode = true;
-            // falls through
+            config_file = optarg;
+            break;
 
         case 'c': // config file
             config_file = optarg;
@@ -184,9 +194,11 @@ main(int argc, char* argv[]) {
             ControlledDhcpv4Srv server(0);
             ConstElementPtr answer;
 
+            server.setProcName(DHCP4_NAME);
+
             // Now we pass the Dhcp4 configuration to the server, but
             // tell it to check the configuration only (check_only = true)
-            answer = configureDhcp4Server(server, dhcp4, true);
+            answer = configureDhcp4Server(server, dhcp4, true, load_hooks);
 
             int status_code = 0;
             answer = isc::config::parseAnswer(status_code, answer);
index 73e3a17f9048f23871cf659872cef8ce6f1968ac..1199527622528cf4b0b6e8af99f08aa029879342 100644 (file)
@@ -20,6 +20,10 @@ static const int LIBRARY_NUMBER = 1;
 // issues related to namespaces.
 extern "C" {
 
+int (*do_load)(isc::hooks::LibraryHandle& handle);
+
+int (*do_unload)(isc::hooks::LibraryHandle& handle);
+
 /// @brief This function is called to retrieve the multi-threading compatibility.
 ///
 /// @return 1 which means compatible with multi-threading.
index 7b1ad4b14dcf0d7a90ceead6291b69beef18fae2..cdb090f9f0c2cab451e4defd9d93df9a89eeef58 100644 (file)
@@ -14,3 +14,11 @@ static const int LIBRARY_NUMBER = 2;
 #include <config.h>
 
 #include <dhcp4/tests/callout_library_common.h>
+
+extern "C" {
+
+int (*do_load)(isc::hooks::LibraryHandle& handle);
+
+int (*do_unload)(isc::hooks::LibraryHandle& handle);
+
+}
index 494b25801d9a74a2f7c2574eae20cd7d799e5df9..a00ce10fc7cf95eacc9d7b13451ed69168162a2c 100644 (file)
@@ -25,6 +25,23 @@ using namespace isc::hooks;
 // issues related to namespaces.
 extern "C" {
 
+int
+do_load_impl(LibraryHandle& handle) {
+    // Determine if this callout is configured to fail.
+    isc::dhcp::SrvConfigPtr config;
+    isc::data::ConstElementPtr const& parameters(handle.getParameters());
+    isc::data::ConstElementPtr mode_element(parameters ? parameters->get("mode") : 0);
+    std::string mode(mode_element ? mode_element->stringValue() : "");
+    if (mode == "fail-on-load") {
+        return (1);
+    }
+    return (0);
+}
+
+int (*do_load)(isc::hooks::LibraryHandle& handle) = do_load_impl;
+
+int (*do_unload)(isc::hooks::LibraryHandle& handle);
+
 /// @brief Callout which appends library number and provided arguments to
 /// the marker file for dhcp4_srv_configured callout.
 ///
index 568746a0f9bb02df951de8e2723429701594a005..b40465c2a3e340007d420668e51a69b9ffd39a16 100644 (file)
 
 extern "C" {
 
+extern int (*do_load)(isc::hooks::LibraryHandle& handle);
+
+extern int (*do_unload)(isc::hooks::LibraryHandle& handle);
+
 /// @brief Append digit to marker file
 ///
 /// If the marker file does not exist, create it.  Then append the single
@@ -84,13 +88,23 @@ version() {
 }
 
 int
-load(isc::hooks::LibraryHandle&) {
-    return (appendDigit(LOAD_MARKER_FILE));
+load(isc::hooks::LibraryHandle& handle) {
+    int result = 0;
+    result = appendDigit(LOAD_MARKER_FILE);
+    if (result == 0 && do_load) {
+        result = do_load(handle);
+    }
+    return (result);
 }
 
 int
-unload() {
-    return (appendDigit(UNLOAD_MARKER_FILE));
+unload(isc::hooks::LibraryHandle& handle) {
+    int result = 0;
+    result = appendDigit(UNLOAD_MARKER_FILE);
+    if (result == 0 && do_unload) {
+        result = do_unload(handle);
+    }
+    return (result);
 }
 
 };
index 8cc8d93b6d9257d1991c188b534c2e052b60c511..82f250299f7ec3b8bff2bcd641fc320252638cf7 100644 (file)
@@ -24,6 +24,8 @@ LOG_FILE="@abs_top_builddir@/src/bin/dhcp4/tests/test.log"
 LEASE_FILE="@abs_top_builddir@/src/bin/dhcp4/tests/test_leases.csv"
 # Path to the Kea LFC application
 export KEA_LFC_EXECUTABLE="@abs_top_builddir@/src/bin/lfc/kea-lfc"
+# Path to test hooks library
+HOOK_PATH="@abs_top_builddir@/src/bin/dhcp4/tests/.libs/libco3.so"
 # Kea configuration to be stored in the configuration file.
 CONFIG="{
     \"Dhcp4\":
@@ -46,7 +48,7 @@ CONFIG="{
             \"subnet\": \"10.0.0.0/8\",
             \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ]
         } ],
-       \"dhcp-ddns\": {
+        \"dhcp-ddns\": {
             \"enable-updates\": true,
             \"qualifying-suffix\": \"\"
         },
@@ -63,6 +65,7 @@ CONFIG="{
         ]
     }
 }"
+
 # Invalid configuration (syntax error) to check that Kea can check syntax.
 # This config has following errors:
 # - it should be interfaces-config/interfaces, not interfaces
@@ -168,6 +171,108 @@ CONFIG_INVALID="{
     }
 }"
 
+# Invalid configuration (hook explicitly fails to load) to check that performing
+# extra configuration checks detects the error.
+INVALID_CONFIG_HOOKS_LOAD="{
+    \"Dhcp4\":
+    {
+        \"interfaces-config\": {
+            \"interfaces\": [ ]
+        },
+        \"multi-threading\": {
+          \"enable-multi-threading\": false
+        },
+        \"valid-lifetime\": 4000,
+        \"renew-timer\": 1000,
+        \"rebind-timer\": 2000,
+        \"lease-database\":
+        {
+            \"type\": \"memfile\",
+            \"name\": \"$LEASE_FILE\",
+            \"persist\": false,
+            \"lfc-interval\": 0
+        },
+        \"subnet4\": [
+        {
+            \"subnet\": \"10.0.0.0/8\",
+            \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ]
+        } ],
+        \"dhcp-ddns\": {
+            \"enable-updates\": true,
+            \"qualifying-suffix\": \"\"
+        },
+        \"hooks-libraries\": [
+        {
+            \"library\": \"$HOOK_PATH\",
+                \"parameters\": {
+                    \"mode\": \"fail-on-load\"
+            }
+        } ],
+        \"loggers\": [
+        {
+            \"name\": \"kea-dhcp4\",
+            \"output_options\": [
+                {
+                    \"output\": \"$LOG_FILE\"
+                }
+            ],
+            \"severity\": \"INFO\"
+        }
+        ]
+    }
+}"
+
+# Invalid configuration (hook point returns error) to check that performing
+# extra configuration checks detects the error.
+INVALID_CONFIG_HOOKS_CALLOUT_FAIL="{
+    \"Dhcp4\":
+    {
+        \"interfaces-config\": {
+            \"interfaces\": [ ]
+        },
+        \"multi-threading\": {
+          \"enable-multi-threading\": false
+        },
+        \"valid-lifetime\": 4000,
+        \"renew-timer\": 1000,
+        \"rebind-timer\": 2000,
+        \"lease-database\":
+        {
+            \"type\": \"memfile\",
+            \"name\": \"$LEASE_FILE\",
+            \"persist\": false,
+            \"lfc-interval\": 0
+        },
+        \"subnet4\": [
+        {
+            \"subnet\": \"10.0.0.0/8\",
+            \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ]
+        } ],
+        \"dhcp-ddns\": {
+            \"enable-updates\": true,
+            \"qualifying-suffix\": \"\"
+        },
+        \"hooks-libraries\": [
+        {
+            \"library\": \"$HOOK_PATH\",
+                \"parameters\": {
+                    \"mode\": \"fail-without-error\"
+            }
+        } ],
+        \"loggers\": [
+        {
+            \"name\": \"kea-dhcp4\",
+            \"output_options\": [
+                {
+                    \"output\": \"$LOG_FILE\"
+                }
+            ],
+            \"severity\": \"INFO\"
+        }
+        ]
+    }
+}"
+
 # Set the location of the executable.
 bin="kea-dhcp4"
 bin_path="@abs_top_builddir@/src/bin/dhcp4"
@@ -184,15 +289,22 @@ syntax_check_test() {
     local test_name="${1}"
     local config="${2}"
     local expected_code="${3}"
+    local extra_check="${4}"
 
     # Log the start of the test and print test name.
     test_start "${test_name}"
     # Create correct configuration file.
     create_config "${config}"
     # Check it
-    printf "Running command %s.\n" "\"${bin_path}/${bin} -t ${CFG_FILE}\""
-    run_command \
-        "${bin_path}/${bin}" -t "${CFG_FILE}"
+    if [ "${extra_check}" -eq 1 ]; then
+        printf "Running command %s.\n" "\"${bin_path}/${bin} -T ${CFG_FILE}\""
+        run_command \
+            "${bin_path}/${bin}" -T "${CFG_FILE}"
+    else
+        printf "Running command %s.\n" "\"${bin_path}/${bin} -t ${CFG_FILE}\""
+        run_command \
+            "${bin_path}/${bin}" -t "${CFG_FILE}"
+    fi
     if [ "${EXIT_CODE}" -ne "${expected_code}" ]; then
         printf 'ERROR: expected exit code %s, got %s\n' "${expected_code}" "${EXIT_CODE}"
         clean_exit 1
@@ -471,7 +583,9 @@ shutdown_test "dhcpv4.sigint_test" 2
 version_test "dhcpv4.version"
 logger_vars_test "dhcpv4.variables"
 lfc_timer_test
-syntax_check_test "dhcpv4.syntax_check_success" "${CONFIG}" 0
-syntax_check_test "dhcpv4.syntax_check_bad_syntax" "${CONFIG_BAD_SYNTAX}" 1
-syntax_check_test "dhcpv4.syntax_check_bad_values" "${CONFIG_BAD_VALUES}" 1
+syntax_check_test "dhcpv4.syntax_check_success" "${CONFIG}" 0 0
+syntax_check_test "dhcpv4.syntax_check_bad_syntax" "${CONFIG_BAD_SYNTAX}" 1 0
+syntax_check_test "dhcpv4.syntax_check_bad_values" "${CONFIG_BAD_VALUES}" 1 0
+syntax_check_test "dhcpv4.syntax_check_hooks_load_fail" "${INVALID_CONFIG_HOOKS_LOAD}" 1 1
+syntax_check_test "dhcpv4.syntax_check_hooks_callout_fail" "${INVALID_CONFIG_HOOKS_CALLOUT_FAIL}" 1 1
 password_redact_test "dhcpv4.password_redact_test" "$(kea_dhcp_config 4)" 0
index 62c37e27549a4a1c21f1c6a4a9bb3dc73c88e24b..55c3046dbf37566e3e24d9f88ffac3a8ece22d73 100644 (file)
@@ -880,7 +880,6 @@ ControlledDhcpv6Srv::processCommand(const string& command,
 
 isc::data::ConstElementPtr
 ControlledDhcpv6Srv::processConfig(isc::data::ConstElementPtr config) {
-
     ControlledDhcpv6Srv* srv = ControlledDhcpv6Srv::getInstance();
 
     // Single stream instance used in all error clauses
@@ -1046,6 +1045,29 @@ ControlledDhcpv6Srv::processConfig(isc::data::ConstElementPtr config) {
     // exception free.
     LibDHCP::commitRuntimeOptionDefs();
 
+    auto notify_libraries = ControlledDhcpv6Srv::finishConfigHookLibraries(config);
+    if (notify_libraries) {
+        return (notify_libraries);
+    }
+
+    // Apply multi threading settings.
+    // @note These settings are applied/updated only if no errors occur while
+    // applying the new configuration.
+    // @todo This should be fixed.
+    try {
+        CfgMultiThreading::apply(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading());
+    } catch (const std::exception& ex) {
+        err << "Error applying multi threading settings: "
+            << ex.what();
+        return (isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str()));
+    }
+
+    return (answer);
+}
+
+isc::data::ConstElementPtr
+ControlledDhcpv6Srv::finishConfigHookLibraries(isc::data::ConstElementPtr config) {
+    ControlledDhcpv6Srv* srv = ControlledDhcpv6Srv::getInstance();
     // This hook point notifies hooks libraries that the configuration of the
     // DHCPv6 server has completed. It provides the hook library with the pointer
     // to the common IO service object, new server configuration in the JSON
@@ -1074,27 +1096,11 @@ ControlledDhcpv6Srv::processConfig(isc::data::ConstElementPtr config) {
         }
     }
 
-    // Apply multi threading settings.
-    // @note These settings are applied/updated only if no errors occur while
-    // applying the new configuration.
-    // @todo This should be fixed.
-    try {
-        CfgMultiThreading::apply(CfgMgr::instance().getStagingCfg()->getDHCPMultiThreading());
-    } catch (const std::exception& ex) {
-        err << "Error applying multi threading settings: "
-            << ex.what();
-        return (isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str()));
-    }
-
-    return (answer);
+    return (ConstElementPtr());
 }
 
 isc::data::ConstElementPtr
 ControlledDhcpv6Srv::checkConfig(isc::data::ConstElementPtr config) {
-
-    LOG_DEBUG(dhcp6_logger, DBG_DHCP6_COMMAND, DHCP6_CONFIG_RECEIVED)
-        .arg(redactConfig(config)->str());
-
     ControlledDhcpv6Srv* srv = ControlledDhcpv6Srv::getInstance();
 
     if (!srv) {
@@ -1103,6 +1109,9 @@ ControlledDhcpv6Srv::checkConfig(isc::data::ConstElementPtr config) {
         return (no_srv);
     }
 
+    LOG_DEBUG(dhcp6_logger, DBG_DHCP6_COMMAND, DHCP6_CONFIG_RECEIVED)
+        .arg(srv->redactConfig(config)->str());
+
     return (configureDhcp6Server(*srv, config, true));
 }
 
index adff1277838a693e3f902284eb5072d35695889c..41c2a223e386d10800044b7bddf517af8216f268 100644 (file)
@@ -105,21 +105,32 @@ public:
     /// As pointer to this method is used a callback in ASIO used in
     /// ModuleCCSession, it has to be static.
     ///
-    /// @param new_config textual representation of the new configuration
+    /// @param config textual representation of the new configuration
     ///
     /// @return status of the config update
     static isc::data::ConstElementPtr
-    processConfig(isc::data::ConstElementPtr new_config);
+    processConfig(isc::data::ConstElementPtr config);
 
     /// @brief Configuration checker
     ///
     /// This is a method for checking incoming configuration.
     ///
-    /// @param new_config JSON representation of the new configuration
+    /// @param config JSON representation of the new configuration
     ///
     /// @return status of the config check
-    isc::data::ConstElementPtr
-    checkConfig(isc::data::ConstElementPtr new_config);
+    static isc::data::ConstElementPtr
+    checkConfig(isc::data::ConstElementPtr config);
+
+    /// @brief Configuration checker for hook libraries
+    ///
+    /// This is a method for checking incoming configuration in the hooks
+    /// libraries. It calls dhcp4_srv_configured hook point for all hooks.
+    ///
+    /// @param config JSON representation of the new configuration
+    ///
+    /// @return status of the config check
+    static isc::data::ConstElementPtr
+    finishConfigHookLibraries(isc::data::ConstElementPtr config);
 
     /// @brief Returns pointer to the sole instance of Dhcpv6Srv
     ///
index 58e691c0a8c7154eaeff71ca54b5a3532ba7b448..96cb4630d81f6dd99ff87e5773fce869f2e88937 100644 (file)
 #include <cc/command_interpreter.h>
 #include <config/command_mgr.h>
 #include <database/dbaccess_parser.h>
-#include <dhcp6/json_config_parser.h>
+#include <dhcp6/ctrl_dhcp6_srv.h>
 #include <dhcp6/dhcp6_log.h>
 #include <dhcp6/dhcp6_srv.h>
+#include <dhcp6/json_config_parser.h>
 #include <dhcp/libdhcp++.h>
 #include <dhcp/iface_mgr.h>
 #include <dhcpsrv/cb_ctl_dhcp4.h>
@@ -867,7 +868,7 @@ processDhcp6Config(isc::data::ConstElementPtr config_set) {
 
 isc::data::ConstElementPtr
 configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
-                     bool check_only) {
+                     bool check_only, bool extra_checks) {
     if (!config_set) {
         ConstElementPtr answer = isc::config::createAnswer(CONTROL_RESULT_ERROR,
                                                            "Can't parse NULL config");
@@ -877,21 +878,14 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
     LOG_DEBUG(dhcp6_logger, DBG_DHCP6_COMMAND, DHCP6_CONFIG_START)
         .arg(server.redactConfig(config_set)->str());
 
-    // Rollback informs whether error occurred and original data
-    // have to be restored to global storages.
-    bool rollback = false;
-
     auto answer = processDhcp6Config(config_set);
 
-    int status_code = 0;
+    int status_code = CONTROL_RESULT_SUCCESS;
     isc::config::parseAnswer(status_code, answer);
-    if (status_code != CONTROL_RESULT_SUCCESS) {
-        rollback = true;
-    }
 
     SrvConfigPtr srv_config;
 
-    if (!rollback) {
+    if (status_code == CONTROL_RESULT_SUCCESS) {
         if (!check_only) {
             string parameter_name;
             ElementPtr mutable_cfg;
@@ -932,20 +926,33 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
                 LOG_ERROR(dhcp6_logger, DHCP6_PARSER_FAIL)
                           .arg(parameter_name).arg(ex.what());
                 answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, ex.what());
-
-                // An error occurred, so make sure that we restore original data.
-                rollback = true;
+                status_code = CONTROL_RESULT_ERROR;
             } catch (...) {
                 // For things like bad_cast in boost::lexical_cast
                 LOG_ERROR(dhcp6_logger, DHCP6_PARSER_EXCEPTION).arg(parameter_name);
                 answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, "undefined configuration"
                                                    " processing error");
-
-                // An error occurred, so make sure that we restore original data.
-                rollback = true;
+                status_code = CONTROL_RESULT_ERROR;
             }
         } else {
-            rollback = true;
+            if (extra_checks) {
+                // Re-open lease and host database with new parameters.
+                try {
+                    // Get the staging configuration.
+                    srv_config = CfgMgr::instance().getStagingCfg();
+
+                    CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
+                    string params = "universe=6 persist=false";
+                    if (cfg_db->getExtendedInfoTablesEnabled()) {
+                        params += " extended-info-tables=true";
+                    }
+                    cfg_db->setAppendedParameters(params);
+                    cfg_db->createManagers();
+                } catch (const std::exception& ex) {
+                    answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, ex.what());
+                    status_code = CONTROL_RESULT_ERROR;
+                }
+            }
         }
     }
 
@@ -953,12 +960,26 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
     // configuration. This will add created subnets and option values into
     // the server's configuration.
     // This operation should be exception safe but let's make sure.
-    if (!rollback) {
+    if (status_code == CONTROL_RESULT_SUCCESS && (!check_only || extra_checks)) {
         try {
 
             // Setup the command channel.
             configureCommandChannel();
+        } catch (const isc::Exception& ex) {
+            LOG_ERROR(dhcp6_logger, DHCP6_PARSER_COMMIT_FAIL).arg(ex.what());
+            answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, ex.what());
+            status_code = CONTROL_RESULT_ERROR;
+        } catch (...) {
+            // For things like bad_cast in boost::lexical_cast
+            LOG_ERROR(dhcp6_logger, DHCP6_PARSER_COMMIT_EXCEPTION);
+            answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, "undefined configuration"
+                                               " parsing error");
+            status_code = CONTROL_RESULT_ERROR;
+        }
+    }
 
+    if (status_code == CONTROL_RESULT_SUCCESS && (!check_only || extra_checks)) {
+        try {
             // No need to commit interface names as this is handled by the
             // CfgMgr::commit() function.
 
@@ -966,7 +987,21 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
             D2ClientConfigPtr cfg;
             cfg = CfgMgr::instance().getStagingCfg()->getD2ClientConfig();
             CfgMgr::instance().setD2ClientConfig(cfg);
+        } catch (const isc::Exception& ex) {
+            LOG_ERROR(dhcp6_logger, DHCP6_PARSER_COMMIT_FAIL).arg(ex.what());
+            answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, ex.what());
+            status_code = CONTROL_RESULT_ERROR;
+        } catch (...) {
+            // For things like bad_cast in boost::lexical_cast
+            LOG_ERROR(dhcp6_logger, DHCP6_PARSER_COMMIT_EXCEPTION);
+            answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, "undefined configuration"
+                                               " parsing error");
+            status_code = CONTROL_RESULT_ERROR;
+        }
+    }
 
+    if (status_code == CONTROL_RESULT_SUCCESS && (!check_only || extra_checks)) {
+        try {
             // This occurs last as if it succeeds, there is no easy way to
             // revert it.  As a result, the failure to commit a subsequent
             // change causes problems when trying to roll back.
@@ -978,35 +1013,32 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
         } catch (const isc::Exception& ex) {
             LOG_ERROR(dhcp6_logger, DHCP6_PARSER_COMMIT_FAIL).arg(ex.what());
             answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, ex.what());
-
-            // An error occurred, so make sure to restore the original data.
-            rollback = true;
+            status_code = CONTROL_RESULT_ERROR;
         } catch (...) {
             // For things like bad_cast in boost::lexical_cast
             LOG_ERROR(dhcp6_logger, DHCP6_PARSER_COMMIT_EXCEPTION);
             answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, "undefined configuration"
                                                " parsing error");
-
-            // An error occurred, so make sure to restore the original data.
-            rollback = true;
+            status_code = CONTROL_RESULT_ERROR;
         }
     }
 
     // Moved from the commit block to add the config backend indication.
-    if (!rollback) {
+    if (status_code == CONTROL_RESULT_SUCCESS && (!check_only || extra_checks)) {
         try {
-
-            // If there are config backends, fetch and merge into staging config
-            server.getCBControl()->databaseConfigFetch(srv_config,
-                                                       CBControlDHCPv6::FetchMode::FETCH_ALL);
+            if (extra_checks) {
+                server.getCBControl()->databaseConfigConnect(srv_config);
+            } else {
+                // If there are config backends, fetch and merge into staging config
+                server.getCBControl()->databaseConfigFetch(srv_config,
+                                                           CBControlDHCPv6::FetchMode::FETCH_ALL);
+            }
         } catch (const isc::Exception& ex) {
             std::ostringstream err;
             err << "during update from config backend database: " << ex.what();
             LOG_ERROR(dhcp6_logger, DHCP6_PARSER_COMMIT_FAIL).arg(err.str());
             answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str());
-
-            // An error occurred, so make sure to restore the original data.
-            rollback = true;
+            status_code = CONTROL_RESULT_ERROR;
         } catch (...) {
             // For things like bad_cast in boost::lexical_cast
             std::ostringstream err;
@@ -1014,17 +1046,23 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
                 << "undefined configuration parsing error";
             LOG_ERROR(dhcp6_logger, DHCP6_PARSER_COMMIT_FAIL).arg(err.str());
             answer = isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str());
-
-            // An error occurred, so make sure to restore the original data.
-            rollback = true;
+            status_code = CONTROL_RESULT_ERROR;
         }
     }
 
     // Rollback changes as the configuration parsing failed.
-    if (rollback) {
+    if (check_only || status_code != CONTROL_RESULT_SUCCESS) {
         // Revert to original configuration of runtime option definitions
         // in the libdhcp++.
         LibDHCP::revertRuntimeOptionDefs();
+
+        if (status_code == CONTROL_RESULT_SUCCESS && extra_checks) {
+            auto notify_libraries = ControlledDhcpv6Srv::finishConfigHookLibraries(config_set);
+            if (notify_libraries) {
+                return (notify_libraries);
+            }
+        }
+
         return (answer);
     }
 
index 8230d3550e7a4cc9c4880c1a9a92ab7a9ced6b44..883339bef98e777f3c6f921101293326792d8277 100644 (file)
 
 #include <string>
 
+/// @todo: This header file and its .cc counterpart are very similar between
+/// DHCPv4 and DHCPv6. They should be merged.
+
 namespace isc {
 namespace dhcp {
 
 class Dhcpv6Srv;
 
-/// @brief Configures DHCPv6 server
+/// @brief Configure DHCPv6 server (@c Dhcpv6Srv) with a set of configuration
+/// values.
+///
+/// This function parses configuration information stored in @c config_set
+/// and configures the @c server by applying the configuration to it.
+/// It provides the strong exception guarantee as long as the underlying
+/// derived class implementations of @c DhcpConfigParser meet the assumption,
+/// that is, it ensures that either configuration is fully applied or the
+/// state of the server is intact.
+///
+/// If a syntax or semantics level error happens during the configuration
+/// (such as malformed configuration or invalid configuration parameter),
+/// this function returns appropriate error code.
 ///
 /// This function is called every time a new configuration is received. The
 /// extra parameter is a reference to DHCPv6 server component. It is currently
@@ -32,17 +47,19 @@ class Dhcpv6Srv;
 /// reconfiguration statuses. It may return the following response codes:
 /// 0 - configuration successful
 /// 1 - malformed configuration (parsing failed)
-/// 2 - commit failed (parsing was successful, but the values could not be
-/// stored in the configuration).
+/// 2 - commit failed (parsing was successful, but failed to store the
+/// values in to server's configuration)
 ///
 /// @param server DHCPv6 server object.
-/// @param config_set a new configuration for DHCPv6 server.
-/// @param check_only whether this configuration is for testing only
+/// @param config_set a new configuration (JSON) for DHCPv6 server.
+/// @param check_only whether this configuration is for testing only.
+/// @param extra_checks load hooks and perform extra checks if this flag is true
+///        and check_only is also true, otherwise perform simple check if
+///        check_only is true.
 /// @return answer that contains result of the reconfiguration.
-/// @throw Dhcp6ConfigError if trying to create a parser for NULL config.
 isc::data::ConstElementPtr
 configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
-                     bool check_only = false);
+                     bool check_only = false, bool extra_checks = false);
 
 }  // namespace dhcp
 }  // namespace isc
index e1f4cd50db7adbb204b87efa27e3e9d1a39c0557..fcfff7df53508669f7f3a87d1d5d0ab8e1106116 100644 (file)
@@ -52,13 +52,15 @@ usage() {
          << endl;
     cerr << endl;
     cerr << "Usage: " << DHCP6_NAME
-         << " -[v|V|W] [-d] [-{c|t} cfgfile] [-p number] [-P number]" << endl;
+         << " -[v|V|W] [-d] [-{c|t|T} cfgfile] [-p number] [-P number]" << endl;
     cerr << "  -v: print version number and exit" << endl;
     cerr << "  -V: print extended version and exit" << endl;
     cerr << "  -W: display the configuration report and exit" << endl;
     cerr << "  -d: debug mode with extra verbosity (former -v)" << endl;
     cerr << "  -c file: specify configuration file" << endl;
     cerr << "  -t file: check the configuration file syntax and exit" << endl;
+    cerr << "  -T file: check the configuration file doing hooks load and extra "
+         << "checks and exit" << endl;
     cerr << "  -p number: specify non-standard server port number 1-65535 "
          << "(useful for testing only)" << endl;
     cerr << "  -P number: specify non-standard client port number 1-65535 "
@@ -76,11 +78,12 @@ main(int argc, char* argv[]) {
     int client_port_number = 0;
     bool verbose_mode = false; // Should server be verbose?
     bool check_mode = false;   // Check syntax
+    bool load_hooks = false;   // Check hooks config
 
     // The standard config file
     std::string config_file("");
 
-    while ((ch = getopt(argc, argv, "dvVWc:p:P:t:")) != -1) {
+    while ((ch = getopt(argc, argv, "dvVWc:p:P:t:T:")) != -1) {
         switch (ch) {
         case 'd':
             verbose_mode = true;
@@ -98,9 +101,16 @@ main(int argc, char* argv[]) {
             cout << isc::detail::getConfigReport() << endl;
             return (EXIT_SUCCESS);
 
+        case 'T':
+            load_hooks = true;
+            check_mode = true;
+            config_file = optarg;
+            break;
+
         case 't':
             check_mode = true;
-            // falls through
+            config_file = optarg;
+            break;
 
         case 'c': // config file
             config_file = optarg;
@@ -184,9 +194,11 @@ main(int argc, char* argv[]) {
             ControlledDhcpv6Srv server(0);
             ConstElementPtr answer;
 
+            server.setProcName(DHCP6_NAME);
+
             // Now we pass the Dhcp6 configuration to the server, but
             // tell it to check the configuration only (check_only = true)
-            answer = configureDhcp6Server(server, dhcp6, true);
+            answer = configureDhcp6Server(server, dhcp6, true, load_hooks);
 
             int status_code = 0;
             answer = isc::config::parseAnswer(status_code, answer);
index 95bd37cb4967088361c6c2298697bf51d78bf3bf..ca6ff1b45a13cfad38057d5ec9268eefdc1ad8fa 100644 (file)
@@ -20,6 +20,10 @@ static const int LIBRARY_NUMBER = 1;
 // issues related to namespaces.
 extern "C" {
 
+int (*do_load)(isc::hooks::LibraryHandle& handle);
+
+int (*do_unload)(isc::hooks::LibraryHandle& handle);
+
 /// @brief This function is called to retrieve the multi-threading compatibility.
 ///
 /// @return 1 which means compatible with multi-threading.
index 5dc72c52d19eb2ad7bb477427b81fe4574b45bb6..c76b2dc550050364f6e8385366551ae0295d6cd7 100644 (file)
@@ -14,3 +14,11 @@ static const int LIBRARY_NUMBER = 2;
 #include <config.h>
 
 #include <dhcp6/tests/callout_library_common.h>
+
+extern "C" {
+
+int (*do_load)(isc::hooks::LibraryHandle& handle);
+
+int (*do_unload)(isc::hooks::LibraryHandle& handle);
+
+}
index 5e5d9cb2e1850dff416ef086a8b36a67cfae1254..df4c44634c49ce33753feb8bb7e2ed03cbb5c91b 100644 (file)
@@ -24,6 +24,23 @@ using namespace isc::hooks;
 // issues related to namespaces.
 extern "C" {
 
+int
+do_load_impl(LibraryHandle& handle) {
+    // Determine if this callout is configured to fail.
+    isc::dhcp::SrvConfigPtr config;
+    isc::data::ConstElementPtr const& parameters(handle.getParameters());
+    isc::data::ConstElementPtr mode_element(parameters ? parameters->get("mode") : 0);
+    std::string mode(mode_element ? mode_element->stringValue() : "");
+    if (mode == "fail-on-load") {
+        return (1);
+    }
+    return (0);
+}
+
+int (*do_load)(isc::hooks::LibraryHandle& handle) = do_load_impl;
+
+int (*do_unload)(isc::hooks::LibraryHandle& handle);
+
 /// @brief Callout which appends library number and provided arguments to
 /// the marker file for dhcp6_srv_configured callout.
 ///
index 36f459ab2e88ab00cf442d4add38f6e5bac379d1..8ae600a08994b3f36ed91893c5941104c4035ff1 100644 (file)
 
 extern "C" {
 
+extern int (*do_load)(isc::hooks::LibraryHandle& handle);
+
+extern int (*do_unload)(isc::hooks::LibraryHandle& handle);
+
 /// @brief Append digit to marker file
 ///
 /// If the marker file does not exist, create it.  Then append the single
@@ -84,13 +88,23 @@ version() {
 }
 
 int
-load(isc::hooks::LibraryHandle&) {
-    return (appendDigit(LOAD_MARKER_FILE));
+load(isc::hooks::LibraryHandle& handle) {
+    int result = 0;
+    result = appendDigit(LOAD_MARKER_FILE);
+    if (result == 0 && do_load) {
+        result = do_load(handle);
+    }
+    return (result);
 }
 
 int
-unload() {
-    return (appendDigit(UNLOAD_MARKER_FILE));
+unload(isc::hooks::LibraryHandle& handle) {
+    int result = 0;
+    result = appendDigit(UNLOAD_MARKER_FILE);
+    if (result == 0 && do_unload) {
+        result = do_unload(handle);
+    }
+    return (result);
 }
 
 };
index 0265ec62a886e66665a81b7ecd9bd4f3178e089a..9cd2bc6bc8b22117cb9dabe840ac122d7f7a98f2 100644 (file)
@@ -24,10 +24,13 @@ LOG_FILE="@abs_top_builddir@/src/bin/dhcp6/tests/test.log"
 LEASE_FILE="@abs_top_builddir@/src/bin/dhcp6/tests/test_leases.csv"
 # Path to the Kea LFC application
 export KEA_LFC_EXECUTABLE="@abs_top_builddir@/src/bin/lfc/kea-lfc"
+# Path to test hooks library
+HOOK_PATH="@abs_top_builddir@/src/bin/dhcp6/tests/.libs/libco3.so"
 # Kea configuration to be stored in the configuration file.
 CONFIG="{
     \"Dhcp6\":
-    {   \"interfaces-config\": {
+    {
+        \"interfaces-config\": {
           \"interfaces\": [ ]
         },
         \"server-id\": {
@@ -67,6 +70,7 @@ CONFIG="{
         ]
     }
 }"
+
 # Invalid configuration (syntax error) to check that Kea can check syntax.
 # This config has following errors:
 # - it should be interfaces-config/interfaces, not interfaces
@@ -102,6 +106,7 @@ CONFIG_BAD_SYNTAX="{
         ]
     }
 }"
+
 # Invalid configuration (negative preferred-lifetime) to check that Kea
 # gracefully handles reconfiguration errors.
 CONFIG_INVALID="{
@@ -142,7 +147,8 @@ CONFIG_INVALID="{
 # it is defined in. Syntactically the config is correct, though.
 CONFIG_BAD_VALUES="{
     \"Dhcp6\":
-    {   \"interfaces-config\": {
+    {
+        \"interfaces-config\": {
           \"interfaces\": [ ]
         },
         \"server-id\": {
@@ -172,6 +178,117 @@ CONFIG_BAD_VALUES="{
     }
 }"
 
+# Invalid configuration (hook explicitly fails to load) to check that performing
+# extra configuration checks detects the error.
+INVALID_CONFIG_HOOKS_LOAD="{
+    \"Dhcp6\":
+    {
+        \"interfaces-config\": {
+          \"interfaces\": [ ]
+        },
+        \"multi-threading\": {
+          \"enable-multi-threading\": false
+        },
+        \"server-id\": {
+          \"type\": \"LLT\",
+          \"persist\": false
+        },
+        \"preferred-lifetime\": 3000,
+        \"valid-lifetime\": 4000,
+        \"renew-timer\": 1000,
+        \"rebind-timer\": 2000,
+        \"lease-database\":
+        {
+            \"type\": \"memfile\",
+            \"name\": \"$LEASE_FILE\",
+            \"persist\": false,
+            \"lfc-interval\": 0
+        },
+        \"subnet6\": [
+        {
+            \"subnet\": \"2001:db8:1::/64\",
+            \"pools\": [ { \"pool\": \"2001:db8:1::10-2001:db8:1::100\" } ]
+        } ],
+        \"dhcp-ddns\": {
+            \"enable-updates\": true,
+            \"qualifying-suffix\": \"\"
+        },
+        \"hooks-libraries\": [
+        {
+            \"library\": \"$HOOK_PATH\",
+                \"parameters\": {
+                    \"mode\": \"fail-on-load\"
+            }
+        } ],
+        \"loggers\": [
+        {
+            \"name\": \"kea-dhcp6\",
+            \"output_options\": [
+                {
+                    \"output\": \"$LOG_FILE\"
+                }
+            ],
+            \"severity\": \"INFO\"
+        }
+        ]
+    }
+}"
+
+# Invalid configuration (hook point returns error) to check that performing
+# extra configuration checks detects the error.
+INVALID_CONFIG_HOOKS_CALLOUT_FAIL="{
+    \"Dhcp6\":
+    {
+        \"interfaces-config\": {
+          \"interfaces\": [ ]
+        },
+        \"multi-threading\": {
+          \"enable-multi-threading\": false
+        },
+        \"server-id\": {
+          \"type\": \"LLT\",
+          \"persist\": false
+        },
+        \"preferred-lifetime\": 3000,
+        \"valid-lifetime\": 4000,
+        \"renew-timer\": 1000,
+        \"rebind-timer\": 2000,
+        \"lease-database\":
+        {
+            \"type\": \"memfile\",
+            \"name\": \"$LEASE_FILE\",
+            \"persist\": false,
+            \"lfc-interval\": 0
+        },
+        \"subnet6\": [
+        {
+            \"subnet\": \"2001:db8:1::/64\",
+            \"pools\": [ { \"pool\": \"2001:db8:1::10-2001:db8:1::100\" } ]
+        } ],
+        \"dhcp-ddns\": {
+            \"enable-updates\": true,
+            \"qualifying-suffix\": \"\"
+        },
+        \"hooks-libraries\": [
+        {
+            \"library\": \"$HOOK_PATH\",
+                \"parameters\": {
+                    \"mode\": \"fail-without-error\"
+            }
+        } ],
+        \"loggers\": [
+        {
+            \"name\": \"kea-dhcp6\",
+            \"output_options\": [
+                {
+                    \"output\": \"$LOG_FILE\"
+                }
+            ],
+            \"severity\": \"INFO\"
+        }
+        ]
+    }
+}"
 
 # Set the location of the executable.
 bin="kea-dhcp6"
@@ -189,15 +306,22 @@ syntax_check_test() {
     local test_name="${1}"
     local config="${2}"
     local expected_code="${3}"
+    local extra_check="${4}"
 
     # Log the start of the test and print test name.
     test_start "${test_name}"
     # Create correct configuration file.
     create_config "${config}"
     # Check it
-    printf "Running command %s.\n" "\"${bin_path}/${bin} -t ${CFG_FILE}\""
-    run_command \
-        "${bin_path}/${bin}" -t "${CFG_FILE}"
+    if [ "${extra_check}" -eq 1 ]; then
+        printf "Running command %s.\n" "\"${bin_path}/${bin} -T ${CFG_FILE}\""
+        run_command \
+            "${bin_path}/${bin}" -T "${CFG_FILE}"
+    else
+        printf "Running command %s.\n" "\"${bin_path}/${bin} -t ${CFG_FILE}\""
+        run_command \
+            "${bin_path}/${bin}" -t "${CFG_FILE}"
+    fi
     if [ "${EXIT_CODE}" -ne "${expected_code}" ]; then
         printf 'ERROR: expected exit code %s, got %s\n' "${expected_code}" "${EXIT_CODE}"
         clean_exit 1
@@ -479,7 +603,9 @@ shutdown_test "dhcpv6.sigint_test" 2
 version_test "dhcpv6.version"
 logger_vars_test "dhcpv6.variables"
 lfc_timer_test
-syntax_check_test "dhcpv6.syntax_check_success" "${CONFIG}" 0
-syntax_check_test "dhcpv6.syntax_check_bad_syntax" "${CONFIG_BAD_SYNTAX}" 1
-syntax_check_test "dhcpv6.syntax_check_bad_values" "${CONFIG_BAD_VALUES}" 1
+syntax_check_test "dhcpv6.syntax_check_success" "${CONFIG}" 0 0
+syntax_check_test "dhcpv6.syntax_check_bad_syntax" "${CONFIG_BAD_SYNTAX}" 1 0
+syntax_check_test "dhcpv6.syntax_check_bad_values" "${CONFIG_BAD_VALUES}" 1 0
+syntax_check_test "dhcpv6.syntax_check_hooks_load_fail" "${INVALID_CONFIG_HOOKS_LOAD}" 1 1
+syntax_check_test "dhcpv6.syntax_check_hooks_callout_fail" "${INVALID_CONFIG_HOOKS_CALLOUT_FAIL}" 1 1
 password_redact_test "dhcpv6.password_redact_test" "$(kea_dhcp_config 6)" 0
index 40825c407eb41d1112a6c10c4dcc7270fe35df2b..be1006c4ada3f8d95f9e15f48281fa520f5ffd05 100644 (file)
@@ -186,7 +186,7 @@ is internal server error and a bug report should be created.
 
 % HA_DHCP6_START_SERVICE_FAILED failed to start DHCPv4 HA service in dhcp6_srv_configured callout: %1
 This error message is issued when an attempt to start High Availability service
-for the DHCPv4 server failed in the dhcp4_srv_configured callout. This
+for the DHCPv6 server failed in the dhcp6_srv_configured callout. This
 is internal server error and a bug report should be created.
 
 % HA_DHCP_DISABLE_COMMUNICATIONS_FAILED failed to send request to disable DHCP service of %1: %2
@@ -242,7 +242,7 @@ servers to resume the HA service.
 
 % HA_INIT_OK loading High Availability hooks library successful
 This informational message indicates that the High Availability hooks library
-has been loaded successfully.
+has been loaded successfully. Enjoy!
 
 % HA_INVALID_PARTNER_STATE_COMMUNICATION_RECOVERY partner is in the communication-recovery state unexpectedly
 This warning message is issued when a partner is in the communication-recovery
index 3aa526c5ba90262209a8d12bc1336d5ff89a1bd6..77fc298342069af5066395d2c3add96b4ef1f04f 100644 (file)
@@ -545,7 +545,7 @@ Debug message issued when triggered an action to retrieve type
 
 % MYSQL_CB_INIT_OK loading MYSQL CB hooks library successful
 This informational message indicates that the MySQL Configuration Backend hooks
-library has been loaded successfully.
+library has been loaded successfully. Enjoy!
 
 % MYSQL_CB_NO_TLS TLS was required but is not used
 This error message is issued when TLS for the connection was required but
index 247ce0877bc3df35b8c2e32eb5de91f870be7652..0cd379a27840a9d8449e02c193eb5ebf9b7f5469 100644 (file)
@@ -545,7 +545,7 @@ Debug message issued when triggered an action to retrieve type
 
 % PGSQL_CB_INIT_OK loading Postgres CB hooks library successful
 This informational message indicates that the Postgres Configuration Backend hooks
-library has been loaded successfully.
+library has been loaded successfully. Enjoy!
 
 % PGSQL_CB_NO_TLS_SUPPORT Attempt to configure TLS (unsupported for PostgreSQL): %1
 This error message is printed when TLS support was required in the Kea
index d2c7ae81f36ae660428c8172f6c6a2242c4ca10d..c8b65fd41b231b356ff87e6625f3c2bc6f345cc8 100644 (file)
@@ -41,6 +41,12 @@ EXPECTED_VERSION="@PACKAGE_VERSION@"
 export KEA_LFC_EXECUTABLE="@abs_top_builddir@/src/bin/lfc/kea-lfc"
 export KEA_LOCKFILE_DIR="@abs_top_builddir@/test_lockfile_dir"
 export KEA_PIDFILE_DIR="@abs_top_builddir@/test_pidfile_dir"
+KEA_DHCP4_LOAD_MARKER_FILE="@abs_top_builddir@/src/bin/dhcp4/tests/load_marker.txt"
+KEA_DHCP4_UNLOAD_MARKER_FILE="@abs_top_builddir@/src/bin/dhcp4/tests/unload_marker.txt"
+KEA_DHCP4_SRV_CONFIG_MARKER_FILE="@abs_top_builddir@/src/bin/dhcp4/tests/srv_config_marker_file.txt"
+KEA_DHCP6_LOAD_MARKER_FILE="@abs_top_builddir@/src/bin/dhcp6/tests/load_marker.txt"
+KEA_DHCP6_UNLOAD_MARKER_FILE="@abs_top_builddir@/src/bin/dhcp6/tests/unload_marker.txt"
+KEA_DHCP6_SRV_CONFIG_MARKER_FILE="@abs_top_builddir@/src/bin/dhcp6/tests/srv_config_marker_file.txt"
 
 # A list of Kea processes, mainly used by the cleanup functions.
 KEA_PROCS="kea-dhcp4 kea-dhcp6 kea-dhcp-ddns kea-ctrl-agent"
@@ -656,7 +662,13 @@ cleanup() {
         "${CFG_FILE-}" \
         "${D2_CFG_FILE-}" \
         "${DHCP4_CFG_FILE-}" \
+        "${KEA_DHCP4_LOAD_MARKER_FILE-}" \
+        "${KEA_DHCP4_UNLOAD_MARKER_FILE-}" \
+        "${KEA_DHCP4_SRV_CONFIG_MARKER_FILE-}" \
         "${DHCP6_CFG_FILE-}" \
+        "${KEA_DHCP6_LOAD_MARKER_FILE-}" \
+        "${KEA_DHCP6_UNLOAD_MARKER_FILE-}" \
+        "${KEA_DHCP6_SRV_CONFIG_MARKER_FILE-}" \
         "${KEACTRL_CFG_FILE-}" \
         "${KEA_LOCKFILE_DIR-}" \
         "${KEA_PIDFILE_DIR-}" \