]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[596-add-a-hook-point-for-post-reconfiguration] Added cb[46]_updated hook points 596-add-a-hook-point-for-post-reconfiguration
authorFrancis Dupont <fdupont@isc.org>
Tue, 8 Oct 2019 09:34:39 +0000 (11:34 +0200)
committerFrancis Dupont <fdupont@isc.org>
Tue, 5 Nov 2019 10:13:14 +0000 (11:13 +0100)
src/bin/dhcp4/dhcp4_hooks.dox
src/bin/dhcp6/dhcp6_hooks.dox
src/lib/database/audit_entry.h
src/lib/dhcpsrv/cb_ctl_dhcp4.cc
src/lib/dhcpsrv/cb_ctl_dhcp6.cc
src/lib/dhcpsrv/tests/cb_ctl_dhcp_unittest.cc

index a152b88f0acf55e411be316012c05f02f088c78b..53209b4dea163ac36568600363d78f43e234358b 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-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
@@ -66,6 +66,18 @@ to the end of this list.
  - <b>Next step status</b>: Status codes retured by the callouts installed on
    this hook point are ignored.
 
+ @subsection dhcpv4HooksCb4Update cb4_updated
+ - @b Arguments:
+   - name: audit_entries, type isc::db::AuditEntryCollectionPtr, direction: <b>in</b>
+
+ - @b Description: this callout is executed when the server has completed
+   a configuration update using the Config Backend. The server provides
+   the audit entries as a never null pointer to a not empty collection
+   copied from the update apply method argument.
+
+ - <b>Next step status</b>: Status codes retured by the callouts installed on
+   this hook point are ignored.
+
  @subsection dhcpv4HooksBuffer4Receive buffer4_receive
 
  - @b Arguments:
index 8b76fd5a0478fb4bc6412ef6bef0b96bc9e7f4f6..d15551c99d2045263318ed3806748620e172c095 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-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
@@ -66,6 +66,18 @@ to the end of this list.
  - <b>Next step status</b>: Status codes retured by the callouts installed on
    this hook point are ignored.
 
+ @subsection dhcpv6HooksCb6Update cb6_updated
+ - @b Arguments:
+   - name: audit_entries, type isc::db::AuditEntryCollectionPtr, direction: <b>in</b>
+
+ - @b Description: this callout is executed when the server has completed
+   a configuration update using the Config Backend. The server provides
+   the audit entries as a never null pointer to a not empty collection
+   copied from the update apply method argument.
+
+ - <b>Next step status</b>: Status codes retured by the callouts installed on
+   this hook point are ignored.
+
  @subsection dhcpv6HooksBuffer6Receive buffer6_receive
 
  - @b Arguments:
index bc5617ffe57c773b679ccc96637043ca0286f817..465705fcf6ba3ab3f2814c9e7a879b41cd24d472 100644 (file)
@@ -241,6 +241,9 @@ typedef boost::multi_index_container<
     >
 > AuditEntryCollection;
 
+//// @brief Pointer to the @c AuditEntryCollection object.
+typedef boost::shared_ptr<AuditEntryCollection> AuditEntryCollectionPtr;
+
 } // end of namespace isc::db
 } // end of namespace isc
 
index b08a9dd0acf82f78ab7b3e2ae41ade918369bb24..98dd526a6a06611dc620a6c24f7ebe177093fa72 100644 (file)
@@ -9,10 +9,33 @@
 #include <dhcpsrv/cfgmgr.h>
 #include <dhcpsrv/dhcpsrv_log.h>
 #include <dhcpsrv/parsers/simple_parser4.h>
+#include <hooks/callout_handle.h>
+#include <hooks/hooks_manager.h>
 
 using namespace isc::db;
 using namespace isc::data;
 using namespace isc::process;
