Commit 828304f2 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰

[master] Merge branch 'trac5134_rebase'

# Conflicts:
#	src/bin/agent/Makefile.am
#	src/bin/agent/ca_cfg_mgr.cc
#	src/bin/agent/tests/.gitignore
#	src/bin/agent/tests/Makefile.am
#	src/bin/agent/tests/ca_cfg_mgr_unittests.cc
#	src/lib/process/tests/d_cfg_mgr_unittests.cc
parents d8c12b9f 5ed26cc0
......@@ -1638,6 +1638,7 @@ AC_CONFIG_FILES([compatcheck/Makefile
src/bin/admin/tests/mysql_tests.sh
src/bin/admin/tests/pgsql_tests.sh
src/bin/admin/tests/cql_tests.sh
src/bin/agent/tests/test_libraries.h
src/hooks/Makefile
src/hooks/dhcp/Makefile
src/hooks/dhcp/user_chk/Makefile
......
......@@ -51,6 +51,7 @@ libagent_la_SOURCES += ca_log.cc ca_log.h
libagent_la_SOURCES += ca_process.cc ca_process.h
libagent_la_SOURCES += ca_response_creator.cc ca_response_creator.h
libagent_la_SOURCES += ca_response_creator_factory.h
libagent_la_SOURCES += simple_parser.cc simple_parser.h
libagent_la_SOURCES += parser_context.cc parser_context.h parser_context_decl.h
libagent_la_SOURCES += agent_lexer.ll location.hh position.hh stack.hh
......
......@@ -6,13 +6,35 @@
#include <config.h>
#include <agent/ca_cfg_mgr.h>
#include <agent/ca_log.h>
#include <agent/simple_parser.h>
#include <cc/simple_parser.h>
#include <cc/command_interpreter.h>
using namespace isc::dhcp;
using namespace isc::process;
using namespace isc::data;
namespace isc {
namespace agent {
CtrlAgentCfgContext::CtrlAgentCfgContext()
:http_host_(""), http_port_(0) {
}
CtrlAgentCfgContext::CtrlAgentCfgContext(const CtrlAgentCfgContext& orig)
: DCfgContextBase(),http_host_(orig.http_host_), http_port_(orig.http_port_),
libraries_(orig.libraries_) {
// We're copying pointers here only. The underlying data will be shared by
// old and new context. That's how shared pointers work and I see no reason
// why it would be different in this particular here.
ctrl_sockets_[TYPE_D2] = orig.ctrl_sockets_[TYPE_D2];
ctrl_sockets_[TYPE_DHCP4] = orig.ctrl_sockets_[TYPE_DHCP4];
ctrl_sockets_[TYPE_DHCP6] = orig.ctrl_sockets_[TYPE_DHCP6];
}
CtrlAgentCfgMgr::CtrlAgentCfgMgr()
: DCfgMgrBase(DCfgContextBasePtr(new CtrlAgentCfgContext())) {
}
......@@ -22,16 +44,49 @@ CtrlAgentCfgMgr::~CtrlAgentCfgMgr() {
std::string
CtrlAgentCfgMgr::getConfigSummary(const uint32_t /*selection*/) {
return ("Control Agent is currently not configurable.");
CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
// First print the http stuff.
std::ostringstream s;
s << "listening on " << ctx->getHttpHost() << ", port "
<< ctx->getHttpPort() << ", control sockets: ";
// Then print the control-sockets
bool socks = false;
if (ctx->getControlSocketInfo(CtrlAgentCfgContext::TYPE_D2)) {
s << "d2 ";
socks = true;
}
if (ctx->getControlSocketInfo(CtrlAgentCfgContext::TYPE_DHCP4)) {
s << "dhcp4 ";
socks = true;
}
if (ctx->getControlSocketInfo(CtrlAgentCfgContext::TYPE_DHCP6)) {
s << "dhcp6 ";
socks = true;
}
if (!socks) {
// That's uncommon, but correct scenario. CA can respond to some
// commands on its own. Further down the road we will possibly get the
// capability to tell CA to start other servers.
s << "none";
}
// Finally, print the hook libraries names
const hooks::HookLibsCollection libs = ctx->getLibraries();
s << ", " << libs.size() << " lib(s):";
for (auto lib = libs.begin(); lib != libs.end(); ++lib) {
s << lib->first << " ";
}
return (s.str());
}
isc::dhcp::ParserPtr
CtrlAgentCfgMgr::createConfigParser(const std::string& element_id,
CtrlAgentCfgMgr::createConfigParser(const std::string& /*element_id*/,
const isc::data::Element::Position& /*pos*/) {
// Create dummy parser, so as we don't return null pointer.
isc::dhcp::ParserPtr parser;
parser.reset(new Uint32Parser(element_id, getContext()->getUint32Storage()));
return (parser);
isc_throw(NotImplemented, "We don't use parser pointers anymore");
}
DCfgContextBasePtr
......@@ -39,5 +94,70 @@ CtrlAgentCfgMgr::createNewContext() {
return (DCfgContextBasePtr(new CtrlAgentCfgContext()));
}
isc::data::ConstElementPtr
CtrlAgentCfgMgr::parse(isc::data::ConstElementPtr config_set, bool check_only) {
// Do a sanity check first.
if (!config_set) {
isc_throw(DhcpConfigError, "Mandatory config parameter not provided");
}
CtrlAgentCfgContextPtr ctx = getCtrlAgentCfgContext();
// Set the defaults
ElementPtr cfg = boost::const_pointer_cast<Element>(config_set);
AgentSimpleParser::setAllDefaults(cfg);
// And parse the configuration.
ConstElementPtr answer;
std::string excuse;
try {
// Do the actual parsing
AgentSimpleParser parser;
parser.parse(ctx, cfg, check_only);
} catch (const isc::Exception& ex) {
excuse = ex.what();
answer = isc::config::createAnswer(2, excuse);
} catch (...) {
excuse = "undefined configuration parsing error";
answer = isc::config::createAnswer(2, excuse);
}
// At this stage the answer was created only in case of exception.
if (answer) {
if (check_only) {
LOG_ERROR(agent_logger, CTRL_AGENT_CONFIG_CHECK_FAIL).arg(excuse);
} else {
LOG_ERROR(agent_logger, CTRL_AGENT_CONFIG_FAIL).arg(excuse);
}
return (answer);
}
if (check_only) {
answer = isc::config::createAnswer(0, "Configuration check successful");
} else {
answer = isc::config::createAnswer(0, "Configuration applied successfully.");
}
return (answer);
}
const data::ConstElementPtr
CtrlAgentCfgContext::getControlSocketInfo(ServerType type) const {
if (type > MAX_TYPE_SUPPORTED) {
isc_throw(BadValue, "Invalid server type");
}
return (ctrl_sockets_[static_cast<uint8_t>(type)]);
}
void
CtrlAgentCfgContext::setControlSocketInfo(const isc::data::ConstElementPtr& control_socket,
ServerType type) {
if (type > MAX_TYPE_SUPPORTED) {
isc_throw(BadValue, "Invalid server type");
}
ctrl_sockets_[static_cast<uint8_t>(type)] = control_socket;
}
} // namespace isc::agent
} // namespace isc
// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2016-2017 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
......@@ -7,8 +7,10 @@
#ifndef CTRL_AGENT_CFG_MGR_H
#define CTRL_AGENT_CFG_MGR_H
#include <cc/data.h>
#include <process/d_cfg_mgr.h>
#include <boost/pointer_cast.hpp>
#include <hooks/libinfo.h>
namespace isc {
namespace agent {
......@@ -26,16 +28,120 @@ typedef boost::shared_ptr<CtrlAgentCfgContext> CtrlAgentCfgContextPtr;
/// It is derived from the context base class, DCfgContextBase.
class CtrlAgentCfgContext : public process::DCfgContextBase {
public:
/// @brief Default constructor
CtrlAgentCfgContext();
/// @brief Specifies type of the server being controlled.
enum ServerType {
TYPE_DHCP4 = 0, ///< kea-dhcp4
TYPE_DHCP6 = 1, ///< kea-dhcp6
TYPE_D2 = 2 ///< kea-dhcp-ddns
};
/// @brief Used check that specified ServerType is within valid range.
static const uint32_t MAX_TYPE_SUPPORTED = TYPE_D2;
/// @brief Creates a clone of this context object.
///
/// Note this method does not do deep copy the information about control sockets.
/// That data is stored as ConstElementPtr (a shared pointer) to the actual data.
///
/// @return A pointer to the new clone.
virtual process::DCfgContextBasePtr clone() {
return (process::DCfgContextBasePtr(new CtrlAgentCfgContext(*this)));
}
/// @brief Returns information about control socket
///
/// This method returns Element tree structure that describes the control
/// socket (or null pointer if the socket is not defined for a particular
/// server type). This information is expected to be compatible with
/// data passed to @ref isc::config::CommandMgr::openCommandSocket.
///
/// @param type type of the server being controlled
/// @return pointer to the Element that holds control-socket map (or NULL)
const data::ConstElementPtr getControlSocketInfo(ServerType type) const;
/// @brief Sets information about the control socket
///
/// This method stores Element tree structure that describes the control
/// socket. This information is expected to be compatible with
/// data passed to @ref isc::config::CommandMgr::openCommandSocket.
///
/// @param control_socket Element that holds control-socket map
/// @param type type of the server being controlled
void setControlSocketInfo(const isc::data::ConstElementPtr& control_socket,
ServerType type);
/// @brief Sets http-host parameter
///
/// @param host Hostname or IP address where the agent's HTTP service
/// will be available.
void setHttpHost(const std::string& host) {
http_host_ = host;
}
/// @brief Returns http-host parameter
///
/// @return Hostname or IP address where the agent's HTTP service is
/// available.
std::string getHttpHost() const {
return (http_host_);
}
/// @brief Sets http port
///
/// @param port sets the TCP port the HTTP server will listen on
void setHttpPort(const uint16_t port) {
http_port_ = port;
}
/// @brief Returns the TCP post the HTTP server will listen on
uint16_t getHttpPort() const {
return (http_port_);
}
/// @brief Returns a list of hook libraries
/// @return a list of hook libraries
const hooks::HookLibsCollection& getLibraries() const {
return (libraries_);
}
/// @brief Sets the list of hook libraries
///
/// @params libs a coolection of libraries to remember.
void setLibraries(const hooks::HookLibsCollection& libs) {
libraries_ = libs;
}
private:
/// @brief Private copy constructor
///
/// It is private to forbid anyone outside of this class to make copies.
/// The only legal way to copy a context is to call @ref clone().
///
/// @param orig the original context to copy from
CtrlAgentCfgContext(const CtrlAgentCfgContext& orig);
/// @brief Private assignment operator to avoid potential for slicing.
///
/// @param rhs Context to be assigned.
CtrlAgentCfgContext& operator=(const CtrlAgentCfgContext& rhs);
/// Socket information will be stored here (for all supported servers)
data::ConstElementPtr ctrl_sockets_[MAX_TYPE_SUPPORTED + 1];
/// Hostname the CA should listen on.
std::string http_host_;
/// TCP port the CA should listen on.
uint16_t http_port_;
/// List of hook libraries.
hooks::HookLibsCollection libraries_;
};
/// @brief Ctrl Agent Configuration Manager.
......@@ -69,20 +175,22 @@ public:
protected:
/// @brief Create a parser instance based on an element id.
///
/// Given an element_id returns an instance of the appropriate parser.
/// @brief Parses configuration of the Control Agent.
///
/// @param element_id is the string name of the element as it will appear
/// in the configuration set.
/// @param pos position within the configuration text (or file) of element
/// to be parsed. This is passed for error messaging.
/// @param config Pointer to a configuration specified for the agent.
/// @param check_only Boolean flag indicating if this method should
/// only verify correctness of the provided conifiguration.
/// @return Pointer to a result of configuration parsing.
virtual isc::data::ConstElementPtr
parse(isc::data::ConstElementPtr config, bool check_only);
/// @brief This is no longer used.
///
/// @return returns a ParserPtr to the parser instance.
/// @throw NotImplemented
/// @return nothing, always throws
virtual isc::dhcp::ParserPtr
createConfigParser(const std::string& element_id,
const isc::data::Element::Position& pos
= isc::data::Element::ZERO_POSITION());
createConfigParser(const std::string&,
const isc::data::Element::Position& pos);
/// @brief Creates a new, blank CtrlAgentCfgContext context.
///
......
......@@ -23,3 +23,13 @@ event loop.
This informational message indicates that the DHCP-DDNS server has
processed all configuration information and is ready to begin processing.
The version is also printed.
% CTRL_AGENT_CONFIG_FAIL Control Agent configuration failed: %1
This error message indicates that the CA had failed configuration
attempt. Details are provided. Additional details may be available
in earlier log entries, possibly on lower levels.
% CTRL_AGENT_CONFIG_CHECK_FAIL Control Agent configuration check failed: %1
This error message indicates that the CA had failed configuration
check. Details are provided. Additional details may be available
in earlier log entries, possibly on lower levels.
......@@ -93,9 +93,11 @@ CtrlAgentProcess::shutdown(isc::data::ConstElementPtr /*args*/) {
}
isc::data::ConstElementPtr
CtrlAgentProcess::configure(isc::data::ConstElementPtr config_set) {
CtrlAgentProcess::configure(isc::data::ConstElementPtr config_set,
bool check_only) {
int rcode = 0;
isc::data::ConstElementPtr answer = getCfgMgr()->parseConfig(config_set);
isc::data::ConstElementPtr answer = getCfgMgr()->simpleParseConfig(config_set,
check_only);
config::parseAnswer(rcode, answer);
return (answer);
}
......
......@@ -79,11 +79,12 @@ public:
/// below.
///
/// @param config_set a new configuration (JSON) for the process
/// @param check_only true if configuration is to be verified only, not applied
/// @return an Element that contains the results of configuration composed
/// of an integer status value (0 means successful, non-zero means failure),
/// and a string explanation of the outcome.
virtual isc::data::ConstElementPtr
configure(isc::data::ConstElementPtr config_set);
configure(isc::data::ConstElementPtr config_set, bool check_only);
/// @brief Processes the given command.
///
......
// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <agent/simple_parser.h>
#include <cc/data.h>
#include <cc/dhcp_config_error.h>
#include <hooks/hooks_parser.h>
#include <boost/foreach.hpp>
using namespace isc::data;
namespace isc {
namespace agent {
/// @brief This sets of arrays define the default values in various scopes
/// of the Control Agent Configuration.
///
/// Each of those is documented in @file agent/simple_parser.cc. This
/// is different than most other comments in Kea code. The reason
/// for placing those in .cc rather than .h file is that it
/// is expected to be one centralized place to look at for
/// the default values. This is expected to be looked at also by
/// people who are not skilled in C or C++, so they may be
/// confused with the differences between declaration and definition.
/// As such, there's one file to look at that hopefully is readable
/// without any C or C++ skills.
///
/// @{
/// @brief This table defines default values for global options.
///
/// These are global Control Agent parameters.
const SimpleDefaults AgentSimpleParser::AGENT_DEFAULTS = {
{ "http-host", Element::string, "localhost"},
{ "http-port", Element::integer, "8000"}
};
/// @brief This table defines default values for control sockets.
///
const SimpleDefaults AgentSimpleParser::SOCKET_DEFAULTS = {
{ "socket-type", Element::string, "unix"}
};
/// @}
/// ---------------------------------------------------------------------------
/// --- end of default values -------------------------------------------------
/// ---------------------------------------------------------------------------
size_t AgentSimpleParser::setAllDefaults(const isc::data::ElementPtr& global) {
size_t cnt = 0;
// Set global defaults first.
cnt = setDefaults(global, AGENT_DEFAULTS);
// Now set the defaults for control-sockets, if any.
ConstElementPtr sockets = global->get("control-sockets");
if (sockets) {
ElementPtr d2 = boost::const_pointer_cast<Element>(sockets->get("d2-server"));
if (d2) {
cnt += SimpleParser::setDefaults(d2, SOCKET_DEFAULTS);
}
ElementPtr d4 = boost::const_pointer_cast<Element>(sockets->get("dhcp4-server"));
if (d4) {
cnt += SimpleParser::setDefaults(d4, SOCKET_DEFAULTS);
}
ElementPtr d6 = boost::const_pointer_cast<Element>(sockets->get("dhcp6-server"));
if (d6) {
cnt += SimpleParser::setDefaults(d6, SOCKET_DEFAULTS);
}
}
return (cnt);
}
void
AgentSimpleParser::parse(const CtrlAgentCfgContextPtr& ctx,
const isc::data::ConstElementPtr& config,
bool check_only) {
// Let's get the HTTP parameters first.
ctx->setHttpHost(SimpleParser::getString(config, "http-host"));
ctx->setHttpPort(SimpleParser::getIntType<uint16_t>(config, "http-port"));
// Control sockets are second.
ConstElementPtr ctrl_sockets = config->get("control-sockets");
if (ctrl_sockets) {
ConstElementPtr d2_socket = ctrl_sockets->get("d2-server");
ConstElementPtr d4_socket = ctrl_sockets->get("dhcp4-server");
ConstElementPtr d6_socket = ctrl_sockets->get("dhcp6-server");
if (d2_socket) {
ctx->setControlSocketInfo(d2_socket, CtrlAgentCfgContext::TYPE_D2);
}
if (d4_socket) {
ctx->setControlSocketInfo(d4_socket, CtrlAgentCfgContext::TYPE_DHCP4);
}
if (d6_socket) {
ctx->setControlSocketInfo(d6_socket, CtrlAgentCfgContext::TYPE_DHCP6);
}
}
// Finally, let's get the hook libs!
hooks::HooksLibrariesParser hooks_parser;
ConstElementPtr hooks = config->get("hooks-libraries");
if (hooks) {
hooks_parser.parse(hooks);
hooks_parser.verifyLibraries();
hooks::HookLibsCollection libs;
hooks_parser.getLibraries(libs);
ctx->setLibraries(libs);
}
if (!check_only) {
// This occurs last as if it succeeds, there is no easy way
// revert it. As a result, the failure to commit a subsequent
// change causes problems when trying to roll back.
hooks_parser.loadLibraries();
}
}
};
};
// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef AGENT_SIMPLE_PARSER_H
#define AGENT_SIMPLE_PARSER_H
#include <cc/simple_parser.h>
#include <agent/ca_cfg_mgr.h>
namespace isc {
namespace agent {
/// @brief SimpleParser specialized for Control Agent
///
/// This class is a @ref isc::data::SimpleParser dedicated to Control Agent.
/// In particular, it contains all the default values for the whole
/// agent and for the socket defaults.
///
/// For the actual values, see @file agent/simple_parser.cc
class AgentSimpleParser : public isc::data::SimpleParser {
public:
/// @brief Sets all defaults for Control Agent configuration
///
/// This method sets global, option data and option definitions defaults.
///
/// @param global scope to be filled in with defaults.
/// @return number of default values added
static size_t setAllDefaults(const isc::data::ElementPtr& global);
/// @brief Parses the control agent configuration
///
/// @param ctx - parsed information will be stored here
/// @param config - Element tree structure that holds configuration
/// @param check_only - if true the configuration is verified only, not applied
///
/// @throw ConfigError if any issues are encountered.
void parse(const CtrlAgentCfgContextPtr& ctx,
const isc::data::ConstElementPtr& config,
bool check_only);
// see simple_parser.cc for comments for those parameters
static const isc::data::SimpleDefaults AGENT_DEFAULTS;
static const isc::data::SimpleDefaults SOCKET_DEFAULTS;
};
};
};
#endif
/ca_unittests
/ca_process_tests.sh
/test_libraries.h
......@@ -4,8 +4,8 @@ SHTESTS =
SHTESTS += ca_process_tests.sh
noinst_SCRIPTS = ca_process_tests.sh
EXTRA_DIST = ca_process_tests.sh.in
noinst_LTLIBRARIES = libbasic.la
# test using command-line arguments, so use check-local target instead of TESTS
check-local:
......@@ -78,6 +78,17 @@ ca_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
ca_unittests_LDADD += $(LOG4CPLUS_LIBS) $(CRYPTO_LIBS)
ca_unittests_LDADD += $(BOOST_LIBS) $(GTEST_LDADD)
# The basic callout library - contains standard callouts
libbasic_la_SOURCES = basic_library.cc
libbasic_la_CXXFLAGS = $(AM_CXXFLAGS)
libbasic_la_CPPFLAGS = $(AM_CPPFLAGS)
libbasic_la_LIBADD = $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
libbasic_la_LIBADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la
libbasic_la_LIBADD += $(top_builddir)/src/lib/log/libkea-log.la
libbasic_la_LDFLAGS = -avoid-version -export-dynamic -module -rpath /nowhere
nodist_run_unittests_SOURCES = test_libraries.h
endif
noinst_PROGRAMS = $(TESTS)
// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
/// @file
/// @brief Basic callout library
///
/// This is source of a test library for Control Agent.
///
/// - Only the "version" framework function is supplied.
///
/// - hookpt_one callout is supplied.
#include <config.h>
#include <hooks/hooks.h>
using namespace isc::hooks;
using namespace std;
namespace {
extern "C" {
// Callouts. All return their result through the "result" argument.
int
context_create(CalloutHandle& handle) {
handle.setContext("result", static_cast<int>(10));