14#include <boost/make_shared.hpp>
71 auto config_storage = boost::make_shared<HAConfigMapper>();
75 parseAll(config_storage,
config);
76 validateRelationships(config_storage);
77 logConfigStatus(config_storage);
78 return (config_storage);
83 }
catch (
const std::exception& ex) {
103 auto const& config_vec =
config->listValue();
104 if (config_vec.empty()) {
107 for (
auto const& cfg : config_vec) {
108 parseOne(config_storage, cfg);
117 isc_throw(ConfigError,
"HA configuration must not be null");
122 isc_throw(ConfigError,
"HA configuration for a relationship must be a map");
129 rel_config->setHAMode(
getString(config,
"mode"));
139 if (!config->contains(
"peers")) {
140 isc_throw(ConfigError,
"'peers' parameter missing in HA configuration");
146 isc_throw(ConfigError,
"'peers' parameter must be a list");
154 isc_throw(ConfigError,
"'state-machine' parameter must be a map");
157 states_list = state_machine->get(
"states");
158 if (states_list && (states_list->getType() !=
Element::list)) {
159 isc_throw(ConfigError,
"'states' parameter must be a list");
166 rel_config->setThisServerName(
getString(config,
"this-server-name"));
169 rel_config->setSendLeaseUpdates(
getBoolean(config,
"send-lease-updates"));
172 rel_config->setSyncLeases(
getBoolean(config,
"sync-leases"));
175 uint32_t sync_timeout = getAndValidateInteger<uint32_t>(config,
"sync-timeout");
176 rel_config->setSyncTimeout(sync_timeout);
179 uint32_t sync_page_limit = getAndValidateInteger<uint32_t>(config,
"sync-page-limit");
180 rel_config->setSyncPageLimit(sync_page_limit);
183 uint32_t delayed_updates_limit = getAndValidateInteger<uint32_t>(config,
"delayed-updates-limit");
184 rel_config->setDelayedUpdatesLimit(delayed_updates_limit);
189 int64_t heartbeat_delay_max = std::numeric_limits<uint32_t>::max();
190 if (heartbeat_delay_max > std::numeric_limits<long>::max()) {
191 heartbeat_delay_max = std::numeric_limits<long>::max();
193 int64_t heartbeat_delay64 =
getInteger(config,
"heartbeat-delay");
194 if (heartbeat_delay64 < 0) {
195 isc_throw(ConfigError,
"'heartbeat-delay' must not be negative");
197 if (heartbeat_delay64 > heartbeat_delay_max) {
198 isc_throw(ConfigError,
"'heartbeat-delay' must not be greater than "
199 << heartbeat_delay_max);
201 uint32_t heartbeat_delay =
static_cast<uint32_t
>(heartbeat_delay64);
202 rel_config->setHeartbeatDelay(heartbeat_delay);
205 uint32_t max_response_delay = getAndValidateInteger<uint32_t>(config,
"max-response-delay");
206 rel_config->setMaxResponseDelay(max_response_delay);
209 uint32_t max_ack_delay = getAndValidateInteger<uint32_t>(config,
"max-ack-delay");
210 rel_config->setMaxAckDelay(max_ack_delay);
213 uint32_t max_unacked_clients = getAndValidateInteger<uint32_t>(config,
"max-unacked-clients");
214 rel_config->setMaxUnackedClients(max_unacked_clients);
217 uint32_t max_rejected_lease_updates = getAndValidateInteger<uint32_t>(config,
"max-rejected-lease-updates");
218 rel_config->setMaxRejectedLeaseUpdates(max_rejected_lease_updates);
221 rel_config->setWaitBackupAck(
getBoolean(config,
"wait-backup-ack"));
224 ElementPtr mt_config = boost::const_pointer_cast<Element>(config->get(
"multi-threading"));
228 config->set(
"multi-threading", mt_config);
230 isc_throw(ConfigError,
"multi-threading configuration must be a map");
237 rel_config->setEnableMultiThreading(
getBoolean(mt_config,
"enable-multi-threading"));
240 rel_config->setHttpDedicatedListener(
getBoolean(mt_config,
"http-dedicated-listener"));
243 uint32_t threads = getAndValidateInteger<uint32_t>(mt_config,
"http-listener-threads");
244 rel_config->setHttpListenerThreads(threads);
247 threads = getAndValidateInteger<uint32_t>(mt_config,
"http-client-threads");
248 rel_config->setHttpClientThreads(threads);
253 rel_config->setTrustAnchor(
getString(config,
"trust-anchor"));
259 rel_config->setCertFile(
getString(config,
"cert-file"));
265 rel_config->setKeyFile(
getString(config,
"key-file"));
269 rel_config->setRequireClientCerts(
getBoolean(config,
"require-client-certs"));
272 rel_config->setRestrictCommands(
getBoolean(config,
"restrict-commands"));
275 auto const& peers_vec = peers->listValue();
278 for (
auto const& p : peers_vec) {
282 isc_throw(ConfigError,
"peer configuration must be a map");
288 auto cfg = rel_config->selectNextPeerConfig(
getString(p,
"name"));
294 if (p->contains(
"trust-anchor")) {
295 cfg->setTrustAnchor(
getString(p, (
"trust-anchor")));
299 if (p->contains(
"cert-file")) {
300 cfg->setCertFile(
getString(p, (
"cert-file")));
304 if (p->contains(
"key-file")) {
305 cfg->setKeyFile(
getString(p, (
"key-file")));
312 cfg->setAutoFailover(
getBoolean(p,
"auto-failover"));
315 std::string password;
316 if (p->contains(
"basic-auth-password")) {
317 if (p->contains(
"basic-auth-password-file")) {
318 isc_throw(dhcp::DhcpConfigError,
"only one of "
319 <<
"basic-auth-password and "
320 <<
"basic-auth-password-file parameter can be "
321 <<
"configured in peer '"
322 << cfg->getName() <<
"'");
324 password =
getString(p,
"basic-auth-password");
326 std::string password_file;
327 if (p->contains(
"basic-auth-password-file")) {
328 password_file =
getString(p,
"basic-auth-password-file");
331 }
catch (
const std::exception& ex) {
332 isc_throw(dhcp::DhcpConfigError,
"bad password file in peer '"
333 << cfg->getName() <<
"': " << ex.what());
339 bool do_auth =
false;
340 if (p->contains(
"basic-auth-user")) {
341 if (p->contains(
"basic-auth-user-file")) {
342 isc_throw(dhcp::DhcpConfigError,
"only one of "
343 <<
"basic-auth-user and "
344 <<
"basic-auth-user-file parameter can be "
345 <<
"configured in peer '"
346 << cfg->getName() <<
"'");
351 std::string user_file;
352 if (p->contains(
"basic-auth-user-file")) {
353 user_file =
getString(p,
"basic-auth-user-file");
357 }
catch (
const std::exception& ex) {
358 isc_throw(dhcp::DhcpConfigError,
"bad user file in peer '"
359 << cfg->getName() <<
"': " << ex.what());
368 auth.reset(
new BasicHttpAuth(user, password));
369 auth_config.reset(
new BasicHttpAuthConfig);
370 auth_config->add(user, user_file, password, password_file);
372 }
catch (
const std::exception& ex) {
373 isc_throw(dhcp::DhcpConfigError, ex.what() <<
" in peer '"
374 << cfg->getName() <<
"'");
381 auto const& states_vec = states_list->listValue();
383 std::set<int> configured_states;
386 for (
auto const& s : states_vec) {
390 isc_throw(ConfigError,
"state configuration must be a map");
396 std::string state_name =
getString(s,
"state");
400 if (configured_states.count(state) > 0) {
401 isc_throw(ConfigError,
"duplicated configuration for the '"
402 << state_name <<
"' state");
404 configured_states.insert(state);
406 rel_config->getStateMachineConfig()->
407 getStateConfig(state)->setPausing(
getString(s,
"pause"));
414 rel_config->validate();
416 auto peer_configs = rel_config->getAllServersConfig();
417 for (
auto const& peer_config : peer_configs) {
419 config_storage->map(peer_config.first, rel_config);
421 }
catch (
const std::exception& ex) {
422 isc_throw(HAConfigValidationError,
"server names must be unique for different relationships: "
430 const std::string& parameter_name) {
431 int64_t value =
getInteger(config, parameter_name);
433 isc_throw(ConfigError,
"'" << parameter_name <<
"' must not be negative");
435 }
else if (value > std::numeric_limits<T>::max()) {
436 isc_throw(ConfigError,
"'" << parameter_name <<
"' must not be greater than "
437 << +std::numeric_limits<T>::max());
440 return (
static_cast<T
>(value));
447 for (
auto const& config : config_storage->getAll()) {
451 if (!config->amSendingLeaseUpdates()) {
453 .arg(config->getThisServerName());
457 if (!config->amSyncingLeases()) {
459 .arg(config->getThisServerName());
463 if (config->amSendingLeaseUpdates() !=
464 config->amSyncingLeases()) {
466 .arg(config->getThisServerName())
467 .arg(config->amSendingLeaseUpdates() ?
"true" :
"false")
468 .arg(config->amSyncingLeases() ?
"true" :
"false");
478 if (!config->getThisServerConfig()->isAutoFailover()) {
480 .arg(config->getThisServerName());
487 auto configs = config_storage->getAll();
488 if (configs.size() <= 1) {
491 std::unordered_set<std::string> server_names;
492 for (
auto const& config : configs) {
495 isc_throw(HAConfigValidationError,
"multiple HA relationships are only supported for 'hot-standby' mode");
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
An exception that is thrown if an error occurs while configuring any server.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
static std::string getString(isc::data::ConstElementPtr scope, const std::string &name)
Returns a string parameter from a scope.
static bool getBoolean(isc::data::ConstElementPtr scope, const std::string &name)
Returns a boolean parameter from a scope.
static int64_t getInteger(isc::data::ConstElementPtr scope, const std::string &name)
Returns an integer parameter from a scope.
static size_t setDefaults(isc::data::ElementPtr scope, const SimpleDefaults &default_values)
Sets the default values.
static HAConfigMapperPtr parse(const data::ConstElementPtr &config)
Parses HA configuration.
static HAConfigPtr create()
Instantiates a HAConfig.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
boost::shared_ptr< const Element > ConstElementPtr
std::vector< SimpleDefault > SimpleDefaults
This specifies all default values in a given scope (e.g. a subnet).
boost::shared_ptr< Element > ElementPtr
boost::shared_ptr< HAConfigMapper > HAConfigMapperPtr
Pointer to an object mapping HAConfig to relationships.
isc::log::Logger ha_logger("ha-hooks")
const isc::log::MessageID HA_CONFIGURATION_SUCCESSFUL
const isc::log::MessageID HA_CONFIG_AUTO_FAILOVER_DISABLED
const isc::log::MessageID HA_CONFIG_LEASE_UPDATES_AND_SYNCING_DIFFER
const isc::log::MessageID HA_CONFIG_LEASE_UPDATES_DISABLED
const isc::log::MessageID HA_CONFIG_LEASE_SYNCING_DISABLED
int stringToState(const std::string &state_name)
Returns state for a given name.
boost::shared_ptr< BasicHttpAuth > BasicHttpAuthPtr
Type of pointers to basic HTTP authentication objects.
boost::shared_ptr< BasicHttpAuthConfig > BasicHttpAuthConfigPtr
Type of shared pointers to basic HTTP authentication configuration.
string getContent(string const &file_name)
Get the content of a regular file.
Defines the logger used by the top-level component of kea-lfc.