libagent_la_SOURCES += ctrl_agent_controller.cc ctrl_agent_controller.h
libagent_la_SOURCES += ctrl_agent_log.cc ctrl_agent_log.h
libagent_la_SOURCES += ctrl_agent_process.cc ctrl_agent_process.h
+libagent_la_SOURCES += simple_parser.cc simple_parser.h
libagent_la_SOURCES += agent_parser.cc agent_parser.h
libagent_la_SOURCES += parser_context.cc parser_context.h parser_context_decl.h
libagent_la_SOURCES += agent_lexer.ll
#include <config.h>
#include <agent/ctrl_agent_cfg_mgr.h>
+#include <agent/ctrl_agent_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) {
+
+}
+
CtrlAgentCfgMgr::CtrlAgentCfgMgr()
: DCfgMgrBase(DCfgContextBasePtr(new CtrlAgentCfgContext())) {
}
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->getHost() << ", port " << ctx->getPort()
+ << ", 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 weird
+ 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
return (DCfgContextBasePtr(new CtrlAgentCfgContext()));
}
+isc::data::ConstElementPtr
+CtrlAgentCfgMgr::parse(isc::data::ConstElementPtr config_set, bool check_only) {
+ 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);
+
+ 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);
+ }
+
+ 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");
+ LOG_INFO(agent_logger, CTRL_AGENT_CONFIG_CHECK_COMPLETE)
+ .arg(getConfigSummary(0));
+ } else {
+ answer = isc::config::createAnswer(0, "Configuration applied successfully.");
+ LOG_INFO(agent_logger, CTRL_AGENT_CONFIG_COMPLETE)
+ .arg(getConfigSummary(0));
+ }
+
+ return (answer);
+}
+
} // namespace isc::agent
} // namespace isc
#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 {
/// 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.
///
/// @return A pointer to the new clone.
return (process::DCfgContextBasePtr(new CtrlAgentCfgContext(*this)));
}
+ /// @brief Returns information about control socket
+ ///
+ /// @param type type of the server being controlled
+ /// @return pointer to the Element that holds control-socket map
+ const data::ConstElementPtr getControlSocketInfo(ServerType type) const {
+ if (type > MAX_TYPE_SUPPORTED) {
+ isc_throw(BadValue, "Invalid server type");
+ }
+ return (ctrl_sockets_[static_cast<uint8_t>(type)]);
+ }
+
+ /// @brief Sets information about the control socket
+ ///
+ /// @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) {
+ if (type > MAX_TYPE_SUPPORTED) {
+ isc_throw(BadValue, "Invalid server type");
+ }
+ ctrl_sockets_[static_cast<uint8_t>(type)] = control_socket;
+ }
+
+ /// @brief sets http-host parameter
+ ///
+ /// @param host hostname to be used during http socket creation
+ void setHost(const std::string& host) {
+ http_host_ = host;
+ }
+
+ /// @brief returns http-host parameter
+ ///
+ /// @return name of the http-host parameter
+ std::string getHost() const {
+ return (http_host_);
+ }
+
+ /// @brief Sets http port
+ ///
+ /// @param port sets the TCP port the http server will listen on
+ void setPort(const uint16_t port) {
+ http_port_ = port;
+ }
+
+ /// @brief Returns the TCP post the http server will listen on
+ uint16_t getPort() 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 assignment operator to avoid potential for slicing.
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.
protected:
- /// @brief Create a parser instance based on an element id.
- ///
- /// Given an element_id returns an instance of the appropriate parser.
- ///
- /// @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.
+ 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.
///
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_COMPLETE Control Agent configuration complete: %1
+This informational message indicates that the CA had completed its
+configuration.
+
+% 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_COMPLETE Control Agent configuration check complete: %1
+This informationnal message indicates that the CA had completed the
+configuration check. The outcome of this check is part of the message.
+
+% 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.
}
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);
}
/// 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.
///
--- /dev/null
+// 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-post", 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(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 (d2) {
+ cnt += SimpleParser::setDefaults(d6, SOCKET_DEFAULTS);
+ }
+ }
+
+ return (cnt);
+}
+
+void
+AgentSimpleParser::parse(CtrlAgentCfgContextPtr ctx, isc::data::ConstElementPtr config,
+ bool check_only) {
+
+ ctx->setHost(SimpleParser::getString(config, "http-host"));
+ ctx->setPort(SimpleParser::getIntType<uint16_t>(config, "http-port"));
+
+ ConstElementPtr ctrl_sockets = config->get("control-sockets");
+ if (!ctrl_sockets) {
+ isc_throw(ConfigError, "Missing mandatory parameter 'control-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);
+ }
+
+ hooks::HooksLibrariesParser hooks_parser;
+
+ ConstElementPtr hooks = config->get("hooks-libraries");
+ if (hooks) {
+ hooks_parser.parse(hooks);
+ hooks_parser.verifyLibraries();
+ }
+
+ 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();
+ }
+}
+
+};
+};
--- /dev/null
+// 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/ctrl_agent_cfg_mgr.h>
+
+namespace isc {
+namespace agent {
+
+/// @brief SimpleParser specialized for DHCPv4
+///
+/// This class is a @ref isc::data::SimpleParser dedicated to DHCPv4 parser.
+/// In particular, it contains all the default values and names of the
+/// parameters that are to be derived (inherited) between scopes.
+/// 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(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(CtrlAgentCfgContextPtr ctx, 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
}
isc::data::ConstElementPtr
-D2Process::configure(isc::data::ConstElementPtr config_set) {
+D2Process::configure(isc::data::ConstElementPtr config_set, bool check_only) {
LOG_DEBUG(d2_logger, DBGLVL_TRACE_BASIC,
DHCP_DDNS_CONFIGURE).arg(config_set->str());
+ /// @todo: Implement this eventually.
+ if (check_only) {
+ return (isc::config::createAnswer(0, "Configuration check is not supported by D2."));
+ }
+
int rcode = 0;
isc::data::ConstElementPtr comment;
isc::data::ConstElementPtr answer = getCfgMgr()->parseConfig(config_set);;
/// is retained and a failure response is returned as described 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);
+ virtual isc::data::ConstElementPtr
+ configure(isc::data::ConstElementPtr config_set, bool check_only);
/// @brief Processes the given command.
///
return res;
}
- isc::data::ConstElementPtr answer = configure(config_set_);
+ isc::data::ConstElementPtr answer = configure(config_set_, false);
isc::data::ConstElementPtr comment;
comment = isc::config::parseAnswer(rcode, answer);
ASSERT_TRUE(fromJSON(valid_d2_config));
// Invoke configure() with a valid D2 configuration.
- isc::data::ConstElementPtr answer = configure(config_set_);
+ isc::data::ConstElementPtr answer = configure(config_set_, false);
// Verify that configure result is success and reconfigure queue manager
// flag is true.
ASSERT_TRUE(fromJSON("{ \"bogus\": 1000 } "));
// Invoke configure() with the invalid configuration.
- answer = configure(config_set_);
+ answer = configure(config_set_, false);
// Verify that configure result is failure, the reconfigure flag is
// false, and that the queue manager is still running.
// Invoke configure() with a valid config that contains an unusable IP
ASSERT_TRUE(fromJSON(bad_ip_d2_config));
- isc::data::ConstElementPtr answer = configure(config_set_);
+ isc::data::ConstElementPtr answer = configure(config_set_, false);
// Verify that configure result is success and reconfigure queue manager
// flag is true.
// Verify we can recover given a valid config with an usable IP address.
ASSERT_TRUE(fromJSON(valid_d2_config));
- answer = configure(config_set_);
+ answer = configure(config_set_, false);
// Verify that configure result is success and reconfigure queue manager
// flag is true.
return (answer);
}
+isc::data::ConstElementPtr
+DCfgMgrBase::simpleParseConfig(isc::data::ConstElementPtr config_set,
+ bool check_only) {
+ LOG_DEBUG(dctl_logger, DBGLVL_COMMAND,
+ DCTL_CONFIG_START).arg(config_set->str());
+
+ if (!config_set) {
+ return (isc::config::createAnswer(1,
+ std::string("Can't parse NULL config")));
+ }
+
+ // The parsers implement data inheritance by directly accessing
+ // configuration context. For this reason the data parsers must store
+ // the parsed data into context immediately. This may cause data
+ // inconsistency if the parsing operation fails after the context has been
+ // modified. We need to preserve the original context here
+ // so as we can rollback changes when an error occurs.
+ DCfgContextBasePtr original_context = context_;
+ resetContext();
+
+ // Answer will hold the result returned to the caller.
+ ConstElementPtr answer;
+
+ try {
+ // Let's call the actual implementation
+ answer = parse(config_set, check_only);
+
+ // Everything was fine. Configuration set processed successfully.
+ if (!check_only) {
+ LOG_INFO(dctl_logger, DCTL_CONFIG_COMPLETE).arg(getConfigSummary(0));
+ answer = isc::config::createAnswer(0, "Configuration committed.");
+ } else {
+ LOG_INFO(dctl_logger, DCTL_CONFIG_CHECK_COMPLETE)
+ .arg(getConfigSummary(0))
+ .arg(config::answerToText(answer));
+ }
+
+ } catch (const std::exception& ex) {
+ LOG_ERROR(dctl_logger, DCTL_PARSER_FAIL).arg(ex.what());
+ answer = isc::config::createAnswer(1, ex.what());
+
+ // An error occurred, so make sure that we restore original context.
+ context_ = original_context;
+ return (answer);
+ }
+
+ if (check_only) {
+ // If this is a configuration check only, then don't actually apply
+ // the configuration and reverse to the previous one.
+ context_ = original_context;
+ }
+
+ return (answer);
+}
+
+
void
DCfgMgrBase::buildParams(isc::data::ConstElementPtr params_config) {
// Loop through scalars parsing them and committing them to storage.
parser->commit();
}
+isc::data::ConstElementPtr
+DCfgMgrBase::parse(isc::data::ConstElementPtr, bool) {
+ isc_throw(DCfgMgrBaseError, "This class does not implement simple parser paradigm yet");
+}
+
}; // end of isc::dhcp namespace
}; // end of isc namespace
-
/// class which is handed a set of configuration values to process by upper
/// application management layers.
///
+/// This class allows two configuration methods:
+///
+/// 1. classic method
+///
/// The class presents a public method for receiving new configurations,
/// parseConfig. This method coordinates the parsing effort as follows:
///
///
/// In the event that an error occurs, parsing is halted and the
/// configuration context is restored from backup.
+///
+/// See @ref isc::d2::D2CfgMgr and @ref isc::d2::D2Process for example use of
+/// this approach.
+///
+/// 2. simple configuration method
+///
+/// This approach assumes usage of @ref isc::data::SimpleParser paradigm. It
+/// does not use any intermediate storage, does not use parser pointers, does
+/// not enforce parsing order.
+///
+/// Here's the expected control flow order:
+/// 1. implementation calls simpleParseConfig from its configure method.
+/// 2. simpleParseConfig makes a configuration context
+/// 3. parse method from the derived class is called
+/// 4. if the configuration was unsuccessful of this is only a check, the
+/// old context is reinstantiated. If not, the configuration is kept.
+///
+/// See @ref isc::agent::CtrlAgentCfgMgr and @ref isc::agent::CtrlAgentProcess
+/// for example use of this approach.
class DCfgMgrBase {
public:
/// @brief Constructor
/// @brief Acts as the receiver of new configurations and coordinates
/// the parsing as described in the class brief.
///
- /// @param config_set is a set of configuration elements to parsed.
+ /// @param config_set is a set of configuration elements to be parsed.
///
/// @return an Element that contains the results of configuration composed
/// of an integer status value (0 means successful, non-zero means failure),
isc::data::ConstElementPtr parseConfig(isc::data::ConstElementPtr
config_set);
+
+ /// @brief Acts as the receiver of new configurations.
+ ///
+ /// This method is similar to what @ref parseConfig does, execept it employs
+ /// the simple parser paradigm: no intermediate storage, no parser pointers
+ /// no distinction between params_map and objects_map, parse order (if needed)
+ /// can be enforced in the actual implementation by calling specific
+ /// parsers first. See @ref isc::agent::CtrlAgentCfgMgr::parse for example.
+ ///
+ /// If check_only is true, the actual parsing is done to check if the configuration
+ /// is sane, but is then reverted.
+ ///
+ /// @param config set of configuration elements to be parsed
+ /// @param check_only true if the config is to be checked only, but 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.
+ isc::data::ConstElementPtr
+ simpleParseConfig(isc::data::ConstElementPtr config,
+ bool check_only = false);
+
/// @brief Adds a given element id to the end of the parse order list.
///
/// The order in which object elements are retrieved from this is the
/// @throw DCfgMgrBaseError if context is NULL.
void setContext(DCfgContextBasePtr& context);
+ /// @brief Parses actual configuration.
+ ///
+ /// This method is expected to be implemented in derived classes that employ
+ /// SimpleParser paradigm (i.e. they call simpleParseConfig rather than
+ /// parseConfig from their configure method).
+ ///
+ /// Implementations that do not employ this method may provide dummy
+ /// implementation.
+ ///
+ /// @param config the Element tree structure that decribes the configuration.
+ /// @param check_only false for normal configuration, true when verifying only
+ ///
+ /// @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 parse(isc::data::ConstElementPtr config,
+ bool check_only);
+
private:
/// @brief Parse a configuration element.
// Instance method for handling new config
isc::data::ConstElementPtr
DControllerBase::updateConfig(isc::data::ConstElementPtr new_config) {
- return (process_->configure(new_config));
+ return (process_->configure(new_config, false));
}
/// 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) = 0;
+ virtual isc::data::ConstElementPtr
+ configure(isc::data::ConstElementPtr config_set, bool check_only) = 0;
/// @brief Processes the given command.
///
A debug message listing the command (and possible arguments) received
from the Kea control system by the controller.
+% DCTL_CONFIG_CHECK_COMPLETE server has completed configuration check: %1, result: %2
+This is an informational message announcing the successful processing of a
+new configuration check is complete. The result of that check is printed.
+This informational message is printed when configuration check is requested.
+
% DCTL_CONFIG_COMPLETE server has completed configuration: %1
This is an informational message announcing the successful processing of a
new configuration. It is output during server startup, and when an updated
}
isc::data::ConstElementPtr
-DStubProcess::configure(isc::data::ConstElementPtr config_set) {
+DStubProcess::configure(isc::data::ConstElementPtr config_set, bool check_only) {
+ if (check_only) {
+ return (isc::config::createAnswer(1,
+ "Configuration checking is not supported."));
+ }
+
if (SimFailure::shouldFailOn(SimFailure::ftProcessConfigure)) {
// Simulates a process configure failure.
return (isc::config::createAnswer(1,
/// of the inbound configuration.
///
/// @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);
+ virtual isc::data::ConstElementPtr
+ configure(isc::data::ConstElementPtr config_set, bool check_only);
/// @brief Executes the given command.
///