+using namespace isc::hooks;
+
+namespace {
+
+/// Structure that holds registered hook indexes.
+struct CbCtlHooks {
+    int hook_index_cb4_updated_; ///< index for "cb4_updated" hook point.
+
+    /// Constructor that registers hook points for CBControlDHCPv4.
+    CbCtlHooks() {
+        hook_index_cb4_updated_ = HooksManager::registerHook("cb4_updated");
+    }
+};
+
+// Declare a Hooks object. As this is outside any function or method, it
+// will be instantiated (and the constructor run) when the module is loaded.
+// As a result, the hook indexes will be defined before any method in this
+// module is called.
+CbCtlHooks hooks_;
+
+}; // anonymous namespace
 
 namespace isc {
 namespace dhcp {
@@ -184,8 +207,27 @@ CBControlDHCPv4::databaseConfigApply(const BackendSelector& backend_selector,
         CfgMgr::instance().mergeIntoCurrentCfg(external_cfg->getSequence());
     }
     LOG_INFO(dhcpsrv_logger, DHCPSRV_CFGMGR_CONFIG4_MERGED);
-}
 
+    if (!audit_entries.empty() &&
+        HooksManager::getHooksManager().calloutsPresent(hooks_.hook_index_cb4_updated_)) {
+        CalloutHandlePtr callout_handle =  HooksManager::createCalloutHandle();
+
+        // Use the RAII wrapper to make sure that the callout handle state is
+        // reset when this object goes out of scope. All hook points must do
+        // it to prevent possible circular dependency between the callout
+        // handle and its arguments.
+        ScopedCalloutHandleState callout_handle_state(callout_handle);
+
+        // Pass a shared pointer to audit entries.
+        AuditEntryCollectionPtr ptr(new AuditEntryCollection(audit_entries));
+        callout_handle->setArgument("audit_entries", ptr);
+
+        // Call the callouts
+        HooksManager::callCallouts(hooks_.hook_index_cb4_updated_, *callout_handle);
+
+        // Ignore the result.
+    }
+}
 
 } // end of namespace isc::dhcp
 } // end of namespace isc
index 3e58da9c823be21842350300ffd9bb98fab64963..b43d5bcf2791c456ba8af55e3050a60e07b3243f 100644 (file)
@@ -9,10 +9,33 @@
 #include <dhcpsrv/cfgmgr.h>
 #include <dhcpsrv/dhcpsrv_log.h>
 #include <dhcpsrv/parsers/simple_parser6.h>
+#include <hooks/callout_handle.h>
+#include <hooks/hooks_manager.h>
 
 using namespace isc::db;
 using namespace isc::data;
 using namespace isc::process;
+using namespace isc::hooks;
+
+namespace {
+
+/// Structure that holds registered hook indexes.
+struct CbCtlHooks {
+    int hook_index_cb6_updated_; ///< index for "cb6_updated" hook point.
+
+    /// Constructor that registers hook points for CBControlDHCPv6.
+    CbCtlHooks() {
+        hook_index_cb6_updated_ = HooksManager::registerHook("cb6_updated");
+    }
+};
+
+// Declare a Hooks object. As this is outside any function or method, it
+// will be instantiated (and the constructor run) when the module is loaded.
+// As a result, the hook indexes will be defined before any method in this
+// module is called.
+CbCtlHooks hooks_;
+
+}; // anonymous namespace
 
 namespace isc {
 namespace dhcp {
@@ -183,8 +206,27 @@ CBControlDHCPv6::databaseConfigApply(const db::BackendSelector& backend_selector
         CfgMgr::instance().mergeIntoCurrentCfg(external_cfg->getSequence());
     }
     LOG_INFO(dhcpsrv_logger, DHCPSRV_CFGMGR_CONFIG6_MERGED);
-}
 
+    if (!audit_entries.empty() &&
+        HooksManager::getHooksManager().calloutsPresent(hooks_.hook_index_cb6_updated_)) {
+        CalloutHandlePtr callout_handle =  HooksManager::createCalloutHandle();
+
+        // Use the RAII wrapper to make sure that the callout handle state is
+        // reset when this object goes out of scope. All hook points must do
+        // it to prevent possible circular dependency between the callout
+        // handle and its arguments.
+        ScopedCalloutHandleState callout_handle_state(callout_handle);
+
+        // Pass a shared pointer to audit entries.
+        AuditEntryCollectionPtr ptr(new AuditEntryCollection(audit_entries));
+        callout_handle->setArgument("audit_entries", ptr);
+
+        // Call the callouts
+        HooksManager::callCallouts(hooks_.hook_index_cb6_updated_, *callout_handle);
+
+        // Ignore the result.
+    }
+}
 
 } // end of namespace isc::dhcp
 } // end of namespace isc
index 118fe1bd4d934e530f38c680a15d6ac0520379bc..e61c30cb1152338e09b7948139a7661340a9c86a 100644 (file)
@@ -15,6 +15,9 @@
 #include <dhcpsrv/testutils/generic_backend_unittest.h>
 #include <dhcpsrv/testutils/test_config_backend_dhcp4.h>
 #include <dhcpsrv/testutils/test_config_backend_dhcp6.h>
+#include <hooks/server_hooks.h>
+#include <hooks/callout_manager.h>
+#include <hooks/hooks_manager.h>
 #include <boost/date_time/posix_time/posix_time.hpp>
 #include <gtest/gtest.h>
 #include <map>
@@ -26,6 +29,7 @@ using namespace isc::data;
 using namespace isc::dhcp;
 using namespace isc::dhcp::test;
 using namespace isc::process;
