-// 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
- <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:
-// 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
- <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:
>
> AuditEntryCollection;
+//// @brief Pointer to the @c AuditEntryCollection object.
+typedef boost::shared_ptr<AuditEntryCollection> AuditEntryCollectionPtr;
+
} // end of namespace isc::db
} // end of namespace isc
#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 {
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
#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 {
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
#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>
using namespace isc::dhcp;
using namespace isc::dhcp::test;
using namespace isc::process;
+using namespace isc::hooks;
namespace {
: timestamp_(), object_timestamp_(), audit_entries_() {
CfgMgr::instance().clear();
initTimestamps();
+ callback_name_ = std::string("");
+ callback_audit_entries_.reset();
}
/// @brief Destructor.
// 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.
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_;
/// @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.
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.
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_);
+}
+
}