Commit 390c1a76 authored by Stephen Morris's avatar Stephen Morris
Browse files

[2980] Basic library manager functionality added

Also started to add logging.
parent 0a4612cf
......@@ -10,17 +10,33 @@ AM_CXXFLAGS = $(B10_CXXFLAGS)
# But older GCC compilers don't have the flag.
AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
CLEANFILES = *.gcno *.gcda
# Define rule to build logging source files from message file
hooks_messages.h hooks_messages.cc: hooks_messages.mes
$(top_builddir)/src/lib/log/compiler/message $(top_srcdir)/src/lib/hooks/hooks_messages.mes
# Tell automake that the message files are built as part of the build process
# (so that they are built before the main library is built).
BUILT_SOURCES = hooks_messages.h hooks_messages.cc
# Ensure that the message file is included in the distribution
EXTRA_DIST = hooks_messages.mes
# Get rid of generated message files on a clean
CLEANFILES = *.gcno *.gcda hooks_messages.h hooks_messages.cc
lib_LTLIBRARIES = libb10-hooks.la
libb10_hooks_la_SOURCES =
libb10_hooks_la_SOURCES += callout_handle.cc callout_handle.h
libb10_hooks_la_SOURCES += callout_manager.cc callout_manager.h
libb10_hooks_la_SOURCES += hooks.h
libb10_hooks_la_SOURCES += hooks_log.cc hooks_log.h
libb10_hooks_la_SOURCES += library_handle.cc library_handle.h
libb10_hooks_la_SOURCES += library_manager.cc library_manager.h
libb10_hooks_la_SOURCES += server_hooks.cc server_hooks.h
nodist_libb10_hooks_la_SOURCES = hooks_messages.cc hooks_messages.h
libb10_hooks_la_CXXFLAGS = $(AM_CXXFLAGS)
libb10_hooks_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
libb10_hooks_la_LDFLAGS = $(AM_LDFLAGS) -ldl
......
// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
/// Defines the logger used by the NSAS
#include "hooks/hooks_log.h"
namespace isc {
namespace hooks {
isc::log::Logger hooks_logger("hooks");
} // namespace hooks
} // namespace isc
// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#ifndef HOOKS_LOG_H
#define HOOKS_LOG_H
#include <log/macros.h>
#include <hooks/hooks_messages.h>
namespace isc {
namespace hooks {
/// \brief Hooks system Logging
///
/// Defines the levels used to output debug messages in the Hooks framework.
/// Note that higher numbers equate to more verbose (and detailed) output.
// The first level traces normal operations,
const int HOOKS_DBG_TRACE = DBGLVL_TRACE_BASIC;
// The next level traces each call to hook code.
const int HOOKS_DBG_CALLS = DBGLVL_TRACE_BASIC_DATA;
// Additional information on the calls. Report each call to a callout (even
// if there are multiple callouts on a hook) and each status return.
const int HOOKS_DBG_EXTENDED_CALLS = DBGLVL_TRACE_DETAIL_DATA;
/// \brief HOOKS Logger
///
/// Define the logger used to log messages. We could define it in multiple
/// modules, but defining in a single module and linking to it saves time and
/// space.
extern isc::log::Logger hooks_logger; // isc::hooks::logger is the HOOKS logger
} // namespace hooks
} // namespace isc
#endif // HOOKS_LOG_H
# Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
$NAMESPACE isc::hooks
% HOOKS_CLOSE_ERROR failed to close hook library %1: %2
BIND 10 has failed to close the named hook library for the stated reason.
Although this is an error, this should not affect the running system other
than as a loss of resources. If this error persists, you should restart
BIND 10.
% HOOKS_INCORRECT_VERSION hook library %1 is at version %2, require version %3
BIND 10 has detected that the named hook library has been built against
a version of BIND 10 that is incompatible with the version of BIND 10
running on your system. It has not loaded the library.
This is most likely due to the installation of a new version of BIND 10
without rebuilding the hook library. A rebuild and re-install of the library
should fix the problem in most cases.
% HOOKS_NO_VERSION no version() function found in hook library %1
The shared library named in the message was found and successfully loaded, but
BIND 10 did not find a function named 'version' in it. This function is
required and should return the version of BIND 10 against which the library
was built. The value is used to check that the library was built against a
compatible version of BIND 10. The library has not been loaded.
% HOOKS_OPEN_ERROR failed to open hook library %1: %2
BIND 10 failed to open the specified hook library for the stated reason. The
library has not been loaded. BIND 10 will continue to function, but without
the services offered by the library.
% HOOKS_REGISTER_CALLOUT library %1 has registered a callout for hook %2
This is a debug message, output when the library loading function has located
a standard callout (a callout with the same name as a hook point) and
registered it.
......@@ -109,7 +109,6 @@ protected:
/// when this method was called.
bool closeLibrary();
/// @brief Check library version
///
/// With the library open, accesses the "version()" function and, if
......@@ -122,6 +121,13 @@ protected:
/// @return bool true if the check succeeded
bool checkVersion() const;
/// @brief Register standard callouts
///
/// Loops through the list of hook names and searches the library for
/// functions with those names. Any that are found are registered as
/// callouts for that hook.
void registerStandardCallouts();
private:
void* dl_handle_; ///< Handle returned by dlopen
int index_; ///< Index associated with this library
......
......@@ -25,12 +25,12 @@
///
/// - A context_create callout is supplied.
///
/// - Three other callouts are supplied. Two do some trivial calculations
/// on the arguments supplied to it and the context variables. The
/// third returns the results through the "result" argument, and this is
/// checked by the test program.
/// - Three other callouts are supplied. All do some trivial calculationsll
/// on the arguments supplied to it and the context variables, returning
/// intermediate results through the "result" argument.
#include <hooks/hooks.h>
#include <iostream>
using namespace isc::hooks;
......@@ -46,13 +46,14 @@ version() {
int
context_create(CalloutHandle& handle) {
handle.setContext("result", static_cast<int>(10));
handle.setArgument("result", static_cast<int>(10));
return (0);
}
// First callout adds the passed "data_1" argument to the initialized context
// value of 10.
int basic_one(CalloutHandle& handle) {
int lm_one(CalloutHandle& handle) {
int data;
handle.getArgument("data_1", data);
......@@ -61,6 +62,7 @@ int basic_one(CalloutHandle& handle) {
result += data;
handle.setContext("result", result);
handle.setArgument("result", result);
return (0);
}
......@@ -69,7 +71,7 @@ int basic_one(CalloutHandle& handle) {
// argument.
int
basic_two(CalloutHandle& handle) {
lm_two(CalloutHandle& handle) {
int data;
handle.getArgument("data_2", data);
......@@ -78,17 +80,22 @@ basic_two(CalloutHandle& handle) {
result *= data;
handle.setContext("result", result);
handle.setArgument("result", result);
return (0);
}
// Final callout returns the value in the context through the "result"
// argument.
// Final callout subtracts the result in "data_3" and.
int
basic_three(CalloutHandle& handle) {
lm_three(CalloutHandle& handle) {
int data;
handle.getArgument("data_3", data);
int result;
handle.getContext("result", result);
result -= data;
handle.setArgument("result", result);
return (0);
......
// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <hooks/callout_handle.h>
#include <hooks/callout_manager.h>
#include <hooks/library_manager.h>
#include <hooks/server_hooks.h>
#include <gtest/gtest.h>
#include <algorithm>
#include <string>
#include <vector>
using namespace isc;
using namespace isc::hooks;
using namespace std;
/// @brief Library manager test class
class LibraryManagerTest : public ::testing::Test {
public:
/// @brief Constructor
///
/// Sets up a collection of three LibraryHandle objects to use in the test.
LibraryManagerTest() {
// Set up the server hooks. There is sone singleton for all tests,
// so reset it and explicitly set up the hooks for the test.
ServerHooks& hooks = ServerHooks::getServerHooks();
hooks.reset();
alpha_index_ = hooks.registerHook("alpha");
beta_index_ = hooks.registerHook("beta");
gamma_index_ = hooks.registerHook("gamma");
// Set up the callout manager with these hooks. Assume a maximum of
// four libraries.
callout_manager_.reset(new CalloutManager(1));
// Set up the callout handle.
callout_handle_.reset(new CalloutHandle(callout_manager_));
}
/// @brief Return the callout handle
CalloutHandle& getCalloutHandle() {
return (*callout_handle_);
}
/// @brief Return the callout manager
boost::shared_ptr<CalloutManager> getCalloutManager() {
return (callout_manager_);
}
/// Hook indexes. These are somewhat ubiquitous, so are made public for
/// ease of reference instead of being accessible by a function.
int alpha_index_;
int beta_index_;
int gamma_index_;
private:
/// Callout handle used in calls
boost::shared_ptr<CalloutHandle> callout_handle_;
/// Callout manager used for the test
boost::shared_ptr<CalloutManager> callout_manager_;
};
/// @brief Library manager class
///
/// This is an instance of the LibraryManager class but with the protected
/// methods made public for test purposes.
class PublicLibraryManager : public isc::hooks::LibraryManager {
public:
/// @brief Constructor
///
/// Stores the library name. The actual loading is done in loadLibrary().
///
/// @param name Name of the library to load. This should be an absolute
/// path name.
/// @param index Index of this library
/// @param manager CalloutManager object
PublicLibraryManager(const std::string& name, int index,
const boost::shared_ptr<CalloutManager>& manager)
: LibraryManager(name, index, manager)
{}
/// Public methods that call protected methods on the superclass
//@{
/// @brief Open library
///
/// Opens the library associated with this LibraryManager. A message is
/// logged on an error.
///
/// @return true if the library opened successfully, false otherwise.
bool openLibrary() {
return (LibraryManager::openLibrary());
}
/// @brief Close library
///
/// Closes the library associated with this LibraryManager. A message is
/// logged on an error.
///
/// @return true if the library closed successfully, false otherwise.
bool closeLibrary() {
return (LibraryManager::closeLibrary());
}
/// @brief Check library version
///
/// With the library open, accesses the "version()" function and, if
/// present, checks the returned value against the hooks version symbol
/// for the currently running BIND 10.
///
/// If there is no version() function, or if there is a mismatch in
/// version number, a message logged.
///
/// @return bool true if the check succeeded
bool checkVersion() const {
return (LibraryManager::checkVersion());
}
//@}
};
// Names of the libraries used in these tests. These libraries are built using
// libtool, so we need to look in the hidden ".libs" directory to locate the
// .so file. Note that we access the .so file - libtool creates this as a
// like to the real shared library.
static const char* NOT_PRESENT_LIBRARY = "/home/stephen/bind10/src/lib/hooks/tests/.libs/libnothere.so";
static const char* NO_VERSION_LIBRARY = "/home/stephen/bind10/src/lib/hooks/tests/.libs/libnv.so";
static const char* INCORRECT_VERSION_LIBRARY = "/home/stephen/bind10/src/lib/hooks/tests/.libs/libiv.so";
static const char* BASIC_CALLOUT_LIBRARY = "/home/stephen/bind10/src/lib/hooks/tests/.libs/libbco.so";
namespace {
// Tests that OpenLibrary reports an error for an unknown library.
TEST_F(LibraryManagerTest, NonExistentLibrary) {
// Check that opening a non-existent library fails.
PublicLibraryManager lib_manager(std::string(NOT_PRESENT_LIBRARY),
0, getCalloutManager());
EXPECT_FALSE(lib_manager.openLibrary());
}
// Tests that OpenLibrary handles the case of no version present.
TEST_F(LibraryManagerTest, NoVersionFunction) {
PublicLibraryManager lib_manager(std::string(NO_VERSION_LIBRARY),
0, getCalloutManager());
// Open should succeed.
EXPECT_TRUE(lib_manager.openLibrary());
// Version check should fail.
EXPECT_FALSE(lib_manager.checkVersion());
// Tidy up.
EXPECT_TRUE(lib_manager.closeLibrary());
}
// Tests that OpenLibrary reports an error for an unknown library.
TEST_F(LibraryManagerTest, IncorrectVersionReturned) {
PublicLibraryManager lib_manager(std::string(INCORRECT_VERSION_LIBRARY),
0, getCalloutManager());
// Open should succeed.
EXPECT_TRUE(lib_manager.openLibrary());
// Version check should fail.
EXPECT_FALSE(lib_manager.checkVersion());
// Tidy up.
EXPECT_TRUE(lib_manager.closeLibrary());
}
// Tests that the openLibrary() and closeLibrary() methods work.
TEST_F(LibraryManagerTest, OpenClose) {
// Create the library manager.
PublicLibraryManager lib_manager(std::string(BASIC_CALLOUT_LIBRARY),
0, getCalloutManager());
// Open and close the library
EXPECT_TRUE(lib_manager.openLibrary());
EXPECT_TRUE(lib_manager.closeLibrary());
// Check that closing an already closed library causes no problems.
EXPECT_TRUE(lib_manager.closeLibrary());
}
// Checks the basic functionality - loads a library where the callouts are
// named after the hooks, calls the callouts and checks the results.
TEST_F(LibraryManagerTest, BasicCalloutTest) {
// Load the only library, specifying the index of 0 as it's the only
// library. This should load all callouts.
LibraryManager lib_manager(std::string(BASIC_CALLOUT_LIBRARY),
0, getCalloutManager());
EXPECT_NO_THROW(lib_manager.loadLibrary());
// Set up abbreviations...
boost::shared_ptr<CalloutManager> co_manager = getCalloutManager();
CalloutHandle& callout_handle = getCalloutHandle();
// Now execute the callouts in the order expected. context_create
// always comes first. This sets the context value to 10.
co_manager->callCallouts(ServerHooks::CONTEXT_CREATE, callout_handle);
// First callout adds 5 to the context value.
callout_handle.setArgument("data_1", static_cast<int>(5));
co_manager->callCallouts(alpha_index_, callout_handle);
// Second callout multiples the context value by 7
callout_handle.setArgument("data_2", static_cast<int>(7));
co_manager->callCallouts(beta_index_, callout_handle);
// Third callour retrieves the context value.
co_manager->callCallouts(gamma_index_, callout_handle);
int result;
callout_handle.getArgument("result", result);
EXPECT_EQ(105, result);
}
} // Anonymous namespace
......@@ -23,6 +23,8 @@
#include <string>
#include <vector>
#include <iostream>
using namespace isc;
using namespace isc::hooks;
using namespace std;
......@@ -40,9 +42,9 @@ public:
// so reset it and explicitly set up the hooks for the test.
ServerHooks& hooks = ServerHooks::getServerHooks();
hooks.reset();
alpha_index_ = hooks.registerHook("alpha");
beta_index_ = hooks.registerHook("beta");
gamma_index_ = hooks.registerHook("gamma");
lm_one_index_ = hooks.registerHook("lm_one");
lm_two_index_ = hooks.registerHook("lm_two");
lm_three_index_ = hooks.registerHook("lm_three");
// Set up the callout manager with these hooks. Assume a maximum of
// four libraries.
......@@ -52,23 +54,12 @@ public:
callout_handle_.reset(new CalloutHandle(callout_manager_));
}
/// @brief Return the callout handle
CalloutHandle& getCalloutHandle() {
return (*callout_handle_);
}
/// @brief Return the callout manager
boost::shared_ptr<CalloutManager> getCalloutManager() {
return (callout_manager_);
}
/// Hook indexes. These are somewhat ubiquitous, so are made public for
/// ease of reference instead of being accessible by a function.
int alpha_index_;
int beta_index_;
int gamma_index_;
int lm_one_index_;
int lm_two_index_;
int lm_three_index_;
private:
/// Callout handle used in calls
boost::shared_ptr<CalloutHandle> callout_handle_;
......@@ -90,51 +81,26 @@ public:
///
/// @param name Name of the library to load. This should be an absolute
/// path name.
/// @param index Index of this library
/// @param index Index of this library. For all these tests, it will be
/// zero, as we are only using one library.
/// @param manager CalloutManager object
PublicLibraryManager(const std::string& name, int index,
const boost::shared_ptr<CalloutManager>& manager)
: LibraryManager(name, index, manager)
{}
/// Public methods that call protected methods on the superclass
//@{
/// @brief Open library
///
/// Opens the library associated with this LibraryManager. A message is
/// logged on an error.
///
/// @return true if the library opened successfully, false otherwise.
bool openLibrary() {
return (LibraryManager::openLibrary());
}
/// @brief Close library
///
/// Closes the library associated with this LibraryManager. A message is
/// logged on an error.
///
/// @return true if the library closed successfully, false otherwise.
bool closeLibrary() {
return (LibraryManager::closeLibrary());
}
/// @brief Check library version
///
/// With the library open, accesses the "version()" function and, if
/// present, checks the returned value against the hooks version symbol
/// for the currently running BIND 10.
/// @brief Destructor
///
/// If there is no version() function, or if there is a mismatch in
/// version number, a message logged.
///
/// @return bool true if the check succeeded
bool checkVersion() const {
return (LibraryManager::checkVersion());
/// Ensures that the library is closed after the test.
~PublicLibraryManager() {
static_cast<void>(closeLibrary());
}
//@}
/// Public methods that call protected methods on the superclass.
using LibraryManager::openLibrary;
using LibraryManager::closeLibrary;
using LibraryManager::checkVersion;
using LibraryManager::registerStandardCallouts;
};
// Names of the libraries used in these tests. These libraries are built using
......@@ -152,17 +118,30 @@ namespace {
// Tests that OpenLibrary reports an error for an unknown library.
TEST_F(LibraryManagerTest, NonExistentLibrary) {
// Check that opening a non-existent library fails.
PublicLibraryManager lib_manager(std::string(NOT_PRESENT_LIBRARY),
0, getCalloutManager());
0, callout_manager_);
EXPECT_FALSE(lib_manager.openLibrary());
}
// Tests that OpenLibrary handles the case of no version present.
// Tests that the openLibrary() and closeLibrary() methods work.
TEST_F(LibraryManagerTest, OpenClose) {
PublicLibraryManager lib_manager(std::string(BASIC_CALLOUT_LIBRARY),