25 #include <boost/pointer_cast.hpp>
26 #include <boost/make_shared.hpp>
27 #include <boost/weak_ptr.hpp>
39 namespace ph = std::placeholders;
44 const int HAService::HA_HEARTBEAT_COMPLETE_EVT;
45 const int HAService::HA_LEASE_UPDATES_COMPLETE_EVT;
46 const int HAService::HA_SYNCING_FAILED_EVT;
47 const int HAService::HA_SYNCING_SUCCEEDED_EVT;
48 const int HAService::HA_MAINTENANCE_NOTIFY_EVT;
49 const int HAService::HA_MAINTENANCE_START_EVT;
50 const int HAService::HA_MAINTENANCE_CANCEL_EVT;
51 const int HAService::HA_CONTROL_RESULT_MAINTENANCE_NOT_ALLOWED;
55 : io_service_(io_service), network_state_(network_state), config_(config),
56 server_type_(server_type), client_(), listener_(), communication_state_(),
57 query_filter_(config), mutex_(), pending_requests_(),
58 lease_update_backlog_(config->getDelayedUpdatesLimit()) {
72 if (!
config_->getEnableMultiThreading()) {
78 config_->getHttpClientThreads(),
true));
81 if (
config_->getHttpDedicatedListener()) {
83 auto my_url =
config_->getThisServerConfig()->getUrl();
84 IOAddress server_address(IOAddress::IPV4_ZERO_ADDRESS());
88 server_address =
IOAddress(my_url.getStrippedHostname());
89 }
catch (
const std::exception& ex) {
91 <<
" is not a valid IP address");
95 uint32_t listener_threads =
config_->getHttpListenerThreads();
117 StateModel::defineEvents();
130 StateModel::verifyEvents();
143 StateModel::defineStates();
382 }
else if (
config_->amAllowingCommRecovery()) {
441 if (maintenance ||
config_->getThisServerConfig()->isAutoFailover()) {
699 unsigned int dhcp_disable_timeout =
700 static_cast<unsigned int>(
config_->getSyncTimeout() / 1000);
701 if (dhcp_disable_timeout == 0) {
702 ++dhcp_disable_timeout;
706 std::string status_message;
708 config_->getFailoverPeerConfig()->getName(),
709 dhcp_disable_timeout);
864 boost::to_upper(current_state_name);
865 boost::to_upper(new_state_name);
871 std::string partner_state_name =
getStateLabel(partner_state);
872 boost::to_upper(partner_state_name);
876 .arg(current_state_name)
878 .arg(partner_state_name);
883 .arg(current_state_name)
884 .arg(new_state_name);
905 .arg(new_state_name);
907 }
else if (!
config_->amSendingLeaseUpdates()) {
910 .arg(new_state_name);
917 .arg(new_state_name);
928 switch (
config_->getHAMode()) {
953 boost::to_upper(state_name);
966 return (inScopeInternal(query4));
971 return (inScopeInternal(query6));
974 template<
typename QueryPtrType>
976 HAService::inScopeInternal(QueryPtrType& query) {
978 std::string scope_class;
997 boost::to_upper(current_state_name);
1010 boost::to_upper(current_state_name);
1012 .arg(
config_->getThisServerName())
1013 .arg(current_state_name);
1014 network_state_->disableService(NetworkState::Origin::HA_COMMAND);
1016 }
else if (should_enable && !
network_state_->isServiceEnabled()) {
1018 boost::to_upper(current_state_name);
1020 .arg(
config_->getThisServerName())
1021 .arg(current_state_name);
1059 if (!should_terminate) {
1063 return (should_terminate);
1110 size_t sent_num = 0;
1113 for (
auto p = peers_configs.begin(); p != peers_configs.end(); ++p) {
1121 for (
auto l = deleted_leases->begin(); l != deleted_leases->end(); ++l) {
1126 for (
auto l = leases->begin(); l != leases->end(); ++l) {
1140 for (
auto l = deleted_leases->begin(); l != deleted_leases->end(); ++l) {
1146 for (
auto l = leases->begin(); l != leases->end(); ++l) {
1171 size_t sent_num = 0;
1174 for (
auto p = peers_configs.begin(); p != peers_configs.end(); ++p) {
1181 for (
auto l = deleted_leases->begin(); l != deleted_leases->end(); ++l) {
1186 for (
auto l = leases->begin(); l != leases->end(); ++l) {
1214 template<
typename QueryPtrType>
1218 if (MultiThreadingMgr::instance().getMode()) {
1219 std::lock_guard<std::mutex> lock(mutex_);
1220 return (leaseUpdateCompleteInternal(query, parking_lot));
1222 return (leaseUpdateCompleteInternal(query, parking_lot));
1226 template<
typename QueryPtrType>
1228 HAService::leaseUpdateCompleteInternal(QueryPtrType& query,
1230 auto it = pending_requests_.find(query);
1234 if (it == pending_requests_.end() || (--pending_requests_[query] <= 0)) {
1235 parking_lot->unpark(query);
1239 if (it != pending_requests_.end()) {
1240 pending_requests_.erase(it);
1247 template<
typename QueryPtrType>
1250 if (MultiThreadingMgr::instance().getMode()) {
1251 std::lock_guard<std::mutex> lock(mutex_);
1252 updatePendingRequestInternal(query);
1254 updatePendingRequestInternal(query);
1258 template<
typename QueryPtrType>
1260 HAService::updatePendingRequestInternal(QueryPtrType& query) {
1261 if (pending_requests_.count(query) == 0) {
1262 pending_requests_[query] = 1;
1264 ++pending_requests_[query];
1268 template<
typename QueryPtrType>
1276 (HttpRequest::Method::HTTP_POST,
"/", HttpVersion::HTTP_11(),
1278 config->addBasicAuthHttpHeader(request);
1279 request->setBodyAsJson(command);
1280 request->finalize();
1289 boost::weak_ptr<typename QueryPtrType::element_type> weak_query(query);
1292 client_->asyncSendRequest(config->getUrl(), config->getTlsContext(),
1294 [
this, weak_query, parking_lot, config]
1295 (
const boost::system::error_code& ec,
1297 const std::string& error_str) {
1301 QueryPtrType query = weak_query.lock();
1304 " HA peer. This is programmatic error");
1313 bool lease_update_success =
true;
1316 if (ec || !error_str.empty()) {
1318 .arg(query->getLabel())
1319 .arg(config->getLogLabel())
1320 .arg(ec ? ec.message() : error_str);
1324 lease_update_success =
false;
1336 }
catch (
const std::exception& ex) {
1338 .arg(query->getLabel())
1339 .arg(config->getLogLabel())
1343 lease_update_success =
false;
1350 if (lease_update_success) {
1368 if (!lease_update_success) {
1369 parking_lot->drop(query);
1405 if (!
config_->amSendingLeaseUpdates()) {
1436 if (!
config_->amSendingLeaseUpdates()) {
1451 if (!args || (args->getType() != Element::map)) {
1461 auto failed_leases = args->get(param_name);
1464 if (failed_leases && (failed_leases->getType() == Element::list)) {
1466 for (
int i = 0; i < failed_leases->size(); ++i) {
1467 auto lease = failed_leases->get(i);
1468 if (lease->getType() == Element::map) {
1471 auto ip_address = lease->get(
"ip-address");
1474 auto lease_type = lease->get(
"type");
1477 auto error_message = lease->get(
"error-message");
1480 .arg(query->getLabel())
1481 .arg(lease_type && (lease_type->getType() == Element::string) ?
1482 lease_type->stringValue() :
"(unknown)")
1483 .arg(ip_address && (ip_address->getType() == Element::string) ?
1484 ip_address->stringValue() :
"(unknown)")
1485 .arg(error_message && (error_message->getType() == Element::string) ?
1486 error_message->stringValue() :
"(unknown)");
1501 ElementPtr ha_servers = Element::createMap();
1506 role =
config_->getThisServerConfig()->getRole();
1508 local->set(
"role", Element::create(role_txt));
1515 local->set(
"state", Element::create(std::string()));
1519 for (std::string scope : scopes) {
1520 list->add(Element::create(scope));
1522 local->set(
"scopes", list);
1523 ha_servers->set(
"local", local);
1529 return (ha_servers);
1536 role =
config_->getFailoverPeerConfig()->getRole();
1538 remote->set(
"role", Element::create(role_txt));
1541 remote->set(
"role", Element::create(std::string()));
1543 ha_servers->set(
"remote", remote);
1545 return (ha_servers);
1552 arguments->set(
"state", Element::create(state_label));
1555 arguments->set(
"date-time", Element::create(date_time));
1558 ElementPtr scopes_list = Element::createList();
1559 for (
auto scope : scopes) {
1560 scopes_list->add(Element::create(scope));
1562 arguments->set(
"scopes", scopes_list);
1584 (HttpRequest::Method::HTTP_POST,
"/", HttpVersion::HTTP_11(),
1586 partner_config->addBasicAuthHttpHeader(request);
1588 request->finalize();
1595 client_->asyncSendRequest(partner_config->getUrl(),
1596 partner_config->getTlsContext(),
1598 [
this, partner_config]
1599 (
const boost::system::error_code& ec,
1601 const std::string& error_str) {
1609 bool heartbeat_success =
true;
1612 if (ec || !error_str.empty()) {
1614 .arg(partner_config->getLogLabel())
1615 .arg(ec ? ec.message() : error_str);
1616 heartbeat_success =
false;
1626 if (!args || args->getType() != Element::map) {
1632 if (!state || state->getType() != Element::string) {
1634 " to a ha-heartbeat command or it is not a string");
1641 if (!date_time || date_time->getType() != Element::string) {
1643 " to a ha-heartbeat command or it is not a string");
1650 auto scopes = args->get(
"scopes");
1661 }
catch (
const std::exception& ex) {
1663 .arg(partner_config->getLogLabel())
1665 heartbeat_success =
false;
1671 if (heartbeat_success) {
1681 .arg(partner_config->getName());
1709 if (
config_->getHeartbeatDelay() > 0) {
1718 const std::string& server_name,
1719 const unsigned int max_period,
1725 (HttpRequest::Method::HTTP_POST,
"/", HttpVersion::HTTP_11(),
1728 remote_config->addBasicAuthHttpHeader(request);
1731 request->finalize();
1739 remote_config->getTlsContext(),
1741 [
this, remote_config, post_request_action]
1742 (
const boost::system::error_code& ec,
1744 const std::string& error_str) {
1752 std::string error_message;
1755 if (ec || !error_str.empty()) {
1756 error_message = (ec ? ec.message() : error_str);
1758 .arg(remote_config->getLogLabel())
1759 .arg(error_message);
1768 }
catch (
const std::exception& ex) {
1769 error_message = ex.what();
1771 .arg(remote_config->getLogLabel())
1772 .arg(error_message);
1778 if (!error_message.empty()) {
1783 if (post_request_action) {
1784 post_request_action(error_message.empty(),
1797 const std::string& server_name,
1803 (HttpRequest::Method::HTTP_POST,
"/", HttpVersion::HTTP_11(),
1805 remote_config->addBasicAuthHttpHeader(request);
1807 request->finalize();
1815 remote_config->getTlsContext(),
1817 [
this, remote_config, post_request_action]
1818 (
const boost::system::error_code& ec,
1820 const std::string& error_str) {
1828 std::string error_message;
1831 if (ec || !error_str.empty()) {
1832 error_message = (ec ? ec.message() : error_str);
1834 .arg(remote_config->getLogLabel())
1835 .arg(error_message);
1844 }
catch (
const std::exception& ex) {
1845 error_message = ex.what();
1847 .arg(remote_config->getLogLabel())
1848 .arg(error_message);
1854 if (!error_message.empty()) {
1859 if (post_request_action) {
1860 post_request_action(error_message.empty(),
1873 network_state_->disableService(NetworkState::Origin::HA_COMMAND);
1886 unsigned int dhcp_disable_timeout =
1887 static_cast<unsigned int>(
config_->getSyncTimeout() / 1000);
1888 if (dhcp_disable_timeout == 0) {
1890 dhcp_disable_timeout = 1;
1894 dhcp_disable_timeout,
LeasePtr(), null_action);
1899 const std::string& server_name,
1900 const unsigned int max_period,
1903 const bool dhcp_disabled) {
1910 [
this, &http_client, server_name, max_period, last_lease,
1911 post_sync_action, dhcp_disabled]
1912 (
const bool success,
const std::string& error_message) {
1920 last_lease, post_sync_action,
true);
1923 post_sync_action(success, error_message, dhcp_disabled);
1930 const std::string& server_name,
1931 const unsigned int max_period,
1934 const bool dhcp_disabled) {
1940 (HttpRequest::Method::HTTP_POST,
"/", HttpVersion::HTTP_11(),
1942 partner_config->addBasicAuthHttpHeader(request);
1945 boost::dynamic_pointer_cast<Lease4>(last_lease),
config_->getSyncPageLimit()));
1949 boost::dynamic_pointer_cast<Lease6>(last_lease),
config_->getSyncPageLimit()));
1951 request->finalize();
1959 partner_config->getTlsContext(),
1961 [
this, partner_config, post_sync_action, &http_client, server_name,
1962 max_period, dhcp_disabled]
1963 (
const boost::system::error_code& ec,
1965 const std::string& error_str) {
1977 std::string error_message;
1980 if (ec || !error_str.empty()) {
1981 error_message = (ec ? ec.message() : error_str);
1983 .arg(partner_config->getLogLabel())
1984 .arg(error_message);
1993 if (args && (args->getType() != Element::map)) {
1995 "arguments in the received response must be a map");
1999 if (!leases || (leases->getType() != Element::list)) {
2001 "server response does not contain leases argument or this"
2002 " argument is not a list");
2006 const auto& leases_element = leases->listValue();
2009 .arg(leases_element.size())
2012 for (
auto l = leases_element.begin(); l != leases_element.end(); ++l) {
2016 Lease4Ptr lease = Lease4::fromElement(*l);
2019 Lease4Ptr existing_lease = LeaseMgrFactory::instance().getLease4(lease->addr_);
2020 if (!existing_lease) {
2022 LeaseMgrFactory::instance().addLease(lease);
2024 }
else if (existing_lease->cltt_ < lease->cltt_) {
2030 Lease::syncCurrentExpirationTime(*existing_lease, *lease);
2031 LeaseMgrFactory::instance().updateLease4(lease);
2035 .arg(lease->addr_.toText())
2036 .arg(lease->subnet_id_);
2042 if ((leases_element.size() >=
config_->getSyncPageLimit()) &&
2043 (l + 1 == leases_element.end())) {
2044 last_lease = boost::dynamic_pointer_cast<
Lease>(lease);
2048 Lease6Ptr lease = Lease6::fromElement(*l);
2051 Lease6Ptr existing_lease = LeaseMgrFactory::instance().getLease6(lease->type_,
2053 if (!existing_lease) {
2055 LeaseMgrFactory::instance().addLease(lease);
2057 }
else if (existing_lease->cltt_ < lease->cltt_) {
2063 Lease::syncCurrentExpirationTime(*existing_lease, *lease);
2064 LeaseMgrFactory::instance().updateLease6(lease);
2068 .arg(lease->addr_.toText())
2069 .arg(lease->subnet_id_);
2075 if ((leases_element.size() >=
config_->getSyncPageLimit()) &&
2076 (l + 1 == leases_element.end())) {
2077 last_lease = boost::dynamic_pointer_cast<
Lease>(lease);
2081 }
catch (
const std::exception& ex) {
2088 }
catch (
const std::exception& ex) {
2089 error_message = ex.what();
2091 .arg(partner_config->getLogLabel())
2092 .arg(error_message);
2098 if (!error_message.empty()) {
2101 }
else if (last_lease) {
2105 post_sync_action, dhcp_disabled);
2110 if (post_sync_action) {
2111 post_sync_action(error_message.empty(),
2126 const unsigned int max_period) {
2127 std::string answer_message;
2128 int sync_status =
synchronize(answer_message, server_name, max_period);
2134 const unsigned int max_period) {
2139 [&](
const bool success,
const std::string& error_message,
2140 const bool dhcp_disabled) {
2145 status_message = error_message;
2151 if (dhcp_disabled) {
2153 [&](
const bool success,
2154 const std::string& error_message) {
2158 if (!success && status_message.empty()) {
2159 status_message = error_message;
2189 if (!status_message.empty()) {
2194 .arg(status_message);
2201 status_message =
"Lease database synchronization complete.";
2216 post_request_action(
true,
"");
2236 (HttpRequest::Method::HTTP_POST,
"/", HttpVersion::HTTP_11(),
2238 config->addBasicAuthHttpHeader(request);
2239 request->setBodyAsJson(command);
2240 request->finalize();
2248 [
this, &http_client, config, post_request_action]
2249 (
const boost::system::error_code& ec,
2251 const std::string& error_str) {
2253 std::string error_message;
2255 if (ec || !error_str.empty()) {
2256 error_message = (ec ? ec.message() : error_str);
2258 .arg(config->getLogLabel())
2259 .arg(ec ? ec.message() : error_str);
2266 }
catch (
const std::exception& ex) {
2267 error_message = ex.what();
2269 .arg(config->getLogLabel())
2279 if (error_message.empty()) {
2282 post_request_action(error_message.empty(), error_message);
2290 if (num_updates == 0) {
2297 auto remote_config =
config_->getFailoverPeerConfig();
2298 bool updates_successful =
true;
2302 .arg(remote_config->getName());
2305 [&](
const bool success,
const std::string&) {
2307 updates_successful = success;
2319 if (updates_successful) {
2321 .arg(remote_config->getName())
2322 .arg(stopwatch.logFormatLastDuration());
2325 return (updates_successful);
2336 (HttpRequest::Method::HTTP_POST,
"/", HttpVersion::HTTP_11(),
2338 config->addBasicAuthHttpHeader(request);
2339 request->setBodyAsJson(command);
2340 request->finalize();
2348 [
this, config, post_request_action]
2349 (
const boost::system::error_code& ec,
2351 const std::string& error_str) {
2353 std::string error_message;
2355 if (ec || !error_str.empty()) {
2356 error_message = (ec ? ec.message() : error_str);
2358 .arg(config->getLogLabel())
2359 .arg(ec ? ec.message() : error_str);
2366 }
catch (
const std::exception& ex) {
2367 error_message = ex.what();
2369 .arg(config->getLogLabel())
2374 post_request_action(error_message.empty(), error_message);
2382 auto remote_config =
config_->getFailoverPeerConfig();
2383 bool reset_successful =
true;
2386 [&](
const bool success,
const std::string&) {
2388 reset_successful = success;
2394 return (reset_successful);
2403 }
catch (
const std::exception& ex) {
2423 " maintenance for the server not in the"
2424 " in-maintenance state."));
2444 "Unable to transition the server from the "
2446 " in-maintenance state."));
2463 " partner-in-maintenance state."));
2473 (HttpRequest::Method::HTTP_POST,
"/", HttpVersion::HTTP_11(),
2475 remote_config->addBasicAuthHttpHeader(request);
2477 request->finalize();
2486 boost::system::error_code captured_ec;
2487 std::string captured_error_message;
2488 int captured_rcode = 0;
2492 remote_config->getTlsContext(),
2494 [
this, remote_config, &io_service, &captured_ec, &captured_error_message,
2496 (
const boost::system::error_code& ec,
2498 const std::string& error_str) {
2508 std::string error_message;
2511 if (ec || !error_str.empty()) {
2512 error_message = (ec ? ec.message() : error_str);
2514 .arg(remote_config->getLogLabel())
2515 .arg(error_message);
2523 }
catch (
const std::exception& ex) {
2524 error_message = ex.what();
2526 .arg(remote_config->getLogLabel())
2527 .arg(error_message);
2533 if (!error_message.empty()) {
2538 captured_error_message = error_message;
2557 "Server is now in the partner-down state as its"
2558 " partner appears to be offline for maintenance."));
2572 " partner-in-maintenance state. The partner server responded"
2573 " with the following message to the ha-maintenance-notify"
2574 " command: " + captured_error_message +
"."));
2579 "Server is now in the partner-in-maintenance state"
2580 " and its partner is in-maintenance state. The partner"
2581 " can be now safely shut down."));
2588 " request because the server is not in the"
2589 " partner-in-maintenance state."));
2597 (HttpRequest::Method::HTTP_POST,
"/", HttpVersion::HTTP_11(),
2599 remote_config->addBasicAuthHttpHeader(request);
2601 request->finalize();
2610 std::string error_message;
2614 remote_config->getTlsContext(),
2616 [
this, remote_config, &io_service, &error_message]
2617 (
const boost::system::error_code& ec,
2619 const std::string& error_str) {
2624 if (ec || !error_str.empty()) {
2625 error_message = (ec ? ec.message() : error_str);
2627 .arg(remote_config->getLogLabel())
2628 .arg(error_message);
2637 }
catch (
const std::exception& ex) {
2638 error_message = ex.what();
2640 .arg(remote_config->getLogLabel())
2641 .arg(error_message);
2647 if (!error_message.empty()) {
2663 if (!error_message.empty()) {
2665 "Unable to cancel maintenance. The partner server responded"
2666 " with the following message to the ha-maintenance-notify"
2667 " command: " + error_message +
"."));
2677 "Server maintenance successfully canceled."));
2687 if (!json_response) {
2698 if (body->getType() != Element::list) {
2700 if (body->getType() == Element::map) {
2716 if (body->empty()) {
2725 std::ostringstream s;
2727 if (args && args->getType() == Element::string) {
2728 s << args->stringValue() <<
", ";
2731 s <<
"error code " << rcode;
2743 if (
client_->getThreadIOService()) {
2751 if ((!ec || (ec.value() == boost::asio::error::in_progress))
2752 && (tcp_native_fd >= 0)) {
2757 IfaceMgr::instance().addExternalSocket(tcp_native_fd,
2775 client_->closeIfOutOfBand(tcp_native_fd);
2780 if (tcp_native_fd >= 0) {
2781 IfaceMgr::instance().deleteExternalSocket(tcp_native_fd);
2787 if (MultiThreadingMgr::instance().getMode()) {
2788 std::lock_guard<std::mutex> lock(mutex_);
2789 return (pending_requests_.size());
2791 return (pending_requests_.size());
2795 template<
typename QueryPtrType>
2798 if (MultiThreadingMgr::instance().getMode()) {
2799 std::lock_guard<std::mutex> lock(mutex_);
2800 return (getPendingRequestInternal(query));
2802 return (getPendingRequestInternal(query));
2806 template<
typename QueryPtrType>
2808 HAService::getPendingRequestInternal(
const QueryPtrType& query) {
2809 if (pending_requests_.count(query) == 0) {
2812 return (pending_requests_[query]);
2819 MultiThreadingMgr::instance().addCriticalSectionCallbacks(
"HA_MT",
2844 }
catch (std::exception& ex) {
2862 }
catch (std::exception& ex) {
2871 MultiThreadingMgr::instance().removeCriticalSectionCallbacks(
"HA_MT");
void defineState(unsigned int value, const std::string &label, StateHandler handler, const StatePausing &state_pausing=STATE_PAUSE_NEVER)
Adds an state value and associated label to the set of states.
config::CmdHttpListenerPtr listener_
HTTP listener instance used to receive and respond to HA commands and lease updates.
static const int NOP_EVT
Signifies that no event has occurred.
static data::ConstElementPtr createHAReset(const HAServerType &server_type)
Creates ha-reset command.
const isc::log::MessageID HA_SYNC_FAILED
const int HA_TERMINATED_ST
HA service terminated state.
static const int HA_CONTROL_RESULT_MAINTENANCE_NOT_ALLOWED
Control result returned in response to ha-maintenance-notify.
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
virtual void defineStates()
Defines states of the HA service.
data::ConstElementPtr processStatusGet() const
Processes status-get command and returns a response.
const isc::log::MessageID HA_MAINTENANCE_NOTIFY_COMMUNICATIONS_FAILED
void serveDefaultScopes()
Instructs the HA service to serve default scopes.
data::ConstElementPtr processHAReset()
Processes ha-reset command and returns a response.
std::string rfc1123Format() const
Returns time value formatted as specified in RFC 1123.
const int HA_COMMUNICATION_RECOVERY_ST
Communication recovery state.
void pauseClientAndListener()
Pauses client and(or) listener thread pool operations.
const isc::log::MessageID HA_STATE_TRANSITION
const int HA_HOT_STANDBY_ST
Hot standby state.
const char * CONTROL_RESULT
String used for result, i.e. integer status ("result")
Structure that holds a lease for IPv4 address.
bool leaseUpdateComplete(QueryPtrType &query, const hooks::ParkingLotHandlePtr &parking_lot)
Handle last pending request for this query.
const isc::log::MessageID HA_LEASES_BACKLOG_COMMUNICATIONS_FAILED
static const int HA_MAINTENANCE_CANCEL_EVT
ha-maintenance-cancel command received.
void defineEvent(unsigned int value, const std::string &label)
Adds an event value and associated label to the set of events.
const int DBGLVL_TRACE_BASIC
Trace basic operations.
int getNormalState() const
Returns normal operation state for the current configuration.
bool doOnExit()
Checks if on exit flag is true.
void readyStateHandler()
Handler for "ready" state.
void serveNoScopes()
Disables all scopes.
void run()
Start the underlying event loop.
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
ConstElementPtr createAnswer(const int status_code, const std::string &text, const ConstElementPtr &arg)
const StatePtr getState(unsigned int value)
Fetches the state referred to by value.
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
void asyncSendRequest(const Url &url, const asiolink::TlsContextPtr &tls_context, const HttpRequestPtr &request, const HttpResponsePtr &response, const RequestHandler &request_callback, const RequestTimeout &request_timeout=RequestTimeout(10000), const ConnectHandler &connect_callback=ConnectHandler(), const HandshakeHandler &handshake_callback=HandshakeHandler(), const CloseHandler &close_callback=CloseHandler())
Queues new asynchronous HTTP request for a given URL.
size_t pendingRequestSize()
Get the number of entries in the pending request map.
data::ConstElementPtr processScopes(const std::vector< std::string > &scopes)
Processes ha-scopes command and returns a response.
void scheduleHeartbeat()
Schedules asynchronous heartbeat to a peer if it is not scheduled.
std::map< std::string, PeerConfigPtr > PeerConfigMap
Map of the servers' configurations.
void asyncEnableDHCPService(http::HttpClient &http_client, const std::string &server_name, PostRequestCallback post_request_action)
Schedules asynchronous "dhcp-enable" command to the specified server.
boost::shared_ptr< HttpResponseJson > HttpResponseJsonPtr
Pointer to the HttpResponseJson object.
bool inScope(const dhcp::Pkt4Ptr &query4, std::string &scope_class) const
Checks if this server should process the DHCPv4 query.
const isc::log::MessageID HA_INVALID_PARTNER_STATE_COMMUNICATION_RECOVERY
const isc::log::MessageID HA_LEASE_UPDATES_ENABLED
bool unpause()
Unpauses the HA state machine with logging.
const isc::log::MessageID HA_LEASES_BACKLOG_NOTHING_TO_SEND
void passiveBackupStateHandler()
Handler for "passive-backup" state.
const int HA_PARTNER_DOWN_ST
Partner down state.
std::string getStateLabel(const int state) const
Fetches the label associated with an state value.
void asyncSyncLeases()
Asynchronously reads leases from a peer and updates local lease database.
const isc::log::MessageID HA_LEASE_UPDATE_DELETE_FAILED_ON_PEER
data::ConstElementPtr processHeartbeat()
Processes ha-heartbeat command and returns a response.
QueryFilter query_filter_
Selects queries to be processed/dropped.
An abstract API for lease database.
LeaseUpdateBacklog lease_update_backlog_
Backlog of DHCP lease updates.
OpType
Type of the lease update (operation type).
const isc::log::MessageID HA_MAINTENANCE_STARTED_IN_PARTNER_DOWN
const isc::log::MessageID HA_LEASES_SYNC_COMMUNICATIONS_FAILED
CommunicationStatePtr communication_state_
Holds communication state with a peer.
virtual void verifyEvents()
Verifies events used by the HA service.
const int HA_IN_MAINTENANCE_ST
In maintenance state.
HTTP request/response timeout value.
unsigned int getLastEvent() const
Fetches the model's last event.
static const int HA_SYNCING_SUCCEEDED_EVT
Lease database synchronization succeeded.
bool shouldQueueLeaseUpdates(const HAConfig::PeerConfigPtr &peer_config) const
Checks if the lease updates should be queued.
bool clientConnectHandler(const boost::system::error_code &ec, int tcp_native_fd)
HttpClient connect callback handler.
const int HA_LOAD_BALANCING_ST
Load balancing state.
HAServerType server_type_
DHCP server type.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
boost::shared_ptr< IOService > IOServicePtr
Defines a smart pointer to an IOService instance.
const int CONTROL_RESULT_ERROR
Status code indicating a general failure.
boost::shared_ptr< Element > ElementPtr
const isc::log::MessageID HA_LEASE_SYNC_STALE_LEASE4_SKIP
static const int HA_MAINTENANCE_NOTIFY_EVT
ha-maintenance-notify command received.
const isc::log::MessageID HA_CONFIG_LEASE_UPDATES_DISABLED_REMINDER
const isc::log::MessageID HA_MAINTENANCE_NOTIFY_FAILED
const isc::log::MessageID HA_RESET_FAILED
std::set< std::string > getServedScopes() const
Returns served scopes.
data::ConstElementPtr processMaintenanceCancel()
Processes ha-maintenance-cancel command and returns a response.
const isc::log::MessageID HA_COMMUNICATION_INTERRUPTED
static data::ConstElementPtr createLease6GetPage(const dhcp::Lease6Ptr &lease6, const uint32_t limit)
Creates lease6-get-page command.
void waitingStateHandler()
Handler for "waiting" state.
const isc::log::MessageID HA_LEASES_BACKLOG_SUCCESS
void updatePendingRequest(QueryPtrType &query)
Update pending request counter for this query.
const int HA_PASSIVE_BACKUP_ST
In passive-backup state with a single active server and backup servers.
void partnerInMaintenanceStateHandler()
Handler for "partner-in-maintenance" state.
HAServerType
Lists possible server types for which HA service is created.
const int HA_BACKUP_ST
Backup state.
virtual ~HAService()
Destructor.
bool isMaintenanceCanceled() const
Convenience method checking if the current state is a result of canceling the maintenance.
unsigned int getCurrState() const
Fetches the model's current state.
const isc::log::MessageID HA_LEASE_UPDATES_DISABLED
const isc::log::MessageID HA_RESET_COMMUNICATIONS_FAILED
boost::shared_ptr< Lease > LeasePtr
Pointer to the lease object.
void serveDefaultScopes()
Serve default scopes for the given HA mode.
dhcp::NetworkStatePtr network_state_
Pointer to the state of the DHCP service (enabled/disabled).
static const int HA_MAINTENANCE_START_EVT
ha-maintenance-start command received.
const isc::log::MessageID HA_RESUME_CLIENT_LISTENER_FAILED
The IOService class is a wrapper for the ASIO io_service class.
virtual void runModel(unsigned int event)
Processes events through the state model.
const int CONTROL_RESULT_EMPTY
Status code indicating that the specified command was completed correctly, but failed to produce any ...
asiolink::IOServicePtr io_service_
Pointer to the IO service object shared between this hooks library and the DHCP server.
const int HA_WAITING_ST
Server waiting state, i.e. waiting for another server to be ready.
const isc::log::MessageID HA_INVALID_PARTNER_STATE_HOT_STANDBY
bool isPartnerStateInvalid() const
Indicates if the partner's state is invalid.
data::ConstElementPtr processContinue()
Processes ha-continue command and returns a response.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
void stop()
Stops the stopwatch.
Holds communication state between DHCPv4 servers.
void resumeClientAndListener()
Resumes client and(or) listener thread pool operations.
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
const int HA_PARTNER_IN_MAINTENANCE_ST
Partner in-maintenance state.
boost::shared_ptr< PostHttpRequestJson > PostHttpRequestJsonPtr
Pointer to PostHttpRequestJson.
const int HA_READY_ST
Server ready state, i.e. synchronized database, can enable DHCP service.
static const int HA_HEARTBEAT_COMPLETE_EVT
Finished heartbeat command.
const isc::log::MessageID HA_LEASE_UPDATE_CREATE_UPDATE_FAILED_ON_PEER
const isc::log::MessageID HA_DHCP_DISABLE_COMMUNICATIONS_FAILED
static const int HA_LEASE_UPDATES_COMPLETE_EVT
Finished lease updates commands.
bool shouldSendLeaseUpdates(const HAConfig::PeerConfigPtr &peer_config) const
Checks if the lease updates should be sent as result of leases allocation or release.
boost::shared_ptr< Lease4 > Lease4Ptr
Pointer to a Lease4 structure.
std::string logFormatLastDuration() const
Returns the last measured duration in the format directly usable in log messages. ...
static data::ConstElementPtr createLease4Update(const dhcp::Lease4 &lease4)
Creates lease4-update command.
void partnerDownStateHandler()
Handler for "partner-down" state.
void syncingStateHandler()
Handler for "syncing" state.
void clear()
Removes all lease updates from the queue.
boost::shared_ptr< HttpResponse > HttpResponsePtr
Pointer to the HttpResponse object.
Utility class to measure code execution times.
void asyncSendHeartbeat()
Starts asynchronous heartbeat to a peer.
void serveScopes(const std::vector< std::string > &scopes)
Enables selected scopes.
const isc::log::MessageID HA_LEASES_BACKLOG_START
boost::shared_ptr< Lease4Collection > Lease4CollectionPtr
A shared pointer to the collection of IPv4 leases.
void inMaintenanceStateHandler()
Handler for the "in-maintenance" state.
void logFailedLeaseUpdates(const dhcp::PktPtr &query, const data::ConstElementPtr &args) const
Log failed lease updates.
A generic exception that is thrown when an unexpected error condition occurs.
void asyncSendLeaseUpdate(const QueryPtrType &query, const HAConfig::PeerConfigPtr &config, const data::ConstElementPtr &command, const hooks::ParkingLotHandlePtr &parking_lot)
Asynchronously sends lease update to the peer.
bool doOnEntry()
Checks if on entry flag is true.
const char * CONTROL_TEXT
String used for storing textual description ("text")
const isc::log::MessageID HA_LEASE_SYNC_FAILED
bool push(const OpType op_type, const dhcp::LeasePtr &lease)
Appends lease update to the queue.
const isc::log::MessageID HA_SERVICE_STARTED
std::string stateToString(int state)
Returns state name.
const isc::log::MessageID HA_LOCAL_DHCP_ENABLE
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
void stop()
Stop the underlying event loop.
boost::shared_ptr< const Element > ConstElementPtr
const isc::log::MessageID HA_STATE_TRANSITION_PASSIVE_BACKUP
const isc::log::MessageID HA_HEARTBEAT_FAILED
data::ConstElementPtr processMaintenanceNotify(const bool cancel)
Processes ha-maintenance-notify command and returns a response.
const isc::log::MessageID HA_DHCP_DISABLE_FAILED
size_t size()
Returns the current size of the queue.
bool inScope(dhcp::Pkt4Ptr &query4)
Checks if the DHCPv4 query should be processed by this server.
void terminatedStateHandler()
Handler for "terminated" state.
bool wasOverflown()
Checks if the queue was overflown.
void stopClientAndListener()
Stop the client and(or) listener instances.
const isc::log::MessageID HA_LEASE_UPDATE_COMMUNICATIONS_FAILED
const isc::log::MessageID HA_LEASE_UPDATE_FAILED
void serveFailoverScopes()
Enable scopes required in failover case.
void localDisableDHCPService()
Disables local DHCP service.
boost::shared_ptr< isc::dhcp::Pkt > PktPtr
A pointer to either Pkt4 or Pkt6 packet.
void adjustNetworkState()
Enables or disables network state depending on the served scopes.
const isc::log::MessageID HA_INVALID_PARTNER_STATE_LOAD_BALANCING
This class parses and generates time values used in HTTP.
const isc::log::MessageID HA_SYNC_START
static data::ConstElementPtr createLease4Delete(const dhcp::Lease4 &lease4)
Creates lease4-del command.
void startModel(const int start_state)
Begins execution of the model.
void unpauseModel()
Unpauses state model.
Represents HTTP response with JSON content.
void asyncSyncLeasesInternal(http::HttpClient &http_client, const std::string &server_name, const unsigned int max_period, const dhcp::LeasePtr &last_lease, PostSyncCallback post_sync_action, const bool dhcp_disabled)
Implements fetching one page of leases during synchronization.
std::function< void(const bool, const std::string &, const bool)> PostSyncCallback
Callback invoked when lease database synchronization is complete.
void communicationRecoveryHandler()
Handler for the "communication-recovery" state.
A standard control channel exception that is thrown if a function is there is a problem with one of t...
ConstElementPtr parseAnswer(int &rcode, const ConstElementPtr &msg)
Defines the logger used by the top-level component of kea-dhcp-ddns.
const isc::log::MessageID HA_STATE_MACHINE_PAUSED
bool shouldPartnerDown() const
Indicates if the server should transition to the partner down state.
const isc::log::MessageID HA_LOCAL_DHCP_DISABLE
void conditionalLogPausedState() const
Logs if the server is paused in the current state.
unsigned int getPrevState() const
Fetches the model's previous state.
const isc::log::MessageID HA_MAINTENANCE_NOTIFY_CANCEL_COMMUNICATIONS_FAILED
data::ConstElementPtr processMaintenanceStart()
Processes ha-maintenance-start command and returns a response.
HAConfigPtr config_
Pointer to the HA hooks library configuration.
void startHeartbeat()
Unconditionally starts one heartbeat to a peer.
const isc::log::MessageID HA_MAINTENANCE_STARTED
const isc::log::MessageID HA_HEARTBEAT_COMMUNICATIONS_FAILED
void transition(unsigned int state, unsigned int event)
Sets up the model to transition into given state with a given event.
void startClientAndListener()
Start the client and(or) listener instances.
http::HttpClientPtr client_
HTTP client instance used to send HA commands and lease updates.
const isc::log::MessageID HA_DHCP_ENABLE_FAILED
void normalStateHandler()
Handler for the "hot-standby" and "load-balancing" states.
This file contains several functions and constants that are used for handling commands and responses ...
bool sendLeaseUpdatesFromBacklog()
Attempts to send all lease updates from the backlog synchronously.
static std::string HAModeToString(const HAMode &ha_mode)
Returns HA mode name.
void localEnableDHCPService()
Enables local DHCP service.
a common structure for IPv4 and IPv6 leases
virtual void defineEvents()
Defines events used by the HA service.
std::function< void(const bool, const std::string &)> PostRequestCallback
Callback invoked when request was sent and a response received or an error occurred.
boost::shared_ptr< Lease6Collection > Lease6CollectionPtr
A shared pointer to the collection of IPv6 leases.
boost::shared_ptr< NetworkState > NetworkStatePtr
Pointer to the NetworkState object.
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
static data::ConstElementPtr createLease6BulkApply(const dhcp::Lease6CollectionPtr &leases, const dhcp::Lease6CollectionPtr &deleted_leases)
Creates lease6-bulk-apply command.
isc::log::Logger ha_logger("ha-hooks")
const isc::log::MessageID HA_LEASE_SYNC_STALE_LEASE6_SKIP
void backupStateHandler()
Handler for the "backup" state.
int getPendingRequest(const QueryPtrType &query)
Get the number of scheduled requests for a given query.
const isc::log::MessageID HA_SYNC_SUCCESSFUL
const isc::log::MessageID HA_LEASES_BACKLOG_FAILED
static const int HA_SYNCING_FAILED_EVT
Lease database synchronization failed.
A multi-threaded HTTP listener that can process API commands requests.
Role
Server's role in the High Availability setup.
const isc::log::MessageID HA_MAINTENANCE_SHUTDOWN_SAFE
size_t asyncSendLeaseUpdates(const dhcp::Pkt4Ptr &query, const dhcp::Lease4CollectionPtr &leases, const dhcp::Lease4CollectionPtr &deleted_leases, const hooks::ParkingLotHandlePtr &parking_lot)
Schedules asynchronous IPv4 leases updates.
boost::shared_ptr< ParkingLotHandle > ParkingLotHandlePtr
Pointer to the parking lot handle.
void asyncSendHAReset(http::HttpClient &http_client, const HAConfig::PeerConfigPtr &remote_config, PostRequestCallback post_request_action)
Sends ha-reset command to partner asynchronously.
dhcp::LeasePtr pop(OpType &op_type)
Returns the next lease update and removes it from the queue.
const isc::log::MessageID HA_PAUSE_CLIENT_LISTENER_FAILED
const isc::log::MessageID HA_CONFIG_LEASE_SYNCING_DISABLED_REMINDER
const isc::log::MessageID HA_MAINTENANCE_NOTIFY_CANCEL_FAILED
static std::string roleToString(const HAConfig::PeerConfig::Role &role)
Returns role name.
const isc::log::MessageID HA_STATE_MACHINE_CONTINUED
void socketReadyHandler(int tcp_native_fd)
IfaceMgr external socket ready callback handler.
static data::ConstElementPtr createHeartbeat(const HAServerType &server_type)
Creates ha-heartbeat command for DHCP server.
std::string ClientClass
Defines a single class name.
The IOAddress class represents an IP addresses (version agnostic)
const EventPtr & getEvent(unsigned int value)
Fetches the event referred to by value.
unsigned int getNextEvent() const
Fetches the model's next event.
const isc::log::MessageID HA_TERMINATED_RESTART_PARTNER
constexpr long TIMEOUT_DEFAULT_HTTP_CLIENT_REQUEST
Timeout for the HTTP clients awaiting a response to a request.
data::ConstElementPtr processSynchronize(const std::string &server_name, const unsigned int max_period)
Processes ha-sync command and returns a response.
const int HA_SYNCING_ST
Synchronizing database state.
const isc::log::MessageID HA_DHCP_ENABLE_COMMUNICATIONS_FAILED
const isc::log::MessageID HA_LEASES_SYNC_LEASE_PAGE_RECEIVED
boost::shared_ptr< Lease6 > Lease6Ptr
Pointer to a Lease6 structure.
const isc::log::MessageID HA_LEASES_SYNC_FAILED
static data::ConstElementPtr createMaintenanceNotify(const bool cancel, const HAServerType &server_type)
Creates ha-maintenance-notify command.
bool isModelPaused() const
Returns whether or not the model is paused.
data::ConstElementPtr verifyAsyncResponse(const http::HttpResponsePtr &response, int &rcode)
Checks if the response is valid or contains an error.
static data::ConstElementPtr createDHCPEnable(const HAServerType &server_type)
Creates dhcp-enable command for DHCP server.
bool shouldTerminate() const
Indicates if the server should transition to the terminated state as a result of high clock skew...
void clientCloseHandler(int tcp_native_fd)
HttpClient close callback handler.
void verboseTransition(const unsigned state)
Transitions to a desired state and logs it.
boost::shared_ptr< HAConfig > HAConfigPtr
Pointer to the High Availability configuration structure.
bool sendHAReset()
Sends ha-reset command to partner synchronously.
static data::ConstElementPtr createDHCPDisable(const unsigned int max_period, const HAServerType &server_type)
Creates dhcp-disable command for DHCP server.
Holds communication state between DHCPv6 servers.
const int HA_UNAVAILABLE_ST
Special state indicating that this server is unable to communicate with the partner.
void postNextEvent(unsigned int event)
Sets the next event to the given event value.
int synchronize(std::string &status_message, const std::string &server_name, const unsigned int max_period)
Synchronizes lease database with a partner.
bool clientHandshakeHandler(const boost::system::error_code &)
HttpClient handshake callback handler.
boost::shared_ptr< PeerConfig > PeerConfigPtr
Pointer to the server's configuration.
static data::ConstElementPtr createLease4GetPage(const dhcp::Lease4Ptr &lease4, const uint32_t limit)
Creates lease4-get-page command.
const isc::log::MessageID HA_TERMINATED
void asyncDisableDHCPService(http::HttpClient &http_client, const std::string &server_name, const unsigned int max_period, PostRequestCallback post_request_action)
Schedules asynchronous "dhcp-disable" command to the specified server.
void asyncSendLeaseUpdatesFromBacklog(http::HttpClient &http_client, const HAConfig::PeerConfigPtr &remote_config, PostRequestCallback post_request_action)
Sends lease updates from backlog to partner asynchronously.