+using namespace isc::hooks;
 
 namespace {
 
@@ -38,6 +42,8 @@ public:
         : timestamp_(), object_timestamp_(), audit_entries_() {
         CfgMgr::instance().clear();
         initTimestamps();
+        callback_name_ = std::string("");
+        callback_audit_entries_.reset();
     }
 
     /// @brief Destructor.
@@ -45,6 +51,9 @@ public:
         // Unregister the factory to be tidy.
         ConfigBackendDHCPv4Mgr::instance().unregisterBackendFactory("memfile");
         CfgMgr::instance().clear();
+        // Unregister hooks.
+        HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("cb4_updated");
+        HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts("cb6_updated");
     }
 
     /// @brief Creates new CREATE audit entry.
@@ -160,6 +169,26 @@ public:
         return (false);
     }
 
+    /// @brief Callback that stores received callout name and received value.
+    ///
+    /// @param callout_handle Callout handle.
+    static int
+    cb4_updated_callout(CalloutHandle& callout_handle) {
+        callback_name_ = std::string("cb4_updated");
+        callout_handle.getArgument("audit_entries", callback_audit_entries_);
+        return (0);
+    }
+
+    /// @brief Callback that stores received callout name and received value.
+    ///
+    /// @param callout_handle Callout handle.
+    static int
+    cb6_updated_callout(CalloutHandle& callout_handle) {
+        callback_name_ = std::string("cb6_updated");
+        callout_handle.getArgument("audit_entries", callback_audit_entries_);
+        return (0);
+    }
+
     /// @brief Holds test timestamps.
     std::map<int, boost::posix_time::ptime> timestamp_;
 
@@ -168,8 +197,17 @@ public:
 
     /// @brief Collection of audit entries used in the unit tests.
     AuditEntryCollection audit_entries_;
+
+    /// @brief Callback name.
+    static std::string callback_name_;
+
+    /// @brief Callback value.
+    static AuditEntryCollectionPtr callback_audit_entries_;
 };
 
+std::string CBControlDHCPTest::callback_name_;
+AuditEntryCollectionPtr CBControlDHCPTest::callback_audit_entries_;
+
 // ************************ V4 tests *********************
 
 /// @brief Naked @c CBControlDHCPv4 class exposing protected methods.
@@ -764,6 +802,32 @@ TEST_F(CBControlDHCPv4Test, databaseConfigApplySubnetNotFetched) {
     testDatabaseConfigApply(getTimestamp(-3));
 }
 
+// This test verifies that the configuration updates calls the hook.
+TEST_F(CBControlDHCPv4Test, databaseConfigApplyHook) {
+
+    // Initialize Hooks Manager.
+    HooksManager::loadLibraries(HookLibsCollection());
+
+    // Install cb4_updated.
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "cb4_updated", cb4_updated_callout));
+
+    // Create audit entries.
+    addCreateAuditEntry("dhcp4_global_parameter");
+    addCreateAuditEntry("dhcp4_option_def");
+    addCreateAuditEntry("dhcp4_options");
+    addCreateAuditEntry("dhcp4_shared_network");
+    addCreateAuditEntry("dhcp4_subnet");
+
+    // Run the test.
+    testDatabaseConfigApply(getTimestamp(-5));
+
+    // Checks the callout.
+    EXPECT_EQ("cb4_updated", callback_name_);
+    ASSERT_TRUE(callback_audit_entries_);
+    EXPECT_TRUE(audit_entries_ == *callback_audit_entries_);
+}
+
 // ************************ V6 tests *********************
 
 /// @brief Naked @c CBControlDHCPv6 class exposing protected methods.
@@ -1362,4 +1426,30 @@ TEST_F(CBControlDHCPv6Test, databaseConfigApplySubnetNotFetched) {
     testDatabaseConfigApply(getTimestamp(-3));
 }
 
+// This test verifies that the configuration updates calls the hook.
+TEST_F(CBControlDHCPv6Test, databaseConfigApplyHook) {
+
+    // Initialize Hooks Manager.
+    HooksManager::loadLibraries(HookLibsCollection());
+
+    // Install cb6_updated.
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "cb6_updated", cb6_updated_callout));
+
+    // Create audit entries.
+    addCreateAuditEntry("dhcp6_global_parameter");
+    addCreateAuditEntry("dhcp6_option_def");
+    addCreateAuditEntry("dhcp6_options");
+    addCreateAuditEntry("dhcp6_shared_network");
+    addCreateAuditEntry("dhcp6_subnet");
+
+    // Run the test.
+    testDatabaseConfigApply(getTimestamp(-5));
+
+    // Checks the callout.
+    EXPECT_EQ("cb6_updated", callback_name_);
+    ASSERT_TRUE(callback_audit_entries_);
+    EXPECT_TRUE(audit_entries_ == *callback_audit_entries_);
+}
+
 }