28#include <boost/pointer_cast.hpp>
29#include <boost/make_shared.hpp>
30#include <boost/weak_ptr.hpp>
42namespace ph = std::placeholders;
49 CommandUnsupportedError(
const char* file,
size_t line,
const char* what) :
56 ConflictError(
const char* file,
size_t line,
const char* what) :
79 : id_(id), io_service_(io_service), network_state_(network_state), config_(config),
80 server_type_(server_type), client_(), listener_(), communication_state_(),
81 query_filter_(config), lease_sync_filter_(server_type, config), mutex_(),
82 pending_requests_(), lease_update_backlog_(config->getDelayedUpdatesLimit()),
83 sync_complete_notified_(false) {
97 if (!
config_->getEnableMultiThreading()) {
103 config_->getHttpClientThreads(),
true));
106 if (
config_->getHttpDedicatedListener()) {
108 auto my_url =
config_->getThisServerConfig()->getUrl();
113 server_address =
IOAddress(my_url.getStrippedHostname());
114 }
catch (
const std::exception& ex) {
116 <<
" is not a valid IP address");
120 uint32_t listener_threads =
config_->getHttpListenerThreads();
123 auto tls_context =
config_->getThisServerConfig()->getTlsContext();
127 listener_threads, tls_context));
129 if (
config_->getRestrictCommands()) {
142 .arg(
config_->getThisServerName())
155HAService::getCSCallbacksSetName()
const {
156 std::ostringstream s;
157 s <<
"HA_MT_" <<
id_;
162HAService::defineEvents() {
176HAService::verifyEvents() {
190HAService::defineStates() {
194 std::bind(&HAService::backupStateHandler,
this),
198 std::bind(&HAService::communicationRecoveryHandler,
this),
202 std::bind(&HAService::normalStateHandler,
this),
206 std::bind(&HAService::normalStateHandler,
this),
210 std::bind(&HAService::inMaintenanceStateHandler,
this),
214 std::bind(&HAService::partnerDownStateHandler,
this),
218 std::bind(&HAService::partnerInMaintenanceStateHandler,
this),
222 std::bind(&HAService::passiveBackupStateHandler,
this),
226 std::bind(&HAService::readyStateHandler,
this),
230 std::bind(&HAService::syncingStateHandler,
this),
234 std::bind(&HAService::terminatedStateHandler,
this),
238 std::bind(&HAService::waitingStateHandler,
this),
243HAService::backupStateHandler() {
258HAService::communicationRecoveryHandler() {
375HAService::normalStateHandler() {
430 }
else if (
config_->amAllowingCommRecovery()) {
450HAService::inMaintenanceStateHandler() {
464 .arg(
config_->getThisServerName());
476HAService::partnerDownStateHandler() {
490 if (maintenance ||
config_->getThisServerConfig()->isAutoFailover()) {
505 .arg(
config_->getThisServerName());
568HAService::partnerInMaintenanceStateHandler() {
581 .arg(
config_->getThisServerName());
608HAService::passiveBackupStateHandler() {
626HAService::readyStateHandler() {
706HAService::syncingStateHandler() {
766 unsigned int dhcp_disable_timeout =
767 static_cast<unsigned int>(
config_->getSyncTimeout() / 1000);
768 if (dhcp_disable_timeout == 0) {
769 ++dhcp_disable_timeout;
773 std::string status_message;
775 config_->getFailoverPeerConfig(),
776 dhcp_disable_timeout);
796HAService::terminatedStateHandler() {
812 .arg(
config_->getThisServerName());
819HAService::waitingStateHandler() {
891 if (!partner_in_terminated.is_not_a_date_time() &&
894 .arg(
config_->getThisServerName())
907 .arg(
config_->getThisServerName());
945 boost::to_upper(current_state_name);
946 boost::to_upper(new_state_name);
952 std::string partner_state_name =
getStateLabel(partner_state);
953 boost::to_upper(partner_state_name);
957 .arg(
config_->getThisServerName())
958 .arg(current_state_name)
960 .arg(partner_state_name);
965 .arg(
config_->getThisServerName())
966 .arg(current_state_name)
967 .arg(new_state_name);
976 .arg(
config_->getThisServerName());
989 .arg(
config_->getThisServerName())
990 .arg(new_state_name);
992 }
else if (!
config_->amSendingLeaseUpdates()) {
995 .arg(
config_->getThisServerName())
996 .arg(new_state_name);
1003 .arg(
config_->getThisServerName())
1004 .arg(new_state_name);
1015 switch (
config_->getHAMode()) {
1029 .arg(
config_->getThisServerName());
1041 boost::to_upper(state_name);
1043 .arg(
config_->getThisServerName())
1060 return (inScopeInternal(query4));
1065 return (inScopeInternal(query6));
1068template<
typename QueryPtrType>
1070HAService::inScopeInternal(QueryPtrType& query) {
1072 std::string scope_class;
1090 return (shouldReclaimInternal(lease4));
1095 return (shouldReclaimInternal(lease6));
1098template<
typename LeasePtrType>
1100HAService::shouldReclaimInternal(
const LeasePtrType& lease)
const {
1100HAService::shouldReclaimInternal(
const LeasePtrType& lease)
const {
…}
1107 boost::to_upper(current_state_name);
1120 boost::to_upper(current_state_name);
1122 .arg(
config_->getThisServerName())
1123 .arg(current_state_name);
1126 }
else if (should_enable && !
network_state_->isServiceEnabled()) {
1128 boost::to_upper(current_state_name);
1130 .arg(
config_->getThisServerName())
1131 .arg(current_state_name);
1169 if (!should_terminate) {
1176 return (should_terminate);
1190 .arg(
config_->getThisServerName());
1198 .arg(
config_->getThisServerName());
1206 .arg(
config_->getThisServerName());
1226 size_t sent_num = 0;
1229 for (
auto const& p : peers_configs) {
1237 for (
auto const& l : *deleted_leases) {
1240 if (l->state_ == Lease4::STATE_RELEASED) {
1248 for (
auto const& l : *leases) {
1270 for (
auto const& l : *deleted_leases) {
1273 if (l->state_ == Lease4::STATE_RELEASED) {
1283 for (
auto const& l : *leases) {
1304 leases->push_back(lease);
1319 size_t sent_num = 0;
1322 for (
auto const& p : peers_configs) {
1329 for (
auto const& l : *deleted_leases) {
1332 if (l->state_ == Lease4::STATE_RELEASED) {
1340 for (
auto const& l : *leases) {
1376template<
typename QueryPtrType>
1381 std::lock_guard<std::mutex> lock(mutex_);
1382 return (leaseUpdateCompleteInternal(query, parking_lot));
1384 return (leaseUpdateCompleteInternal(query, parking_lot));
1388template<
typename QueryPtrType>
1390HAService::leaseUpdateCompleteInternal(QueryPtrType& query,
1392 auto it = pending_requests_.find(query);
1396 if (it == pending_requests_.end() || (--pending_requests_[query] <= 0)) {
1398 parking_lot->unpark(query);
1403 if (it != pending_requests_.end()) {
1404 pending_requests_.erase(it);
1411template<
typename QueryPtrType>
1415 std::lock_guard<std::mutex> lock(mutex_);
1416 updatePendingRequestInternal(query);
1418 updatePendingRequestInternal(query);
1422template<
typename QueryPtrType>
1424HAService::updatePendingRequestInternal(QueryPtrType& query) {
1425 if (pending_requests_.count(query) == 0) {
1426 pending_requests_[query] = 1;
1428 ++pending_requests_[query];
1432template<
typename QueryPtrType>
1442 config->addBasicAuthHttpHeader(request);
1443 request->setBodyAsJson(command);
1444 request->finalize();
1453 boost::weak_ptr<typename QueryPtrType::element_type> weak_query(query);
1456 client_->asyncSendRequest(config->getUrl(), config->getTlsContext(),
1458 [
this, weak_query, parking_lot, config]
1459 (
const boost::system::error_code& ec,
1461 const std::string& error_str) {
1465 QueryPtrType query = weak_query.lock();
1467 isc_throw(Unexpected,
"query is null while receiving response from"
1468 " HA peer. This is programmatic error");
1479 bool lease_update_success =
true;
1480 bool lease_update_conflict =
false;
1483 if (ec || !error_str.empty()) {
1484 LOG_WARN(ha_logger, HA_LEASE_UPDATE_COMMUNICATIONS_FAILED)
1485 .arg(config_->getThisServerName())
1486 .arg(query->getLabel())
1487 .arg(config->getLogLabel())
1488 .arg(ec ? ec.message() : error_str);
1492 lease_update_success = false;
1498 auto args = verifyAsyncResponse(response, rcode);
1501 logFailedLeaseUpdates(query, args);
1503 } catch (
const ConflictError& ex) {
1505 lease_update_conflict =
true;
1506 lease_update_success =
false;
1510 .arg(
config_->getThisServerName())
1511 .arg(query->getLabel())
1512 .arg(config->getLogLabel())
1515 }
catch (
const std::exception& ex) {
1518 .arg(
config_->getThisServerName())
1519 .arg(query->getLabel())
1520 .arg(config->getLogLabel())
1524 lease_update_success =
false;
1533 if (!lease_update_success) {
1536 if (!lease_update_conflict) {
1539 communication_state_->setPartnerUnavailable();
1544 communication_state_->reportSuccessfulLeaseUpdate(query);
1551 if (config_->amWaitingBackupAck() || (config->getRole() != HAConfig::PeerConfig::BACKUP)) {
1555 if (!lease_update_success) {
1557 parking_lot->drop(query);
1566 if (leaseUpdateComplete(query, parking_lot)) {
1572 runModel(HA_LEASE_UPDATES_COMPLETE_EVT);
1576 std::bind(&HAService::clientConnectHandler,
this, ph::_1, ph::_2),
1577 std::bind(&HAService::clientHandshakeHandler,
this, ph::_1),
1578 std::bind(&HAService::clientCloseHandler,
this, ph::_1)
1585 if (config_->amWaitingBackupAck() || (config->getRole() != HAConfig::PeerConfig::BACKUP)) {
1587 updatePendingRequest(query);
1594 if (!config_->amSendingLeaseUpdates()) {
1599 if (peer_config->getRole() == HAConfig::PeerConfig::BACKUP) {
1604 if (config_->getThisServerConfig()->getRole() == HAConfig::PeerConfig::BACKUP) {
1610 switch (getCurrState()) {
1625 if (!config_->amSendingLeaseUpdates()) {
1629 if (peer_config->getRole() == HAConfig::PeerConfig::BACKUP) {
1637HAService::logFailedLeaseUpdates(
const PktPtr& query,
1650 auto failed_leases = args->get(param_name);
1653 if (failed_leases && (failed_leases->getType() ==
Element::list)) {
1655 for (
unsigned i = 0; i < failed_leases->size(); ++i) {
1656 auto lease = failed_leases->get(i);
1660 auto ip_address = lease->get(
"ip-address");
1663 auto lease_type = lease->get(
"type");
1666 auto error_message = lease->get(
"error-message");
1669 .arg(query->getLabel())
1671 lease_type->stringValue() :
"(unknown)")
1673 ip_address->stringValue() :
"(unknown)")
1675 error_message->stringValue() :
"(unknown)");
1689HAService::processStatusGet()
const {
1695 role = config_->getThisServerConfig()->getRole();
1696 std::string role_txt = HAConfig::PeerConfig::roleToString(role);
1698 int state = getCurrState();
1706 std::set<std::string> scopes = query_filter_.getServedScopes();
1708 for (
auto const& scope : scopes) {
1711 local->set(
"scopes", list);
1712 local->set(
"server-name",
Element::create(config_->getThisServerName()));
1713 auto const my_time(communication_state_->getMyTimeAtSkew());
1714 if (my_time.is_not_a_date_time()) {
1719 ha_servers->set(
"local", local);
1723 if ((config_->getHAMode() == HAConfig::PASSIVE_BACKUP) ||
1724 (config_->getThisServerConfig()->getRole() == HAConfig::PeerConfig::BACKUP)) {
1725 return (ha_servers);
1729 ElementPtr remote = communication_state_->getReport();
1732 role = config_->getFailoverPeerConfig()->getRole();
1733 role_txt = HAConfig::PeerConfig::roleToString(role);
1739 remote->set(
"server-name",
Element::create(config_->getFailoverPeerConfig()->getName()));
1740 ha_servers->set(
"remote", remote);
1742 return (ha_servers);
1689HAService::processStatusGet()
const {
…}
1746HAService::processHeartbeat() {
1748 std::string state_label = getState(getCurrState())->getLabel();
1754 auto scopes = query_filter_.getServedScopes();
1756 for (
auto const& scope : scopes) {
1759 arguments->set(
"scopes", scopes_list);
1761 arguments->set(
"unsent-update-count",
1762 Element::create(
static_cast<int64_t
>(communication_state_->getUnsentUpdateCount())));
1746HAService::processHeartbeat() {
…}
1769HAService::processHAReset() {
1769HAService::processHAReset() {
…}
1779HAService::asyncSendHeartbeat() {
1789 bool sync_complete_notified = sync_complete_notified_;
1790 sync_complete_notified_ =
false;
1796 partner_config->addBasicAuthHttpHeader(request);
1797 request->setBodyAsJson(CommandCreator::createHeartbeat(config_->getThisServerName(),
1799 request->finalize();
1806 client_->asyncSendRequest(partner_config->getUrl(),
1807 partner_config->getTlsContext(),
1809 [
this, partner_config, sync_complete_notified]
1810 (
const boost::system::error_code& ec,
1812 const std::string& error_str) {
1820 bool heartbeat_success = true;
1823 if (ec || !error_str.empty()) {
1824 LOG_WARN(ha_logger, HA_HEARTBEAT_COMMUNICATIONS_FAILED)
1825 .arg(config_->getThisServerName())
1826 .arg(partner_config->getLogLabel())
1827 .arg(ec ? ec.message() : error_str);
1828 heartbeat_success = false;
1837 ConstElementPtr args = verifyAsyncResponse(response, rcode);
1838 if (!args || args->getType() != Element::map) {
1839 isc_throw(CtrlChannelError,
"returned arguments in the response"
1843 ConstElementPtr state = args->get(
"state");
1844 if (!state || state->getType() != Element::string) {
1845 isc_throw(CtrlChannelError,
"server state not returned in response"
1846 " to a ha-heartbeat command or it is not a string");
1850 communication_state_->setPartnerState(state->stringValue());
1852 ConstElementPtr date_time = args->get(
"date-time");
1853 if (!date_time || date_time->getType() != Element::string) {
1854 isc_throw(CtrlChannelError,
"date-time not returned in response"
1855 " to a ha-heartbeat command or it is not a string");
1858 communication_state_->setPartnerTime(date_time->stringValue());
1862 auto scopes = args->get(
"scopes");
1863 communication_state_->setPartnerScopes(scopes);
1878 auto unsent_update_count = args->get(
"unsent-update-count");
1879 if (unsent_update_count) {
1880 if (unsent_update_count->getType() != Element::integer) {
1881 isc_throw(CtrlChannelError,
"unsent-update-count returned in"
1882 " the ha-heartbeat response is not an integer");
1884 communication_state_->setPartnerUnsentUpdateCount(static_cast<uint64_t>
1885 (unsent_update_count->intValue()));
1888 } catch (
const std::exception& ex) {
1890 .arg(config_->getThisServerName())
1891 .arg(partner_config->getLogLabel())
1893 heartbeat_success =
false;
1899 if (heartbeat_success) {
1900 communication_state_->poke();
1905 communication_state_->setPartnerUnavailable();
1907 if (communication_state_->isCommunicationInterrupted()) {
1908 LOG_WARN(ha_logger, HA_COMMUNICATION_INTERRUPTED)
1909 .arg(config_->getThisServerName())
1910 .arg(partner_config->getName());
1918 if (sync_complete_notified && !heartbeat_success) {
1919 postNextEvent(HA_SYNCED_PARTNER_UNAVAILABLE_EVT);
1926 runModel(HA_HEARTBEAT_COMPLETE_EVT);
1929 std::bind(&HAService::clientConnectHandler,
this, ph::_1, ph::_2),
1930 std::bind(&HAService::clientHandshakeHandler,
this, ph::_1),
1931 std::bind(&HAService::clientCloseHandler,
this, ph::_1)
1779HAService::asyncSendHeartbeat() {
…}
1936HAService::scheduleHeartbeat() {
1937 if (!communication_state_->isHeartbeatRunning()) {
1936HAService::scheduleHeartbeat() {
…}
1943HAService::startHeartbeat() {
1944 if (config_->getHeartbeatDelay() > 0) {
1945 communication_state_->startHeartbeat(config_->getHeartbeatDelay(),
1946 std::bind(&HAService::asyncSendHeartbeat,
1943HAService::startHeartbeat() {
…}
1954 const unsigned int max_period,
1961 remote_config->addBasicAuthHttpHeader(request);
1962 request->setBodyAsJson(CommandCreator::createDHCPDisable(getRemoteOrigin(),
1965 request->finalize();
1973 remote_config->getTlsContext(),
1975 [
this, remote_config, post_request_action]
1976 (
const boost::system::error_code& ec,
1978 const std::string& error_str) {
1987 std::string error_message;
1990 if (ec || !error_str.empty()) {
1991 error_message = (ec ? ec.message() : error_str);
1992 LOG_ERROR(ha_logger, HA_DHCP_DISABLE_COMMUNICATIONS_FAILED)
1993 .arg(config_->getThisServerName())
1994 .arg(remote_config->getLogLabel())
1995 .arg(error_message);
2001 static_cast<void>(verifyAsyncResponse(response, rcode));
2003 } catch (
const std::exception& ex) {
2004 error_message = ex.what();
2006 .arg(config_->getThisServerName())
2007 .arg(remote_config->getLogLabel())
2008 .arg(error_message);
2014 if (!error_message.empty()) {
2015 communication_state_->setPartnerUnavailable();
2019 if (post_request_action) {
2020 post_request_action(error_message.empty(),
2026 std::bind(&HAService::clientConnectHandler,
this, ph::_1, ph::_2),
2027 std::bind(&HAService::clientHandshakeHandler,
this, ph::_1),
2028 std::bind(&HAService::clientCloseHandler,
this, ph::_1)
2040 remote_config->addBasicAuthHttpHeader(request);
2041 request->setBodyAsJson(CommandCreator::createDHCPEnable(getRemoteOrigin(),
2043 request->finalize();
2051 remote_config->getTlsContext(),
2053 [
this, remote_config, post_request_action]
2054 (
const boost::system::error_code& ec,
2056 const std::string& error_str) {
2065 std::string error_message;
2068 if (ec || !error_str.empty()) {
2069 error_message = (ec ? ec.message() : error_str);
2070 LOG_ERROR(ha_logger, HA_DHCP_ENABLE_COMMUNICATIONS_FAILED)
2071 .arg(config_->getThisServerName())
2072 .arg(remote_config->getLogLabel())
2073 .arg(error_message);
2079 static_cast<void>(verifyAsyncResponse(response, rcode));
2081 } catch (
const std::exception& ex) {
2082 error_message = ex.what();
2084 .arg(config_->getThisServerName())
2085 .arg(remote_config->getLogLabel())
2086 .arg(error_message);
2092 if (!error_message.empty()) {
2093 communication_state_->setPartnerUnavailable();
2097 if (post_request_action) {
2098 post_request_action(error_message.empty(),
2104 std::bind(&HAService::clientConnectHandler,
this, ph::_1, ph::_2),
2105 std::bind(&HAService::clientHandshakeHandler,
this, ph::_1),
2106 std::bind(&HAService::clientCloseHandler,
this, ph::_1)
2111HAService::localDisableDHCPService() {
2112 network_state_->disableService(getLocalOrigin());
2111HAService::localDisableDHCPService() {
…}
2116HAService::localEnableDHCPService() {
2117 network_state_->enableService(getLocalOrigin());
2116HAService::localEnableDHCPService() {
…}
2121HAService::asyncSyncLeases() {
2125 unsigned int dhcp_disable_timeout =
2126 static_cast<unsigned int>(config_->getSyncTimeout() / 1000);
2127 if (dhcp_disable_timeout == 0) {
2129 dhcp_disable_timeout = 1;
2132 lease_sync_filter_.apply();
2133 asyncSyncLeases(*client_, config_->getFailoverPeerConfig(),
2134 dhcp_disable_timeout,
LeasePtr(), null_action);
2121HAService::asyncSyncLeases() {
…}
2140 const unsigned int max_period,
2143 const bool dhcp_disabled) {
2149 asyncDisableDHCPService(http_client, remote_config, max_period,
2150 [
this, &http_client, remote_config, max_period, last_lease,
2151 post_sync_action, dhcp_disabled]
2152 (
const bool success,
const std::string& error_message,
const int) {
2159 asyncSyncLeasesInternal(http_client, remote_config, max_period,
2160 last_lease, post_sync_action,
true);
2163 post_sync_action(success, error_message, dhcp_disabled);
2171 const unsigned int max_period,
2174 const bool dhcp_disabled) {
2179 remote_config->addBasicAuthHttpHeader(request);
2180 if (server_type_ == HAServerType::DHCPv4) {
2181 request->setBodyAsJson(CommandCreator::createLease4GetPage(
2182 boost::dynamic_pointer_cast<Lease4>(last_lease), config_->getSyncPageLimit()));
2185 request->setBodyAsJson(CommandCreator::createLease6GetPage(
2186 boost::dynamic_pointer_cast<Lease6>(last_lease), config_->getSyncPageLimit()));
2188 request->finalize();
2196 remote_config->getTlsContext(),
2198 [
this, remote_config, post_sync_action, &http_client, max_period, dhcp_disabled]
2199 (
const boost::system::error_code& ec,
2201 const std::string& error_str) {
2205 LeasePtr last_lease;
2213 std::string error_message;
2216 if (ec || !error_str.empty()) {
2217 error_message = (ec ? ec.message() : error_str);
2218 LOG_ERROR(ha_logger, HA_LEASES_SYNC_COMMUNICATIONS_FAILED)
2219 .arg(config_->getThisServerName())
2220 .arg(remote_config->getLogLabel())
2221 .arg(error_message);
2227 ConstElementPtr args = verifyAsyncResponse(response, rcode);
2230 if (args && (args->getType() != Element::map)) {
2231 isc_throw(CtrlChannelError,
2232 "arguments in the received response must be a map");
2235 ConstElementPtr leases = args->get(
"leases");
2236 if (!leases || (leases->getType() != Element::list)) {
2237 isc_throw(CtrlChannelError,
2238 "server response does not contain leases argument or this"
2239 " argument is not a list");
2243 auto const& leases_element = leases->listValue();
2245 LOG_INFO(ha_logger, HA_LEASES_SYNC_LEASE_PAGE_RECEIVED)
2246 .arg(config_->getThisServerName())
2247 .arg(leases_element.size())
2248 .arg(remote_config->getLogLabel());
2251 uint64_t applied_lease_count = 0;
2252 for (auto l = leases_element.begin(); l != leases_element.end(); ++l) {
2255 if (server_type_ == HAServerType::DHCPv4) {
2256 Lease4Ptr lease = Lease4::fromElement(*l);
2261 if ((leases_element.size() >= config_->getSyncPageLimit()) &&
2262 (l + 1 == leases_element.end())) {
2263 last_lease = boost::dynamic_pointer_cast<Lease>(lease);
2266 if (!lease_sync_filter_.shouldSync(lease)) {
2271 Lease4Ptr existing_lease = LeaseMgrFactory::instance().getLease4(lease->addr_);
2272 if (!existing_lease) {
2274 LeaseMgrFactory::instance().addLease(lease);
2275 ++applied_lease_count;
2277 } else if (existing_lease->cltt_ < lease->cltt_) {
2283 Lease::syncCurrentExpirationTime(*existing_lease, *lease);
2284 LeaseMgrFactory::instance().updateLease4(lease);
2285 ++applied_lease_count;
2288 LOG_DEBUG(ha_logger, DBGLVL_TRACE_BASIC, HA_LEASE_SYNC_STALE_LEASE4_SKIP)
2289 .arg(config_->getThisServerName())
2290 .arg(lease->addr_.toText())
2291 .arg(lease->subnet_id_);
2295 Lease6Ptr lease = Lease6::fromElement(*l);
2300 if ((leases_element.size() >= config_->getSyncPageLimit()) &&
2301 (l + 1 == leases_element.end())) {
2302 last_lease = boost::dynamic_pointer_cast<Lease>(lease);
2305 if (!lease_sync_filter_.shouldSync(lease)) {
2310 Lease6Ptr existing_lease = LeaseMgrFactory::instance().getLease6(lease->type_,
2312 if (!existing_lease) {
2314 LeaseMgrFactory::instance().addLease(lease);
2315 ++applied_lease_count;
2317 } else if (existing_lease->cltt_ < lease->cltt_) {
2323 Lease::syncCurrentExpirationTime(*existing_lease, *lease);
2324 LeaseMgrFactory::instance().updateLease6(lease);
2325 ++applied_lease_count;
2328 LOG_DEBUG(ha_logger, DBGLVL_TRACE_BASIC, HA_LEASE_SYNC_STALE_LEASE6_SKIP)
2329 .arg(config_->getThisServerName())
2330 .arg(lease->addr_.toText())
2331 .arg(lease->subnet_id_);
2335 } catch (const std::exception& ex) {
2336 LOG_WARN(ha_logger, HA_LEASE_SYNC_FAILED)
2337 .arg(config_->getThisServerName())
2343 LOG_INFO(ha_logger, HA_LEASES_SYNC_APPLIED_LEASES)
2344 .arg(config_->getThisServerName())
2345 .arg(applied_lease_count);
2347 } catch (
const std::exception& ex) {
2348 error_message = ex.what();
2350 .arg(config_->getThisServerName())
2351 .arg(remote_config->getLogLabel())
2352 .arg(error_message);
2358 if (!error_message.empty()) {
2359 communication_state_->setPartnerUnavailable();
2361 }
else if (last_lease) {
2364 asyncSyncLeases(http_client, remote_config, max_period, last_lease,
2365 post_sync_action, dhcp_disabled);
2370 if (post_sync_action) {
2371 post_sync_action(error_message.empty(),
2377 std::bind(&HAService::clientConnectHandler,
this, ph::_1, ph::_2),
2378 std::bind(&HAService::clientHandshakeHandler,
this, ph::_1),
2379 std::bind(&HAService::clientCloseHandler,
this, ph::_1)
2385HAService::processSynchronize(
const std::string& server_name,
2386 const unsigned int max_period) {
2389 remote_config = config_->getPeerConfig(server_name);
2390 }
catch (
const std::exception& ex) {
2394 if (remote_config->getName() == config_->getThisServerName()) {
2396 +
"' points to local server but should point to a partner"));
2398 std::string answer_message;
2399 int sync_status = synchronize(answer_message, remote_config, max_period);
2385HAService::processSynchronize(
const std::string& server_name, {
…}
2404HAService::synchronize(std::string& status_message,
2406 const unsigned int max_period) {
2407 lease_sync_filter_.apply();
2412 asyncSyncLeases(client, remote_config, max_period,
Lease4Ptr(),
2413 [&](
const bool success,
const std::string& error_message,
2414 const bool dhcp_disabled) {
2419 status_message = error_message;
2425 if (dhcp_disabled) {
2430 asyncSyncCompleteNotify(client, remote_config,
2431 [&](
const bool success,
2432 const std::string& error_message,
2438 asyncEnableDHCPService(client, remote_config,
2439 [&](
const bool success,
2440 const std::string& error_message,
2445 if (!success && status_message.empty()) {
2446 status_message = error_message;
2458 if (!success && status_message.empty()) {
2459 status_message = error_message;
2471 asyncEnableDHCPService(client, remote_config,
2472 [&](
const bool success,
2473 const std::string& error_message,
2475 if (!success && status_message.empty()) {
2476 status_message = error_message;
2495 .arg(config_->getThisServerName())
2496 .arg(remote_config->getLogLabel());
2510 io_service->stopAndPoll();
2514 if (!status_message.empty()) {
2515 postNextEvent(HA_SYNCING_FAILED_EVT);
2518 .arg(config_->getThisServerName())
2519 .arg(remote_config->getLogLabel())
2520 .arg(status_message);
2527 status_message =
"Lease database synchronization complete.";
2528 postNextEvent(HA_SYNCING_SUCCEEDED_EVT);
2531 .arg(config_->getThisServerName())
2532 .arg(remote_config->getLogLabel())
2404HAService::synchronize(std::string& status_message, {
…}
2539HAService::asyncSendLeaseUpdatesFromBacklog(
HttpClient& http_client,
2542 if (lease_update_backlog_.size() == 0) {
2548 if (server_type_ == HAServerType::DHCPv4) {
2550 Lease4Ptr lease = boost::dynamic_pointer_cast<Lease4>(lease_update_backlog_.pop(op_type));
2551 if (op_type == LeaseUpdateBacklog::ADD) {
2552 command = CommandCreator::createLease4Update(*lease);
2554 command = CommandCreator::createLease4Delete(*lease);
2558 command = CommandCreator::createLease6BulkApply(lease_update_backlog_);
2565 config->addBasicAuthHttpHeader(request);
2566 request->setBodyAsJson(command);
2567 request->finalize();
2575 [
this, &http_client, config, post_request_action]
2576 (
const boost::system::error_code& ec,
2578 const std::string& error_str) {
2581 std::string error_message;
2583 if (ec || !error_str.empty()) {
2584 error_message = (ec ? ec.message() : error_str);
2585 LOG_WARN(ha_logger, HA_LEASES_BACKLOG_COMMUNICATIONS_FAILED)
2586 .arg(config_->getThisServerName())
2587 .arg(config->getLogLabel())
2588 .arg(ec ? ec.message() : error_str);
2593 auto args = verifyAsyncResponse(response, rcode);
2594 } catch (
const std::exception& ex) {
2595 error_message = ex.what();
2597 .arg(config_->getThisServerName())
2598 .arg(config->getLogLabel())
2608 if (error_message.empty()) {
2609 asyncSendLeaseUpdatesFromBacklog(http_client, config, post_request_action);
2611 post_request_action(error_message.empty(), error_message, rcode);
2617HAService::sendLeaseUpdatesFromBacklog() {
2618 auto num_updates = lease_update_backlog_.size();
2619 if (num_updates == 0) {
2621 .arg(config_->getThisServerName());
2627 auto remote_config = config_->getFailoverPeerConfig();
2628 bool updates_successful =
true;
2631 .arg(config_->getThisServerName())
2633 .arg(remote_config->getName());
2635 asyncSendLeaseUpdatesFromBacklog(client, remote_config,
2636 [&](
const bool success,
const std::string&,
const int) {
2638 updates_successful = success;
2652 io_service->stopAndPoll();
2654 if (updates_successful) {
2656 .arg(config_->getThisServerName())
2657 .arg(remote_config->getName())
2658 .arg(stopwatch.logFormatLastDuration());
2661 return (updates_successful);
2617HAService::sendLeaseUpdatesFromBacklog() {
…}
2668 ConstElementPtr command = CommandCreator::createHAReset(config_->getThisServerName(),
2675 config->addBasicAuthHttpHeader(request);
2676 request->setBodyAsJson(command);
2677 request->finalize();
2685 [
this, config, post_request_action]
2686 (
const boost::system::error_code& ec,
2688 const std::string& error_str) {
2691 std::string error_message;
2693 if (ec || !error_str.empty()) {
2694 error_message = (ec ? ec.message() : error_str);
2695 LOG_WARN(ha_logger, HA_RESET_COMMUNICATIONS_FAILED)
2696 .arg(config_->getThisServerName())
2697 .arg(config->getLogLabel())
2698 .arg(ec ? ec.message() : error_str);
2703 auto args = verifyAsyncResponse(response, rcode);
2704 } catch (
const std::exception& ex) {
2705 error_message = ex.what();
2707 .arg(config_->getThisServerName())
2708 .arg(config->getLogLabel())
2713 post_request_action(error_message.empty(), error_message, rcode);
2718HAService::sendHAReset() {
2721 auto remote_config = config_->getFailoverPeerConfig();
2722 bool reset_successful =
true;
2724 asyncSendHAReset(client, remote_config,
2725 [&](
const bool success,
const std::string&,
const int) {
2727 reset_successful = success;
2735 io_service->stopAndPoll();
2737 return (reset_successful);
2741HAService::processScopes(
const std::vector<std::string>& scopes) {
2743 query_filter_.serveScopes(scopes);
2744 adjustNetworkState();
2746 }
catch (
const std::exception& ex) {
2741HAService::processScopes(
const std::vector<std::string>& scopes) {
…}
2754HAService::processContinue() {
2754HAService::processContinue() {
…}
2762HAService::processMaintenanceNotify(
const bool cancel,
const std::string& state) {
2766 " maintenance for the server not in the"
2767 " in-maintenance state."));
2771 communication_state_->setPartnerState(state);
2776 communication_state_->setPartnerUnavailable();
2778 postNextEvent(HA_MAINTENANCE_CANCEL_EVT);
2788 std::string state_label = getState(getCurrState())->getLabel();
2794 switch (getCurrState()) {
2804 return (
createAnswer(HA_CONTROL_RESULT_MAINTENANCE_NOT_ALLOWED,
2805 "Unable to transition the server from the "
2807 " in-maintenance state."));
2810 runModel(HA_MAINTENANCE_NOTIFY_EVT);
2762HAService::processMaintenanceNotify(
const bool cancel,
const std::string& state) {
…}
2816HAService::processMaintenanceStart() {
2817 switch (getCurrState()) {
2824 " partner-in-maintenance state."));
2836 remote_config->addBasicAuthHttpHeader(request);
2837 request->setBodyAsJson(CommandCreator::createMaintenanceNotify(config_->getThisServerName(),
2838 false, getCurrState(), server_type_));
2839 request->finalize();
2848 boost::system::error_code captured_ec;
2849 std::string captured_error_message;
2850 int captured_rcode = 0;
2854 remote_config->getTlsContext(),
2856 [
this, remote_config, &io_service, &captured_ec, &captured_error_message,
2858 (
const boost::system::error_code& ec,
2860 const std::string& error_str) {
2870 std::string error_message;
2873 if (ec || !error_str.empty()) {
2874 error_message = (ec ? ec.message() : error_str);
2875 LOG_ERROR(ha_logger, HA_MAINTENANCE_NOTIFY_COMMUNICATIONS_FAILED)
2876 .arg(config_->getThisServerName())
2877 .arg(remote_config->getLogLabel())
2878 .arg(error_message);
2884 static_cast<void>(verifyAsyncResponse(response, captured_rcode));
2886 } catch (
const std::exception& ex) {
2887 error_message = ex.what();
2889 .arg(config_->getThisServerName())
2890 .arg(remote_config->getLogLabel())
2891 .arg(error_message);
2897 if (!error_message.empty()) {
2898 communication_state_->setPartnerUnavailable();
2902 captured_error_message = error_message;
2905 std::bind(&HAService::clientConnectHandler,
this, ph::_1, ph::_2),
2906 std::bind(&HAService::clientHandshakeHandler,
this, ph::_1),
2907 std::bind(&HAService::clientCloseHandler,
this, ph::_1)
2916 io_service->stopAndPoll();
2921 postNextEvent(HA_MAINTENANCE_START_EVT);
2922 verboseTransition(HA_PARTNER_DOWN_ST);
2925 "Server is now in the partner-down state as its"
2926 " partner appears to be offline for maintenance."));
2932 postNextEvent(HA_MAINTENANCE_START_EVT);
2933 verboseTransition(HA_PARTNER_IN_MAINTENANCE_ST);
2940 " partner-in-maintenance state. The partner server responded"
2941 " with the following message to the ha-maintenance-notify"
2942 " command: " + captured_error_message +
"."));
2947 "Server is now in the partner-in-maintenance state"
2948 " and its partner is in-maintenance state. The partner"
2949 " can be now safely shut down."));
2816HAService::processMaintenanceStart() {
…}
2953HAService::processMaintenanceCancel() {
2956 " request because the server is not in the"
2957 " partner-in-maintenance state."));
2971 remote_config->addBasicAuthHttpHeader(request);
2972 request->setBodyAsJson(CommandCreator::createMaintenanceNotify(config_->getThisServerName(),
2976 request->finalize();
2985 std::string error_message;
2989 remote_config->getTlsContext(),
2991 [
this, remote_config, &io_service, &error_message]
2992 (
const boost::system::error_code& ec,
2994 const std::string& error_str) {
2999 if (ec || !error_str.empty()) {
3000 error_message = (ec ? ec.message() : error_str);
3001 LOG_ERROR(ha_logger, HA_MAINTENANCE_NOTIFY_CANCEL_COMMUNICATIONS_FAILED)
3002 .arg(config_->getThisServerName())
3003 .arg(remote_config->getLogLabel())
3004 .arg(error_message);
3011 ConstElementPtr args = verifyAsyncResponse(response, rcode);
3016 communication_state_->setPartnerUnavailable();
3020 if (args && args->getType() == Element::map) {
3022 ConstElementPtr state = args->get(
"state");
3024 if (state->getType() != Element::string) {
3025 isc_throw(CtrlChannelError,
"server state not returned in response"
3026 " to a ha-heartbeat command or it is not a string");
3028 communication_state_->setPartnerState(state->stringValue());
3031 } catch (
const std::exception& ex) {
3032 error_message = ex.what();
3034 .arg(config_->getThisServerName())
3035 .arg(remote_config->getLogLabel())
3036 .arg(error_message);
3042 if (!error_message.empty()) {
3043 communication_state_->setPartnerUnavailable();
3047 std::bind(&HAService::clientConnectHandler,
this, ph::_1, ph::_2),
3048 std::bind(&HAService::clientHandshakeHandler,
this, ph::_1),
3049 std::bind(&HAService::clientCloseHandler,
this, ph::_1)
3058 io_service->stopAndPoll();
3062 if (!error_message.empty()) {
3064 "Unable to cancel maintenance. The partner server responded"
3065 " with the following message to the ha-maintenance-notify"
3066 " command: " + error_message +
"."));
3072 postNextEvent(HA_MAINTENANCE_CANCEL_EVT);
3073 verboseTransition(next_state);
3077 "Server maintenance successfully canceled."));
2953HAService::processMaintenanceCancel() {
…}
3089 remote_config->addBasicAuthHttpHeader(request);
3090 request->setBodyAsJson(CommandCreator::createSyncCompleteNotify(getRemoteOrigin(),
3091 config_->getThisServerName(),
3093 request->finalize();
3101 remote_config->getTlsContext(),
3103 [
this, remote_config, post_request_action]
3104 (
const boost::system::error_code& ec,
3106 const std::string& error_str) {
3115 std::string error_message;
3118 if (ec || !error_str.empty()) {
3119 error_message = (ec ? ec.message() : error_str);
3120 LOG_ERROR(ha_logger, HA_SYNC_COMPLETE_NOTIFY_COMMUNICATIONS_FAILED)
3121 .arg(config_->getThisServerName())
3122 .arg(remote_config->getLogLabel())
3123 .arg(error_message);
3129 static_cast<void>(verifyAsyncResponse(response, rcode));
3131 } catch (
const CommandUnsupportedError& ex) {
3134 }
catch (
const std::exception& ex) {
3135 error_message = ex.what();
3137 .arg(config_->getThisServerName())
3138 .arg(remote_config->getLogLabel())
3139 .arg(error_message);
3145 if (!error_message.empty()) {
3146 communication_state_->setPartnerUnavailable();
3150 if (post_request_action) {
3151 post_request_action(error_message.empty(),
3157 std::bind(&HAService::clientConnectHandler,
this, ph::_1, ph::_2),
3158 std::bind(&HAService::clientHandshakeHandler,
this, ph::_1),
3159 std::bind(&HAService::clientCloseHandler,
this, ph::_1)
3164HAService::processSyncCompleteNotify(
const unsigned int origin_id) {
3166 sync_complete_notified_ =
true;
3174 network_state_->disableService(getLocalOrigin());
3179 network_state_->enableService(origin_id);
3181 "Server successfully notified about the synchronization completion."));
3164HAService::processSyncCompleteNotify(
const unsigned int origin_id) {
…}
3190 boost::dynamic_pointer_cast<HttpResponseJson>(response);
3191 if (!json_response) {
3220 if (body->empty()) {
3231 std::ostringstream s;
3240 s << args->stringValue() <<
" (";
3243 s <<
"error code " << rcode <<
")";
3248 isc_throw(CommandUnsupportedError, s.str());
3256 auto failed_leases = args->get(
"failed-leases");
3257 if (!failed_leases || (failed_leases->getType() !=
Element::list)) {
3261 auto conflict =
false;
3263 for (
unsigned i = 0; i < failed_leases->size(); ++i) {
3264 auto lease = failed_leases->get(i);
3268 auto result = lease->get(
"result");
3272 auto error_message = lease->get(
"error-message");
3275 if (error_message && error_message->getType()) {
3276 s << error_message->stringValue() <<
" (";
3278 s <<
"error code " << result->intValue() <<
")";
3286 conflict_error_message = error_message;
3292 if (conflict_error_message &&
3294 s << conflict_error_message->stringValue() <<
" (";
3308HAService::clientConnectHandler(
const boost::system::error_code& ec,
int tcp_native_fd) {
3312 if (client_->getThreadIOService()) {
3320 if ((!ec || (ec.value() == boost::asio::error::in_progress))
3321 && (tcp_native_fd >= 0)) {
3327 std::bind(&HAService::socketReadyHandler,
this, ph::_1)
3308HAService::clientConnectHandler(
const boost::system::error_code& ec,
int tcp_native_fd) {
…}
3339HAService::socketReadyHandler(
int tcp_native_fd) {
3344 client_->closeIfOutOfBand(tcp_native_fd);
3339HAService::socketReadyHandler(
int tcp_native_fd) {
…}
3348HAService::clientCloseHandler(
int tcp_native_fd) {
3349 if (tcp_native_fd >= 0) {
3348HAService::clientCloseHandler(
int tcp_native_fd) {
…}
3355HAService::pendingRequestSize() {
3357 std::lock_guard<std::mutex> lock(mutex_);
3358 return (pending_requests_.size());
3360 return (pending_requests_.size());
3355HAService::pendingRequestSize() {
…}
3364template<
typename QueryPtrType>
3366HAService::getPendingRequest(
const QueryPtrType& query) {
3368 std::lock_guard<std::mutex> lock(mutex_);
3369 return (getPendingRequestInternal(query));
3371 return (getPendingRequestInternal(query));
3366HAService::getPendingRequest(
const QueryPtrType& query) {
…}
3375template<
typename QueryPtrType>
3377HAService::getPendingRequestInternal(
const QueryPtrType& query) {
3378 if (pending_requests_.count(query) == 0) {
3381 return (pending_requests_[query]);
3386HAService::checkPermissionsClientAndListener() {
3394 client_->checkPermissions();
3398 listener_->checkPermissions();
3402 .arg(config_->getThisServerName())
3407 }
catch (
const std::exception& ex) {
3409 .arg(config_->getThisServerName())
3386HAService::checkPermissionsClientAndListener() {
…}
3415HAService::startClientAndListener() {
3418 std::bind(&HAService::checkPermissionsClientAndListener,
this),
3419 std::bind(&HAService::pauseClientAndListener,
this),
3420 std::bind(&HAService::resumeClientAndListener,
this));
3415HAService::startClientAndListener() {
…}
3432HAService::pauseClientAndListener() {
3443 }
catch (
const std::exception& ex) {
3432HAService::pauseClientAndListener() {
…}
3450HAService::resumeClientAndListener() {
3459 listener_->resume();
3461 }
catch (std::exception& ex) {
3463 .arg(config_->getThisServerName())
3450HAService::resumeClientAndListener() {
…}
3469HAService::stopClientAndListener() {
3469HAService::stopClientAndListener() {
…}
3483template int HAService::getPendingRequest(
const Pkt4Ptr&);
3484template 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_context 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.
boost::shared_ptr< PeerConfig > PeerConfigPtr
Pointer to the server's configuration.
static std::string HAModeToString(const HAMode &ha_mode)
Returns HA mode name.
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.
bool shouldReclaim(const dhcp::Lease4Ptr &lease4) const
Checks if the lease should be reclaimed by this server.
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.
std::function< void(const bool, const std::string &, const bool)> PostSyncCallback
Callback invoked when lease database synchronization is complete.
QueryFilter query_filter_
Selects queries to be processed/dropped.
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.
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.
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.
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")
ConstElementPtr parseAnswer(int &rcode, const ConstElementPtr &msg)
Parses a standard config/command level answer and returns arguments or text status code.
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.
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< Lease6 > Lease6Ptr
Pointer to a Lease6 structure.
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.
std::string ptimeToText(boost::posix_time::ptime t, size_t fsecs_precision=MAX_FSECS_PRECISION)
Converts ptime structure to text.
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.