27#include <boost/pointer_cast.hpp>
28#include <boost/make_shared.hpp>
29#include <boost/weak_ptr.hpp>
41namespace ph = std::placeholders;
48 CommandUnsupportedError(
const char* file,
size_t line,
const char* what) :
55 ConflictError(
const char* file,
size_t line,
const char* what) :
78 : id_(id), io_service_(io_service), network_state_(network_state), config_(config),
79 server_type_(server_type), client_(), listener_(), communication_state_(),
80 query_filter_(config), lease_sync_filter_(server_type, config), mutex_(),
81 pending_requests_(), lease_update_backlog_(config->getDelayedUpdatesLimit()),
82 sync_complete_notified_(false) {
96 if (!
config_->getEnableMultiThreading()) {
102 config_->getHttpClientThreads(),
true));
105 if (
config_->getHttpDedicatedListener()) {
107 auto my_url =
config_->getThisServerConfig()->getUrl();
112 server_address =
IOAddress(my_url.getStrippedHostname());
113 }
catch (
const std::exception& ex) {
115 <<
" is not a valid IP address");
119 uint32_t listener_threads =
config_->getHttpListenerThreads();
122 auto tls_context =
config_->getThisServerConfig()->getTlsContext();
126 listener_threads, tls_context));
128 if (
config_->getRestrictCommands()) {
141 .arg(
config_->getThisServerName())
154HAService::getCSCallbacksSetName()
const {
155 std::ostringstream s;
156 s <<
"HA_MT_" <<
id_;
161HAService::defineEvents() {
175HAService::verifyEvents() {
189HAService::defineStates() {
193 std::bind(&HAService::backupStateHandler,
this),
197 std::bind(&HAService::communicationRecoveryHandler,
this),
201 std::bind(&HAService::normalStateHandler,
this),
205 std::bind(&HAService::normalStateHandler,
this),
209 std::bind(&HAService::inMaintenanceStateHandler,
this),
213 std::bind(&HAService::partnerDownStateHandler,
this),
217 std::bind(&HAService::partnerInMaintenanceStateHandler,
this),
221 std::bind(&HAService::passiveBackupStateHandler,
this),
225 std::bind(&HAService::readyStateHandler,
this),
229 std::bind(&HAService::syncingStateHandler,
this),
233 std::bind(&HAService::terminatedStateHandler,
this),
237 std::bind(&HAService::waitingStateHandler,
this),
242HAService::backupStateHandler() {
257HAService::communicationRecoveryHandler() {
374HAService::normalStateHandler() {
429 }
else if (
config_->amAllowingCommRecovery()) {
449HAService::inMaintenanceStateHandler() {
463 .arg(
config_->getThisServerName());
475HAService::partnerDownStateHandler() {
489 if (maintenance ||
config_->getThisServerConfig()->isAutoFailover()) {
504 .arg(
config_->getThisServerName());
567HAService::partnerInMaintenanceStateHandler() {
580 .arg(
config_->getThisServerName());
607HAService::passiveBackupStateHandler() {
625HAService::readyStateHandler() {
705HAService::syncingStateHandler() {
765 unsigned int dhcp_disable_timeout =
766 static_cast<unsigned int>(
config_->getSyncTimeout() / 1000);
767 if (dhcp_disable_timeout == 0) {
768 ++dhcp_disable_timeout;
772 std::string status_message;
774 config_->getFailoverPeerConfig(),
775 dhcp_disable_timeout);
795HAService::terminatedStateHandler() {
811 .arg(
config_->getThisServerName());
818HAService::waitingStateHandler() {
890 if (!partner_in_terminated.is_not_a_date_time() &&
893 .arg(
config_->getThisServerName())
906 .arg(
config_->getThisServerName());
944 boost::to_upper(current_state_name);
945 boost::to_upper(new_state_name);
951 std::string partner_state_name =
getStateLabel(partner_state);
952 boost::to_upper(partner_state_name);
956 .arg(
config_->getThisServerName())
957 .arg(current_state_name)
959 .arg(partner_state_name);
964 .arg(
config_->getThisServerName())
965 .arg(current_state_name)
966 .arg(new_state_name);
975 .arg(
config_->getThisServerName());
988 .arg(
config_->getThisServerName())
989 .arg(new_state_name);
991 }
else if (!
config_->amSendingLeaseUpdates()) {
994 .arg(
config_->getThisServerName())
995 .arg(new_state_name);
1002 .arg(
config_->getThisServerName())
1003 .arg(new_state_name);
1014 switch (
config_->getHAMode()) {
1028 .arg(
config_->getThisServerName());
1040 boost::to_upper(state_name);
1042 .arg(
config_->getThisServerName())
1059 return (inScopeInternal(query4));
1064 return (inScopeInternal(query6));
1067template<
typename QueryPtrType>
1069HAService::inScopeInternal(QueryPtrType& query) {
1071 std::string scope_class;
1090 boost::to_upper(current_state_name);
1103 boost::to_upper(current_state_name);
1105 .arg(
config_->getThisServerName())
1106 .arg(current_state_name);
1109 }
else if (should_enable && !
network_state_->isServiceEnabled()) {
1111 boost::to_upper(current_state_name);
1113 .arg(
config_->getThisServerName())
1114 .arg(current_state_name);
1152 if (!should_terminate) {
1159 return (should_terminate);
1173 .arg(
config_->getThisServerName());
1181 .arg(
config_->getThisServerName());
1189 .arg(
config_->getThisServerName());
1209 size_t sent_num = 0;
1212 for (
auto const& p : peers_configs) {
1220 for (
auto const& l : *deleted_leases) {
1225 for (
auto const& l : *leases) {
1247 for (
auto const& l : *deleted_leases) {
1253 for (
auto const& l : *leases) {
1274 leases->push_back(lease);
1289 size_t sent_num = 0;
1292 for (
auto const& p : peers_configs) {
1299 for (
auto const& l : *deleted_leases) {
1304 for (
auto const& l : *leases) {
1340template<
typename QueryPtrType>
1345 std::lock_guard<std::mutex> lock(mutex_);
1346 return (leaseUpdateCompleteInternal(query, parking_lot));
1348 return (leaseUpdateCompleteInternal(query, parking_lot));
1352template<
typename QueryPtrType>
1354HAService::leaseUpdateCompleteInternal(QueryPtrType& query,
1356 auto it = pending_requests_.find(query);
1360 if (it == pending_requests_.end() || (--pending_requests_[query] <= 0)) {
1362 parking_lot->unpark(query);
1367 if (it != pending_requests_.end()) {
1368 pending_requests_.erase(it);
1375template<
typename QueryPtrType>
1379 std::lock_guard<std::mutex> lock(mutex_);
1380 updatePendingRequestInternal(query);
1382 updatePendingRequestInternal(query);
1386template<
typename QueryPtrType>
1388HAService::updatePendingRequestInternal(QueryPtrType& query) {
1389 if (pending_requests_.count(query) == 0) {
1390 pending_requests_[query] = 1;
1392 ++pending_requests_[query];
1396template<
typename QueryPtrType>
1406 config->addBasicAuthHttpHeader(request);
1407 request->setBodyAsJson(command);
1408 request->finalize();
1417 boost::weak_ptr<typename QueryPtrType::element_type> weak_query(query);
1420 client_->asyncSendRequest(config->getUrl(), config->getTlsContext(),
1422 [
this, weak_query, parking_lot, config]
1423 (
const boost::system::error_code& ec,
1425 const std::string& error_str) {
1429 QueryPtrType query = weak_query.lock();
1431 isc_throw(Unexpected,
"query is null while receiving response from"
1432 " HA peer. This is programmatic error");
1443 bool lease_update_success =
true;
1444 bool lease_update_conflict =
false;
1447 if (ec || !error_str.empty()) {
1448 LOG_WARN(ha_logger, HA_LEASE_UPDATE_COMMUNICATIONS_FAILED)
1449 .arg(config_->getThisServerName())
1450 .arg(query->getLabel())
1451 .arg(config->getLogLabel())
1452 .arg(ec ? ec.message() : error_str);
1456 lease_update_success = false;
1462 auto args = verifyAsyncResponse(response, rcode);
1465 logFailedLeaseUpdates(query, args);
1467 } catch (
const ConflictError& ex) {
1469 lease_update_conflict =
true;
1470 lease_update_success =
false;
1474 .arg(
config_->getThisServerName())
1475 .arg(query->getLabel())
1476 .arg(config->getLogLabel())
1479 }
catch (
const std::exception& ex) {
1482 .arg(
config_->getThisServerName())
1483 .arg(query->getLabel())
1484 .arg(config->getLogLabel())
1488 lease_update_success =
false;
1497 if (!lease_update_success) {
1500 if (!lease_update_conflict) {
1503 communication_state_->setPartnerUnavailable();
1508 communication_state_->reportSuccessfulLeaseUpdate(query);
1519 if (!lease_update_success) {
1521 parking_lot->drop(query);
1530 if (leaseUpdateComplete(query, parking_lot)) {
1536 runModel(HA_LEASE_UPDATES_COMPLETE_EVT);
1540 std::bind(&HAService::clientConnectHandler,
this, ph::_1, ph::_2),
1541 std::bind(&HAService::clientHandshakeHandler,
this, ph::_1),
1542 std::bind(&HAService::clientCloseHandler,
this, ph::_1)
1549 if (config_->amWaitingBackupAck() || (config->getRole() != HAConfig::PeerConfig::BACKUP)) {
1551 updatePendingRequest(query);
1558 if (!config_->amSendingLeaseUpdates()) {
1563 if (peer_config->getRole() == HAConfig::PeerConfig::BACKUP) {
1568 if (config_->getThisServerConfig()->getRole() == HAConfig::PeerConfig::BACKUP) {
1574 switch (getCurrState()) {
1589 if (!config_->amSendingLeaseUpdates()) {
1593 if (peer_config->getRole() == HAConfig::PeerConfig::BACKUP) {
1601HAService::logFailedLeaseUpdates(
const PktPtr& query,
1614 auto failed_leases = args->get(param_name);
1617 if (failed_leases && (failed_leases->getType() ==
Element::list)) {
1619 for (
int i = 0; i < failed_leases->size(); ++i) {
1620 auto lease = failed_leases->get(i);
1624 auto ip_address = lease->get(
"ip-address");
1627 auto lease_type = lease->get(
"type");
1630 auto error_message = lease->get(
"error-message");
1633 .arg(query->getLabel())
1635 lease_type->stringValue() :
"(unknown)")
1637 ip_address->stringValue() :
"(unknown)")
1639 error_message->stringValue() :
"(unknown)");
1653HAService::processStatusGet()
const {
1659 role = config_->getThisServerConfig()->getRole();
1660 std::string role_txt = HAConfig::PeerConfig::roleToString(role);
1662 int state = getCurrState();
1670 std::set<std::string> scopes = query_filter_.getServedScopes();
1672 for (
auto const& scope : scopes) {
1675 local->set(
"scopes", list);
1676 local->set(
"server-name",
Element::create(config_->getThisServerName()));
1677 ha_servers->set(
"local", local);
1681 if ((config_->getHAMode() == HAConfig::PASSIVE_BACKUP) ||
1682 (config_->getThisServerConfig()->getRole() == HAConfig::PeerConfig::BACKUP)) {
1683 return (ha_servers);
1687 ElementPtr remote = communication_state_->getReport();
1690 role = config_->getFailoverPeerConfig()->getRole();
1691 role_txt = HAConfig::PeerConfig::roleToString(role);
1697 remote->set(
"server-name",
Element::create(config_->getFailoverPeerConfig()->getName()));
1698 ha_servers->set(
"remote", remote);
1700 return (ha_servers);
1704HAService::processHeartbeat() {
1706 std::string state_label = getState(getCurrState())->getLabel();
1712 auto scopes = query_filter_.getServedScopes();
1714 for (
auto const& scope : scopes) {
1717 arguments->set(
"scopes", scopes_list);
1719 arguments->set(
"unsent-update-count",
1720 Element::create(
static_cast<int64_t
>(communication_state_->getUnsentUpdateCount())));
1727HAService::processHAReset() {
1737HAService::asyncSendHeartbeat() {
1747 bool sync_complete_notified = sync_complete_notified_;
1748 sync_complete_notified_ =
false;
1754 partner_config->addBasicAuthHttpHeader(request);
1755 request->setBodyAsJson(CommandCreator::createHeartbeat(config_->getThisServerName(),
1757 request->finalize();
1764 client_->asyncSendRequest(partner_config->getUrl(),
1765 partner_config->getTlsContext(),
1767 [
this, partner_config, sync_complete_notified]
1768 (
const boost::system::error_code& ec,
1770 const std::string& error_str) {
1778 bool heartbeat_success = true;
1781 if (ec || !error_str.empty()) {
1782 LOG_WARN(ha_logger, HA_HEARTBEAT_COMMUNICATIONS_FAILED)
1783 .arg(config_->getThisServerName())
1784 .arg(partner_config->getLogLabel())
1785 .arg(ec ? ec.message() : error_str);
1786 heartbeat_success = false;
1795 ConstElementPtr args = verifyAsyncResponse(response, rcode);
1796 if (!args || args->getType() != Element::map) {
1797 isc_throw(CtrlChannelError,
"returned arguments in the response"
1801 ConstElementPtr state = args->get(
"state");
1802 if (!state || state->getType() != Element::string) {
1803 isc_throw(CtrlChannelError,
"server state not returned in response"
1804 " to a ha-heartbeat command or it is not a string");
1808 communication_state_->setPartnerState(state->stringValue());
1810 ConstElementPtr date_time = args->get(
"date-time");
1811 if (!date_time || date_time->getType() != Element::string) {
1812 isc_throw(CtrlChannelError,
"date-time not returned in response"
1813 " to a ha-heartbeat command or it is not a string");
1816 communication_state_->setPartnerTime(date_time->stringValue());
1820 auto scopes = args->get(
"scopes");
1821 communication_state_->setPartnerScopes(scopes);
1836 auto unsent_update_count = args->get(
"unsent-update-count");
1837 if (unsent_update_count) {
1838 if (unsent_update_count->getType() != Element::integer) {
1839 isc_throw(CtrlChannelError,
"unsent-update-count returned in"
1840 " the ha-heartbeat response is not an integer");
1842 communication_state_->setPartnerUnsentUpdateCount(static_cast<uint64_t>
1843 (unsent_update_count->intValue()));
1846 } catch (
const std::exception& ex) {
1848 .arg(config_->getThisServerName())
1849 .arg(partner_config->getLogLabel())
1851 heartbeat_success =
false;
1857 if (heartbeat_success) {
1858 communication_state_->poke();
1863 communication_state_->setPartnerUnavailable();
1865 if (communication_state_->isCommunicationInterrupted()) {
1866 LOG_WARN(ha_logger, HA_COMMUNICATION_INTERRUPTED)
1867 .arg(config_->getThisServerName())
1868 .arg(partner_config->getName());
1876 if (sync_complete_notified && !heartbeat_success) {
1877 postNextEvent(HA_SYNCED_PARTNER_UNAVAILABLE_EVT);
1884 runModel(HA_HEARTBEAT_COMPLETE_EVT);
1887 std::bind(&HAService::clientConnectHandler,
this, ph::_1, ph::_2),
1888 std::bind(&HAService::clientHandshakeHandler,
this, ph::_1),
1889 std::bind(&HAService::clientCloseHandler,
this, ph::_1)
1894HAService::scheduleHeartbeat() {
1895 if (!communication_state_->isHeartbeatRunning()) {
1901HAService::startHeartbeat() {
1902 if (config_->getHeartbeatDelay() > 0) {
1903 communication_state_->startHeartbeat(config_->getHeartbeatDelay(),
1904 std::bind(&HAService::asyncSendHeartbeat,
1912 const unsigned int max_period,
1919 remote_config->addBasicAuthHttpHeader(request);
1920 request->setBodyAsJson(CommandCreator::createDHCPDisable(getRemoteOrigin(),
1923 request->finalize();
1931 remote_config->getTlsContext(),
1933 [
this, remote_config, post_request_action]
1934 (
const boost::system::error_code& ec,
1936 const std::string& error_str) {
1945 std::string error_message;
1948 if (ec || !error_str.empty()) {
1949 error_message = (ec ? ec.message() : error_str);
1950 LOG_ERROR(ha_logger, HA_DHCP_DISABLE_COMMUNICATIONS_FAILED)
1951 .arg(config_->getThisServerName())
1952 .arg(remote_config->getLogLabel())
1953 .arg(error_message);
1959 static_cast<void>(verifyAsyncResponse(response, rcode));
1961 } catch (
const std::exception& ex) {
1962 error_message = ex.what();
1964 .arg(config_->getThisServerName())
1965 .arg(remote_config->getLogLabel())
1966 .arg(error_message);
1972 if (!error_message.empty()) {
1973 communication_state_->setPartnerUnavailable();
1977 if (post_request_action) {
1978 post_request_action(error_message.empty(),
1984 std::bind(&HAService::clientConnectHandler,
this, ph::_1, ph::_2),
1985 std::bind(&HAService::clientHandshakeHandler,
this, ph::_1),
1986 std::bind(&HAService::clientCloseHandler,
this, ph::_1)
1998 remote_config->addBasicAuthHttpHeader(request);
1999 request->setBodyAsJson(CommandCreator::createDHCPEnable(getRemoteOrigin(),
2001 request->finalize();
2009 remote_config->getTlsContext(),
2011 [
this, remote_config, post_request_action]
2012 (
const boost::system::error_code& ec,
2014 const std::string& error_str) {
2023 std::string error_message;
2026 if (ec || !error_str.empty()) {
2027 error_message = (ec ? ec.message() : error_str);
2028 LOG_ERROR(ha_logger, HA_DHCP_ENABLE_COMMUNICATIONS_FAILED)
2029 .arg(config_->getThisServerName())
2030 .arg(remote_config->getLogLabel())
2031 .arg(error_message);
2037 static_cast<void>(verifyAsyncResponse(response, rcode));
2039 } catch (
const std::exception& ex) {
2040 error_message = ex.what();
2042 .arg(config_->getThisServerName())
2043 .arg(remote_config->getLogLabel())
2044 .arg(error_message);
2050 if (!error_message.empty()) {
2051 communication_state_->setPartnerUnavailable();
2055 if (post_request_action) {
2056 post_request_action(error_message.empty(),
2062 std::bind(&HAService::clientConnectHandler,
this, ph::_1, ph::_2),
2063 std::bind(&HAService::clientHandshakeHandler,
this, ph::_1),
2064 std::bind(&HAService::clientCloseHandler,
this, ph::_1)
2069HAService::localDisableDHCPService() {
2070 network_state_->disableService(getLocalOrigin());
2074HAService::localEnableDHCPService() {
2075 network_state_->enableService(getLocalOrigin());
2079HAService::asyncSyncLeases() {
2083 unsigned int dhcp_disable_timeout =
2084 static_cast<unsigned int>(config_->getSyncTimeout() / 1000);
2085 if (dhcp_disable_timeout == 0) {
2087 dhcp_disable_timeout = 1;
2090 lease_sync_filter_.apply();
2091 asyncSyncLeases(*client_, config_->getFailoverPeerConfig(),
2092 dhcp_disable_timeout,
LeasePtr(), null_action);
2098 const unsigned int max_period,
2101 const bool dhcp_disabled) {
2107 asyncDisableDHCPService(http_client, remote_config, max_period,
2108 [
this, &http_client, remote_config, max_period, last_lease,
2109 post_sync_action, dhcp_disabled]
2110 (
const bool success,
const std::string& error_message,
const int) {
2117 asyncSyncLeasesInternal(http_client, remote_config, max_period,
2118 last_lease, post_sync_action,
true);
2121 post_sync_action(success, error_message, dhcp_disabled);
2129 const unsigned int max_period,
2132 const bool dhcp_disabled) {
2137 remote_config->addBasicAuthHttpHeader(request);
2138 if (server_type_ == HAServerType::DHCPv4) {
2139 request->setBodyAsJson(CommandCreator::createLease4GetPage(
2140 boost::dynamic_pointer_cast<Lease4>(last_lease), config_->getSyncPageLimit()));
2143 request->setBodyAsJson(CommandCreator::createLease6GetPage(
2144 boost::dynamic_pointer_cast<Lease6>(last_lease), config_->getSyncPageLimit()));
2146 request->finalize();
2154 remote_config->getTlsContext(),
2156 [
this, remote_config, post_sync_action, &http_client, max_period, dhcp_disabled]
2157 (
const boost::system::error_code& ec,
2159 const std::string& error_str) {
2163 LeasePtr last_lease;
2171 std::string error_message;
2174 if (ec || !error_str.empty()) {
2175 error_message = (ec ? ec.message() : error_str);
2176 LOG_ERROR(ha_logger, HA_LEASES_SYNC_COMMUNICATIONS_FAILED)
2177 .arg(config_->getThisServerName())
2178 .arg(remote_config->getLogLabel())
2179 .arg(error_message);
2185 ConstElementPtr args = verifyAsyncResponse(response, rcode);
2188 if (args && (args->getType() != Element::map)) {
2189 isc_throw(CtrlChannelError,
2190 "arguments in the received response must be a map");
2193 ConstElementPtr leases = args->get(
"leases");
2194 if (!leases || (leases->getType() != Element::list)) {
2195 isc_throw(CtrlChannelError,
2196 "server response does not contain leases argument or this"
2197 " argument is not a list");
2201 auto const& leases_element = leases->listValue();
2203 LOG_INFO(ha_logger, HA_LEASES_SYNC_LEASE_PAGE_RECEIVED)
2204 .arg(config_->getThisServerName())
2205 .arg(leases_element.size())
2206 .arg(remote_config->getLogLabel());
2209 uint64_t applied_lease_count = 0;
2210 for (auto l = leases_element.begin(); l != leases_element.end(); ++l) {
2213 if (server_type_ == HAServerType::DHCPv4) {
2214 Lease4Ptr lease = Lease4::fromElement(*l);
2219 if ((leases_element.size() >= config_->getSyncPageLimit()) &&
2220 (l + 1 == leases_element.end())) {
2221 last_lease = boost::dynamic_pointer_cast<Lease>(lease);
2224 if (!lease_sync_filter_.shouldSync(lease)) {
2229 Lease4Ptr existing_lease = LeaseMgrFactory::instance().getLease4(lease->addr_);
2230 if (!existing_lease) {
2232 LeaseMgrFactory::instance().addLease(lease);
2233 ++applied_lease_count;
2235 } else if (existing_lease->cltt_ < lease->cltt_) {
2241 Lease::syncCurrentExpirationTime(*existing_lease, *lease);
2242 LeaseMgrFactory::instance().updateLease4(lease);
2243 ++applied_lease_count;
2246 LOG_DEBUG(ha_logger, DBGLVL_TRACE_BASIC, HA_LEASE_SYNC_STALE_LEASE4_SKIP)
2247 .arg(config_->getThisServerName())
2248 .arg(lease->addr_.toText())
2249 .arg(lease->subnet_id_);
2253 Lease6Ptr lease = Lease6::fromElement(*l);
2258 if ((leases_element.size() >= config_->getSyncPageLimit()) &&
2259 (l + 1 == leases_element.end())) {
2260 last_lease = boost::dynamic_pointer_cast<Lease>(lease);
2263 if (!lease_sync_filter_.shouldSync(lease)) {
2268 Lease6Ptr existing_lease = LeaseMgrFactory::instance().getLease6(lease->type_,
2270 if (!existing_lease) {
2272 LeaseMgrFactory::instance().addLease(lease);
2273 ++applied_lease_count;
2275 } else if (existing_lease->cltt_ < lease->cltt_) {
2281 Lease::syncCurrentExpirationTime(*existing_lease, *lease);
2282 LeaseMgrFactory::instance().updateLease6(lease);
2283 ++applied_lease_count;
2286 LOG_DEBUG(ha_logger, DBGLVL_TRACE_BASIC, HA_LEASE_SYNC_STALE_LEASE6_SKIP)
2287 .arg(config_->getThisServerName())
2288 .arg(lease->addr_.toText())
2289 .arg(lease->subnet_id_);
2293 } catch (const std::exception& ex) {
2294 LOG_WARN(ha_logger, HA_LEASE_SYNC_FAILED)
2295 .arg(config_->getThisServerName())
2301 LOG_INFO(ha_logger, HA_LEASES_SYNC_APPLIED_LEASES)
2302 .arg(config_->getThisServerName())
2303 .arg(applied_lease_count);
2305 } catch (
const std::exception& ex) {
2306 error_message = ex.what();
2308 .arg(config_->getThisServerName())
2309 .arg(remote_config->getLogLabel())
2310 .arg(error_message);
2316 if (!error_message.empty()) {
2317 communication_state_->setPartnerUnavailable();
2319 }
else if (last_lease) {
2322 asyncSyncLeases(http_client, remote_config, max_period, last_lease,
2323 post_sync_action, dhcp_disabled);
2328 if (post_sync_action) {
2329 post_sync_action(error_message.empty(),
2335 std::bind(&HAService::clientConnectHandler,
this, ph::_1, ph::_2),
2336 std::bind(&HAService::clientHandshakeHandler,
this, ph::_1),
2337 std::bind(&HAService::clientCloseHandler,
this, ph::_1)
2343HAService::processSynchronize(
const std::string& server_name,
2344 const unsigned int max_period) {
2347 remote_config = config_->getPeerConfig(server_name);
2348 }
catch (
const std::exception& ex) {
2352 if (remote_config->getName() == config_->getThisServerName()) {
2354 +
"' points to local server but should point to a partner"));
2356 std::string answer_message;
2357 int sync_status = synchronize(answer_message, remote_config, max_period);
2362HAService::synchronize(std::string& status_message,
2364 const unsigned int max_period) {
2365 lease_sync_filter_.apply();
2370 asyncSyncLeases(client, remote_config, max_period,
Lease4Ptr(),
2371 [&](
const bool success,
const std::string& error_message,
2372 const bool dhcp_disabled) {
2377 status_message = error_message;
2383 if (dhcp_disabled) {
2388 asyncSyncCompleteNotify(client, remote_config,
2389 [&](
const bool success,
2390 const std::string& error_message,
2396 asyncEnableDHCPService(client, remote_config,
2397 [&](
const bool success,
2398 const std::string& error_message,
2403 if (!success && status_message.empty()) {
2404 status_message = error_message;
2416 if (!success && status_message.empty()) {
2417 status_message = error_message;
2429 asyncEnableDHCPService(client, remote_config,
2430 [&](
const bool success,
2431 const std::string& error_message,
2433 if (!success && status_message.empty()) {
2434 status_message = error_message;
2453 .arg(config_->getThisServerName())
2454 .arg(remote_config->getLogLabel());
2468 io_service->stopAndPoll();
2472 if (!status_message.empty()) {
2473 postNextEvent(HA_SYNCING_FAILED_EVT);
2476 .arg(config_->getThisServerName())
2477 .arg(remote_config->getLogLabel())
2478 .arg(status_message);
2485 status_message =
"Lease database synchronization complete.";
2486 postNextEvent(HA_SYNCING_SUCCEEDED_EVT);
2489 .arg(config_->getThisServerName())
2490 .arg(remote_config->getLogLabel())
2497HAService::asyncSendLeaseUpdatesFromBacklog(
HttpClient& http_client,
2500 if (lease_update_backlog_.size() == 0) {
2506 if (server_type_ == HAServerType::DHCPv4) {
2508 Lease4Ptr lease = boost::dynamic_pointer_cast<Lease4>(lease_update_backlog_.pop(op_type));
2509 if (op_type == LeaseUpdateBacklog::ADD) {
2510 command = CommandCreator::createLease4Update(*lease);
2512 command = CommandCreator::createLease4Delete(*lease);
2516 command = CommandCreator::createLease6BulkApply(lease_update_backlog_);
2523 config->addBasicAuthHttpHeader(request);
2524 request->setBodyAsJson(command);
2525 request->finalize();
2533 [
this, &http_client, config, post_request_action]
2534 (
const boost::system::error_code& ec,
2536 const std::string& error_str) {
2539 std::string error_message;
2541 if (ec || !error_str.empty()) {
2542 error_message = (ec ? ec.message() : error_str);
2543 LOG_WARN(ha_logger, HA_LEASES_BACKLOG_COMMUNICATIONS_FAILED)
2544 .arg(config_->getThisServerName())
2545 .arg(config->getLogLabel())
2546 .arg(ec ? ec.message() : error_str);
2551 auto args = verifyAsyncResponse(response, rcode);
2552 } catch (
const std::exception& ex) {
2553 error_message = ex.what();
2555 .arg(config_->getThisServerName())
2556 .arg(config->getLogLabel())
2566 if (error_message.empty()) {
2567 asyncSendLeaseUpdatesFromBacklog(http_client, config, post_request_action);
2569 post_request_action(error_message.empty(), error_message, rcode);
2575HAService::sendLeaseUpdatesFromBacklog() {
2576 auto num_updates = lease_update_backlog_.size();
2577 if (num_updates == 0) {
2579 .arg(config_->getThisServerName());
2585 auto remote_config = config_->getFailoverPeerConfig();
2586 bool updates_successful =
true;
2589 .arg(config_->getThisServerName())
2591 .arg(remote_config->getName());
2593 asyncSendLeaseUpdatesFromBacklog(client, remote_config,
2594 [&](
const bool success,
const std::string&,
const int) {
2596 updates_successful = success;
2610 io_service->stopAndPoll();
2612 if (updates_successful) {
2614 .arg(config_->getThisServerName())
2615 .arg(remote_config->getName())
2616 .arg(stopwatch.logFormatLastDuration());
2619 return (updates_successful);
2626 ConstElementPtr command = CommandCreator::createHAReset(config_->getThisServerName(),
2633 config->addBasicAuthHttpHeader(request);
2634 request->setBodyAsJson(command);
2635 request->finalize();
2643 [
this, config, post_request_action]
2644 (
const boost::system::error_code& ec,
2646 const std::string& error_str) {
2649 std::string error_message;
2651 if (ec || !error_str.empty()) {
2652 error_message = (ec ? ec.message() : error_str);
2653 LOG_WARN(ha_logger, HA_RESET_COMMUNICATIONS_FAILED)
2654 .arg(config_->getThisServerName())
2655 .arg(config->getLogLabel())
2656 .arg(ec ? ec.message() : error_str);
2661 auto args = verifyAsyncResponse(response, rcode);
2662 } catch (
const std::exception& ex) {
2663 error_message = ex.what();
2665 .arg(config_->getThisServerName())
2666 .arg(config->getLogLabel())
2671 post_request_action(error_message.empty(), error_message, rcode);
2676HAService::sendHAReset() {
2679 auto remote_config = config_->getFailoverPeerConfig();
2680 bool reset_successful =
true;
2682 asyncSendHAReset(client, remote_config,
2683 [&](
const bool success,
const std::string&,
const int) {
2685 reset_successful = success;
2693 io_service->stopAndPoll();
2695 return (reset_successful);
2699HAService::processScopes(
const std::vector<std::string>& scopes) {
2701 query_filter_.serveScopes(scopes);
2702 adjustNetworkState();
2704 }
catch (
const std::exception& ex) {
2712HAService::processContinue() {
2720HAService::processMaintenanceNotify(
const bool cancel) {
2724 " maintenance for the server not in the"
2725 " in-maintenance state."));
2728 postNextEvent(HA_MAINTENANCE_CANCEL_EVT);
2729 verboseTransition(getPrevState());
2734 switch (getCurrState()) {
2744 return (
createAnswer(HA_CONTROL_RESULT_MAINTENANCE_NOT_ALLOWED,
2745 "Unable to transition the server from the "
2747 " in-maintenance state."));
2750 runModel(HA_MAINTENANCE_NOTIFY_EVT);
2756HAService::processMaintenanceStart() {
2757 switch (getCurrState()) {
2764 " partner-in-maintenance state."));
2776 remote_config->addBasicAuthHttpHeader(request);
2777 request->setBodyAsJson(CommandCreator::createMaintenanceNotify(config_->getThisServerName(),
2778 false, server_type_));
2779 request->finalize();
2788 boost::system::error_code captured_ec;
2789 std::string captured_error_message;
2790 int captured_rcode = 0;
2794 remote_config->getTlsContext(),
2796 [
this, remote_config, &io_service, &captured_ec, &captured_error_message,
2798 (
const boost::system::error_code& ec,
2800 const std::string& error_str) {
2810 std::string error_message;
2813 if (ec || !error_str.empty()) {
2814 error_message = (ec ? ec.message() : error_str);
2815 LOG_ERROR(ha_logger, HA_MAINTENANCE_NOTIFY_COMMUNICATIONS_FAILED)
2816 .arg(config_->getThisServerName())
2817 .arg(remote_config->getLogLabel())
2818 .arg(error_message);
2824 static_cast<void>(verifyAsyncResponse(response, captured_rcode));
2826 } catch (
const std::exception& ex) {
2827 error_message = ex.what();
2829 .arg(config_->getThisServerName())
2830 .arg(remote_config->getLogLabel())
2831 .arg(error_message);
2837 if (!error_message.empty()) {
2838 communication_state_->setPartnerUnavailable();
2842 captured_error_message = error_message;
2845 std::bind(&HAService::clientConnectHandler,
this, ph::_1, ph::_2),
2846 std::bind(&HAService::clientHandshakeHandler,
this, ph::_1),
2847 std::bind(&HAService::clientCloseHandler,
this, ph::_1)
2856 io_service->stopAndPoll();
2861 postNextEvent(HA_MAINTENANCE_START_EVT);
2862 verboseTransition(HA_PARTNER_DOWN_ST);
2865 "Server is now in the partner-down state as its"
2866 " partner appears to be offline for maintenance."));
2872 postNextEvent(HA_MAINTENANCE_START_EVT);
2873 verboseTransition(HA_PARTNER_IN_MAINTENANCE_ST);
2880 " partner-in-maintenance state. The partner server responded"
2881 " with the following message to the ha-maintenance-notify"
2882 " command: " + captured_error_message +
"."));
2887 "Server is now in the partner-in-maintenance state"
2888 " and its partner is in-maintenance state. The partner"
2889 " can be now safely shut down."));
2893HAService::processMaintenanceCancel() {
2896 " request because the server is not in the"
2897 " partner-in-maintenance state."));
2907 remote_config->addBasicAuthHttpHeader(request);
2908 request->setBodyAsJson(CommandCreator::createMaintenanceNotify(config_->getThisServerName(),
2909 true, server_type_));
2910 request->finalize();
2919 std::string error_message;
2923 remote_config->getTlsContext(),
2925 [
this, remote_config, &io_service, &error_message]
2926 (
const boost::system::error_code& ec,
2928 const std::string& error_str) {
2933 if (ec || !error_str.empty()) {
2934 error_message = (ec ? ec.message() : error_str);
2935 LOG_ERROR(ha_logger, HA_MAINTENANCE_NOTIFY_CANCEL_COMMUNICATIONS_FAILED)
2936 .arg(config_->getThisServerName())
2937 .arg(remote_config->getLogLabel())
2938 .arg(error_message);
2945 static_cast<void>(verifyAsyncResponse(response, rcode));
2947 } catch (
const std::exception& ex) {
2948 error_message = ex.what();
2950 .arg(config_->getThisServerName())
2951 .arg(remote_config->getLogLabel())
2952 .arg(error_message);
2958 if (!error_message.empty()) {
2959 communication_state_->setPartnerUnavailable();
2963 std::bind(&HAService::clientConnectHandler,
this, ph::_1, ph::_2),
2964 std::bind(&HAService::clientHandshakeHandler,
this, ph::_1),
2965 std::bind(&HAService::clientCloseHandler,
this, ph::_1)
2974 io_service->stopAndPoll();
2978 if (!error_message.empty()) {
2980 "Unable to cancel maintenance. The partner server responded"
2981 " with the following message to the ha-maintenance-notify"
2982 " command: " + error_message +
"."));
2987 postNextEvent(HA_MAINTENANCE_CANCEL_EVT);
2988 verboseTransition(getPrevState());
2992 "Server maintenance successfully canceled."));
3004 remote_config->addBasicAuthHttpHeader(request);
3005 request->setBodyAsJson(CommandCreator::createSyncCompleteNotify(getRemoteOrigin(),
3006 config_->getThisServerName(),
3008 request->finalize();
3016 remote_config->getTlsContext(),
3018 [
this, remote_config, post_request_action]
3019 (
const boost::system::error_code& ec,
3021 const std::string& error_str) {
3030 std::string error_message;
3033 if (ec || !error_str.empty()) {
3034 error_message = (ec ? ec.message() : error_str);
3035 LOG_ERROR(ha_logger, HA_SYNC_COMPLETE_NOTIFY_COMMUNICATIONS_FAILED)
3036 .arg(config_->getThisServerName())
3037 .arg(remote_config->getLogLabel())
3038 .arg(error_message);
3044 static_cast<void>(verifyAsyncResponse(response, rcode));
3046 } catch (
const CommandUnsupportedError& ex) {
3049 }
catch (
const std::exception& ex) {
3050 error_message = ex.what();
3052 .arg(config_->getThisServerName())
3053 .arg(remote_config->getLogLabel())
3054 .arg(error_message);
3060 if (!error_message.empty()) {
3061 communication_state_->setPartnerUnavailable();
3065 if (post_request_action) {
3066 post_request_action(error_message.empty(),
3072 std::bind(&HAService::clientConnectHandler,
this, ph::_1, ph::_2),
3073 std::bind(&HAService::clientHandshakeHandler,
this, ph::_1),
3074 std::bind(&HAService::clientCloseHandler,
this, ph::_1)
3079HAService::processSyncCompleteNotify(
const unsigned int origin_id) {
3081 sync_complete_notified_ =
true;
3089 network_state_->disableService(getLocalOrigin());
3094 network_state_->enableService(origin_id);
3096 "Server successfully notified about the synchronization completion."));
3105 boost::dynamic_pointer_cast<HttpResponseJson>(response);
3106 if (!json_response) {
3135 if (body->empty()) {
3146 std::ostringstream s;
3155 s << args->stringValue() <<
" (";
3158 s <<
"error code " << rcode <<
")";
3163 isc_throw(CommandUnsupportedError, s.str());
3171 auto failed_leases = args->get(
"failed-leases");
3172 if (!failed_leases || (failed_leases->getType() !=
Element::list)) {
3176 auto conflict =
false;
3178 for (
auto i = 0; i < failed_leases->size(); ++i) {
3179 auto lease = failed_leases->get(i);
3183 auto result = lease->get(
"result");
3187 auto error_message = lease->get(
"error-message");
3190 if (error_message && error_message->getType()) {
3191 s << error_message->stringValue() <<
" (";
3193 s <<
"error code " << result->intValue() <<
")";
3201 conflict_error_message = error_message;
3207 if (conflict_error_message &&
3209 s << conflict_error_message->stringValue() <<
" (";
3223HAService::clientConnectHandler(
const boost::system::error_code& ec,
int tcp_native_fd) {
3227 if (client_->getThreadIOService()) {
3235 if ((!ec || (ec.value() == boost::asio::error::in_progress))
3236 && (tcp_native_fd >= 0)) {
3242 std::bind(&HAService::socketReadyHandler,
this, ph::_1)
3254HAService::socketReadyHandler(
int tcp_native_fd) {
3259 client_->closeIfOutOfBand(tcp_native_fd);
3263HAService::clientCloseHandler(
int tcp_native_fd) {
3264 if (tcp_native_fd >= 0) {
3270HAService::pendingRequestSize() {
3272 std::lock_guard<std::mutex> lock(mutex_);
3273 return (pending_requests_.size());
3275 return (pending_requests_.size());
3279template<
typename QueryPtrType>
3281HAService::getPendingRequest(
const QueryPtrType& query) {
3283 std::lock_guard<std::mutex> lock(mutex_);
3284 return (getPendingRequestInternal(query));
3286 return (getPendingRequestInternal(query));
3290template<
typename QueryPtrType>
3292HAService::getPendingRequestInternal(
const QueryPtrType& query) {
3293 if (pending_requests_.count(query) == 0) {
3296 return (pending_requests_[query]);
3301HAService::checkPermissionsClientAndListener() {
3309 client_->checkPermissions();
3313 listener_->checkPermissions();
3317 .arg(config_->getThisServerName())
3322 }
catch (
const std::exception& ex) {
3324 .arg(config_->getThisServerName())
3330HAService::startClientAndListener() {
3333 std::bind(&HAService::checkPermissionsClientAndListener,
this),
3334 std::bind(&HAService::pauseClientAndListener,
this),
3335 std::bind(&HAService::resumeClientAndListener,
this));
3347HAService::pauseClientAndListener() {
3358 }
catch (
const std::exception& ex) {
3365HAService::resumeClientAndListener() {
3374 listener_->resume();
3376 }
catch (std::exception& ex) {
3378 .arg(config_->getThisServerName())
3384HAService::stopClientAndListener() {
3398template int HAService::getPendingRequest(
const Pkt4Ptr&);
3399template int HAService::getPendingRequest(
const Pkt6Ptr&);
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
Exception thrown when a worker thread is trying to stop or pause the respective thread pool (which wo...
A generic exception that is thrown when an unexpected error condition occurs.
The IOAddress class represents an IP addresses (version agnostic)
static const IOAddress & IPV4_ZERO_ADDRESS()
Returns an address set to all zeros.
The IOService class is a wrapper for the ASIO io_service class.
A multi-threaded HTTP listener that can process API commands requests.
static std::unordered_set< std::string > command_accept_list_
The server command accept list.
A standard control channel exception that is thrown if a function is there is a problem with one of t...
static ElementPtr create(const Position &pos=ZERO_POSITION())
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
void deleteExternalSocket(int socketfd)
Deletes external socket.
static IfaceMgr & instance()
IfaceMgr is a singleton class.
void addExternalSocket(int socketfd, SocketCallback callback)
Adds external socket and a callback.
static data::ConstElementPtr createLease4Delete(const dhcp::Lease4 &lease4)
Creates lease4-del command.
static std::unordered_set< std::string > ha_commands4_
List of commands used by the High Availability in v4.
static data::ConstElementPtr createLease4Update(const dhcp::Lease4 &lease4)
Creates lease4-update command.
static data::ConstElementPtr createLease6BulkApply(const dhcp::Lease6CollectionPtr &leases, const dhcp::Lease6CollectionPtr &deleted_leases)
Creates lease6-bulk-apply command.
static std::unordered_set< std::string > ha_commands6_
List of commands used by the High Availability in v6.
Holds communication state between DHCPv4 servers.
Holds communication state between DHCPv6 servers.
Role
Server's role in the High Availability setup.
static std::string roleToString(const HAConfig::PeerConfig::Role &role)
Returns role name.
std::map< std::string, PeerConfigPtr > PeerConfigMap
Map of the servers' configurations.
static std::string HAModeToString(const HAMode &ha_mode)
Returns HA mode name.
boost::shared_ptr< PeerConfig > PeerConfigPtr
Pointer to the server's configuration.
static const int HA_MAINTENANCE_START_EVT
ha-maintenance-start command received.
bool inScope(dhcp::Pkt4Ptr &query4)
Checks if the DHCPv4 query should be processed by this server.
void adjustNetworkState()
Enables or disables network state depending on the served scopes.
void stopClientAndListener()
Stop the client and(or) listener instances.
int getNormalState() const
Returns normal operation state for the current configuration.
bool shouldQueueLeaseUpdates(const HAConfig::PeerConfigPtr &peer_config) const
Checks if the lease updates should be queued.
static const int HA_HEARTBEAT_COMPLETE_EVT
Finished heartbeat command.
bool isMaintenanceCanceled() const
Convenience method checking if the current state is a result of canceling the maintenance.
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.
void verboseTransition(const unsigned state)
Transitions to a desired state and logs it.
bool sendLeaseUpdatesFromBacklog()
Attempts to send all lease updates from the backlog synchronously.
config::CmdHttpListenerPtr listener_
HTTP listener instance used to receive and respond to HA commands and lease updates.
bool leaseUpdateComplete(QueryPtrType &query, const hooks::ParkingLotHandlePtr &parking_lot)
Handle last pending request for this query.
HAConfigPtr config_
Pointer to the HA hooks library configuration.
unsigned int id_
Unique service id.
bool shouldTerminate() const
Indicates if the server should transition to the terminated state.
dhcp::NetworkStatePtr network_state_
Pointer to the state of the DHCP service (enabled/disabled).
void scheduleHeartbeat()
Schedules asynchronous heartbeat to a peer if it is not scheduled.
QueryFilter query_filter_
Selects queries to be processed/dropped.
static const int HA_MAINTENANCE_NOTIFY_EVT
ha-maintenance-notify command received.
static const int HA_SYNCED_PARTNER_UNAVAILABLE_EVT
The heartbeat command failed after receiving ha-sync-complete-notify command from the partner.
void conditionalLogPausedState() const
Logs if the server is paused in the current state.
bool unpause()
Unpauses the HA state machine with logging.
static const int HA_CONTROL_RESULT_MAINTENANCE_NOT_ALLOWED
Control result returned in response to ha-maintenance-notify.
void serveDefaultScopes()
Instructs the HA service to serve default scopes.
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.
static const int HA_SYNCING_SUCCEEDED_EVT
Lease database synchronization succeeded.
bool sendHAReset()
Sends ha-reset command to partner synchronously.
std::function< void(const bool, const std::string &, const int)> PostRequestCallback
Callback invoked when request was sent and a response received or an error occurred.
asiolink::IOServicePtr io_service_
Pointer to the IO service object shared between this hooks library and the DHCP server.
CommunicationStatePtr communication_state_
Holds communication state with a peer.
LeaseUpdateBacklog lease_update_backlog_
Backlog of DHCP lease updates.
virtual ~HAService()
Destructor.
static const int HA_SYNCING_FAILED_EVT
Lease database synchronization failed.
static const int HA_MAINTENANCE_CANCEL_EVT
ha-maintenance-cancel command received.
size_t asyncSendSingleLeaseUpdate(const dhcp::Pkt4Ptr &query, const dhcp::Lease4Ptr &lease, const hooks::ParkingLotHandlePtr &parking_lot)
Schedules an asynchronous IPv4 lease update.
bool isPartnerStateInvalid() const
Indicates if the partner's state is invalid.
int synchronize(std::string &status_message, const HAConfig::PeerConfigPtr &remote_config, const unsigned int max_period)
Synchronizes lease database with a partner.
bool shouldSendLeaseUpdates(const HAConfig::PeerConfigPtr &peer_config) const
Checks if the lease updates should be sent as result of leases allocation or release.
void serveFailoverScopes()
Instructs the HA service to serve failover scopes.
static const int HA_LEASE_UPDATES_COMPLETE_EVT
Finished lease updates commands.
HAService(const unsigned int id, const asiolink::IOServicePtr &io_service, const dhcp::NetworkStatePtr &network_state, const HAConfigPtr &config, const HAServerType &server_type=HAServerType::DHCPv4)
Constructor.
http::HttpClientPtr client_
HTTP client instance used to send HA commands and lease updates.
void updatePendingRequest(QueryPtrType &query)
Update pending request counter for this query.
bool shouldPartnerDown() const
Indicates if the server should transition to the partner down state.
std::function< void(const bool, const std::string &, const bool)> PostSyncCallback
Callback invoked when lease database synchronization is complete.
static const int HA_WAITING_TO_TERMINATED_ST_DELAY_MINUTES
A delay in minutes to transition from the waiting to terminated state when the partner remains in ter...
bool push(const OpType op_type, const dhcp::LeasePtr &lease)
Appends lease update to the queue.
OpType
Type of the lease update (operation type).
void clear()
Removes all lease updates from the queue.
bool wasOverflown()
Checks if the queue was overflown.
bool inScope(const dhcp::Pkt4Ptr &query4, std::string &scope_class) const
Checks if this server should process the DHCPv4 query.
void serveFailoverScopes()
Enable scopes required in failover case.
void serveDefaultScopes()
Serve default scopes for the given HA mode.
void serveNoScopes()
Disables all scopes.
void stop()
Halts client-side IO activity.
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.
This class parses and generates time values used in HTTP.
std::string rfc1123Format() const
Returns time value formatted as specified in RFC 1123.
static MultiThreadingMgr & instance()
Returns a single instance of Multi Threading Manager.
void removeCriticalSectionCallbacks(const std::string &name)
Removes the set of callbacks associated with a given name from the list of CriticalSection callbacks.
void addCriticalSectionCallbacks(const std::string &name, const CSCallbackSet::Callback &check_cb, const CSCallbackSet::Callback &entry_cb, const CSCallbackSet::Callback &exit_cb)
Adds a set of callbacks to the list of CriticalSection callbacks.
const EventPtr & getEvent(unsigned int value)
Fetches the event referred to by value.
std::string getStateLabel(const int state) const
Fetches the label associated with an state value.
void unpauseModel()
Unpauses state model.
bool isModelPaused() const
Returns whether or not the model is paused.
virtual void defineEvents()
Populates the set of events.
void postNextEvent(unsigned int event)
Sets the next event to the given event value.
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.
bool doOnExit()
Checks if on exit flag is true.
unsigned int getNextEvent() const
Fetches the model's next event.
void defineEvent(unsigned int value, const std::string &label)
Adds an event value and associated label to the set of events.
void transition(unsigned int state, unsigned int event)
Sets up the model to transition into given state with a given event.
virtual void verifyEvents()
Validates the contents of the set of events.
bool doOnEntry()
Checks if on entry flag is true.
static const int NOP_EVT
Signifies that no event has occurred.
void startModel(const int start_state)
Begins execution of the model.
virtual void defineStates()
Populates the set of states.
unsigned int getLastEvent() const
Fetches the model's last event.
unsigned int getCurrState() const
Fetches the model's current state.
Utility class to measure code execution times.
void stop()
Stops the stopwatch.
std::string logFormatLastDuration() const
Returns the last measured duration in the format directly usable in log messages.
This file contains several functions and constants that are used for handling commands and responses ...
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
An abstract API for lease database.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
#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< IOService > IOServicePtr
Defines a smart pointer to an IOService instance.
const int CONTROL_RESULT_EMPTY
Status code indicating that the specified command was completed correctly, but failed to produce any ...
const char * CONTROL_TEXT
String used for storing textual description ("text")
constexpr long TIMEOUT_DEFAULT_HTTP_CLIENT_REQUEST
Timeout for the HTTP clients awaiting a response to a request.
const int CONTROL_RESULT_ERROR
Status code indicating a general failure.
ConstElementPtr createAnswer()
Creates a standard config/command level success answer message (i.e.
const int CONTROL_RESULT_CONFLICT
Status code indicating that the command was unsuccessful due to a conflict between the command argume...
const int CONTROL_RESULT_COMMAND_UNSUPPORTED
Status code indicating that the specified command is not supported.
ConstElementPtr parseAnswer(int &rcode, const ConstElementPtr &msg)
const char * CONTROL_RESULT
String used for result, i.e. integer status ("result")
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
boost::shared_ptr< const Element > ConstElementPtr
boost::shared_ptr< Element > ElementPtr
boost::shared_ptr< isc::dhcp::Pkt > PktPtr
A pointer to either Pkt4 or Pkt6 packet.
std::string ClientClass
Defines a single class name.
boost::shared_ptr< Lease4Collection > Lease4CollectionPtr
A shared pointer to the collection of IPv4 leases.
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
boost::shared_ptr< Lease > LeasePtr
Pointer to the lease object.
boost::shared_ptr< NetworkState > NetworkStatePtr
Pointer to the NetworkState object.
boost::shared_ptr< Lease6Collection > Lease6CollectionPtr
A shared pointer to the collection of IPv6 leases.
boost::shared_ptr< Pkt6 > Pkt6Ptr
A pointer to Pkt6 packet.
std::vector< Lease4Ptr > Lease4Collection
A collection of IPv4 leases.
boost::shared_ptr< Lease4 > Lease4Ptr
Pointer to a Lease4 structure.
const isc::log::MessageID HA_INVALID_PARTNER_STATE_LOAD_BALANCING
const isc::log::MessageID HA_RESUME_CLIENT_LISTENER_FAILED
const isc::log::MessageID HA_LOCAL_DHCP_ENABLE
const isc::log::MessageID HA_LEASES_BACKLOG_NOTHING_TO_SEND
const isc::log::MessageID HA_LEASES_BACKLOG_FAILED
const isc::log::MessageID HA_SYNC_FAILED
const isc::log::MessageID HA_TERMINATED_RESTART_PARTNER
const int HA_PASSIVE_BACKUP_ST
In passive-backup state with a single active server and backup servers.
const int HA_HOT_STANDBY_ST
Hot standby state.
const isc::log::MessageID HA_INVALID_PARTNER_STATE_COMMUNICATION_RECOVERY
const isc::log::MessageID HA_LEASES_BACKLOG_SUCCESS
const int HA_COMMUNICATION_RECOVERY_ST
Communication recovery state.
const isc::log::MessageID HA_STATE_MACHINE_CONTINUED
isc::log::Logger ha_logger("ha-hooks")
const isc::log::MessageID HA_LEASES_SYNC_FAILED
const isc::log::MessageID HA_SYNC_SUCCESSFUL
const int HA_UNAVAILABLE_ST
Special state indicating that this server is unable to communicate with the partner.
const isc::log::MessageID HA_CONFIG_LEASE_UPDATES_DISABLED_REMINDER
const isc::log::MessageID HA_SERVICE_STARTED
const int HA_TERMINATED_ST
HA service terminated state.
const int HA_IN_MAINTENANCE_ST
In maintenance state.
const int HA_LOAD_BALANCING_ST
Load balancing state.
const isc::log::MessageID HA_DHCP_ENABLE_FAILED
const isc::log::MessageID HA_LEASE_UPDATE_DELETE_FAILED_ON_PEER
const isc::log::MessageID HA_LEASES_BACKLOG_START
const isc::log::MessageID HA_SYNC_START
const isc::log::MessageID HA_HEARTBEAT_FAILED
const int HA_PARTNER_DOWN_ST
Partner down state.
const isc::log::MessageID HA_LEASE_UPDATES_ENABLED
const isc::log::MessageID HA_INVALID_PARTNER_STATE_HOT_STANDBY
const isc::log::MessageID HA_STATE_MACHINE_PAUSED
const isc::log::MessageID HA_TERMINATED
const isc::log::MessageID HA_DHCP_DISABLE_FAILED
boost::shared_ptr< HAConfig > HAConfigPtr
Pointer to the High Availability configuration structure.
const isc::log::MessageID HA_MAINTENANCE_STARTED_IN_PARTNER_DOWN
const int HA_PARTNER_IN_MAINTENANCE_ST
Partner in-maintenance state.
const isc::log::MessageID HA_MAINTENANCE_NOTIFY_FAILED
const int HA_WAITING_ST
Server waiting state, i.e. waiting for another server to be ready.
HAServerType
Lists possible server types for which HA service is created.
const int HA_BACKUP_ST
Backup state.
const isc::log::MessageID HA_PAUSE_CLIENT_LISTENER_ILLEGAL
const isc::log::MessageID HA_PAUSE_CLIENT_LISTENER_FAILED
const isc::log::MessageID HA_MAINTENANCE_SHUTDOWN_SAFE
const isc::log::MessageID HA_MAINTENANCE_NOTIFY_CANCEL_FAILED
const isc::log::MessageID HA_LEASE_UPDATE_CONFLICT
const isc::log::MessageID HA_LEASE_UPDATES_DISABLED
const isc::log::MessageID HA_LOCAL_DHCP_DISABLE
const int HA_SYNCING_ST
Synchronizing database state.
const isc::log::MessageID HA_RESET_FAILED
const isc::log::MessageID HA_STATE_TRANSITION
const isc::log::MessageID HA_CONFIG_LEASE_SYNCING_DISABLED_REMINDER
std::string stateToString(int state)
Returns state name.
const int HA_READY_ST
Server ready state, i.e. synchronized database, can enable DHCP service.
const isc::log::MessageID HA_TERMINATED_PARTNER_DID_NOT_RESTART
const isc::log::MessageID HA_SYNC_COMPLETE_NOTIFY_FAILED
const isc::log::MessageID HA_MAINTENANCE_STARTED
const isc::log::MessageID HA_LEASE_UPDATE_CREATE_UPDATE_FAILED_ON_PEER
const isc::log::MessageID HA_LEASE_UPDATE_FAILED
const isc::log::MessageID HA_STATE_TRANSITION_PASSIVE_BACKUP
boost::shared_ptr< ParkingLotHandle > ParkingLotHandlePtr
Pointer to the parking lot handle.
boost::shared_ptr< PostHttpRequestJson > PostHttpRequestJsonPtr
Pointer to PostHttpRequestJson.
boost::shared_ptr< HttpResponseJson > HttpResponseJsonPtr
Pointer to the HttpResponseJson object.
boost::shared_ptr< HttpResponse > HttpResponsePtr
Pointer to the HttpResponse object.
Defines the logger used by the top-level component of kea-lfc.
HTTP request/response timeout value.
static const HttpVersion & HTTP_11()
HTTP version 1.1.