std::string status_message;
int sync_status = synchronize(status_message,
config_->getFailoverPeerConfig()->getName(),
- 60);
+ 60, 1024);
// If the leases synchronization was successful, let's transition
// to the ready state.
}
void
-HAService::asyncSyncLeases() {
+HAService::asyncSyncLeases(const uint32_t limit) {
PostRequestCallback null_action;
- asyncSyncLeases(client_, null_action);
+ asyncSyncLeases(client_, LeasePtr(), limit, null_action);
}
void
HAService::asyncSyncLeases(http::HttpClient& http_client,
+ const dhcp::LeasePtr& last_lease,
+ const uint32_t limit,
const PostRequestCallback& post_sync_action) {
HAConfig::PeerConfigPtr partner_config = config_->getFailoverPeerConfig();
PostHttpRequestJsonPtr request = boost::make_shared<PostHttpRequestJson>
(HttpRequest::Method::HTTP_POST, "/", HttpVersion::HTTP_11());
if (server_type_ == HAServerType::DHCPv4) {
- request->setBodyAsJson(CommandCreator::createLease4GetAll());
+ request->setBodyAsJson(CommandCreator::createLease4GetPage(
+ boost::dynamic_pointer_cast<Lease4>(last_lease), limit));
} else {
- request->setBodyAsJson(CommandCreator::createLease6GetAll());
+ request->setBodyAsJson(CommandCreator::createLease6GetPage(
+ boost::dynamic_pointer_cast<Lease6>(last_lease), limit));
}
request->finalize();
// Schedule asynchronous HTTP request.
http_client.asyncSendRequest(partner_config->getUrl(), request, response,
- [this, partner_config, post_sync_action]
+ [this, partner_config, post_sync_action, &http_client, limit]
(const boost::system::error_code& ec,
const HttpResponsePtr& response,
const std::string& error_str) {
+ // Holds last lease received on the page of leases. If the last
+ // page was hit, this value remains null.
+ LeasePtr last_lease;
+
// There are three possible groups of errors during the heartneat.
// One is the IO error causing issues in communication with the peer.
// Another one is an HTTP parsing error. The last type of error is
// Iterate over the leases and update the database as appropriate.
const auto& leases_element = leases->listValue();
+
+ // If we haven't hit the last page. Set the last lease pointer so as
+ // it can be used as an input to the next leaseX-get-page command.
+ if (leases_element.size() >= limit) {
+ last_lease = boost::dynamic_pointer_cast<Lease>(*leases_element.rbegin());
+ }
+
for (auto l = leases_element.begin(); l != leases_element.end(); ++l) {
try {
if (server_type_ == HAServerType::DHCPv4) {
// partner as unavailable.
if (!error_message.empty()) {
communication_state_->setPartnerState("unavailable");
+
+ } else if (last_lease) {
+ asyncSyncLeases(http_client, last_lease, limit, post_sync_action);
+ return;
}
// Invoke post synchronization action if it was specified.
HAService::processSynchronize(const std::string& server_name,
const unsigned int max_period) {
std::string answer_message;
- int sync_status = synchronize(answer_message, server_name, max_period);
+ int sync_status = synchronize(answer_message, server_name, max_period, 1024);
return (createAnswer(sync_status, answer_message));
}
int
HAService::synchronize(std::string& status_message, const std::string& server_name,
- const unsigned int max_period) {
+ const unsigned int max_period, const uint32_t page_limit) {
IOService io_service;
HttpClient client(io_service);
// If we have successfully disabled the DHCP service on the peer,
// we can start fetching the leases.
if (success) {
- asyncSyncLeases(client, [&](const bool success,
- const std::string& error_message) {
+ asyncSyncLeases(client, Lease4Ptr(), page_limit,
+ [&](const bool success, const std::string& error_message) {
// If there was a fatal error while fetching the leases, let's
// log an error message so as it can be included in the response
// to the controlling client.
/// remaining leases.
///
/// This method variant uses default HTTP client for communication.
- void asyncSyncLeases();
+ ///
+ /// @param limit Limit of leases on the page.
+ void asyncSyncLeases(const uint32_t limit = 1024);
/// @brief Asynchronously reads leases from a peer and updates local
/// lease database using a provided client instance.
///
/// @param http_client reference to the client to be used to communicate
/// with the other server.
+ /// @param lease Pointer to the last lease returned on the previous
+ /// page of leases. This lease is used to set the value of the "from"
+ /// parameter in the lease4-get-page and lease6-get-page commands. If this
+ /// command is sent to fetch the first page, the @c last_lease parameter
+ /// should be set to null.
+ /// @param limit Limit of leases on the page.
/// @param post_sync_action pointer to the function to be executed when
/// lease database synchronization is complete. If this is null, no
/// post synchronization action is invoked.
void asyncSyncLeases(http::HttpClient& http_client,
+ const dhcp::LeasePtr& last_lease,
+ const uint32_t limit,
const PostRequestCallback& post_sync_action);
public:
/// @param max_period maximum number of seconds to disable DHCP service
/// of the peer. This value is used in dhcp-disable command issued to
/// the peer before the lease4-get-all command.
+ /// @param page_limit Maximum size of a single page of leases to be returned.
///
/// @return Synchronization result according to the status codes returned
/// in responses to control commands.
int synchronize(std::string& status_message, const std::string& server_name,
- const unsigned int max_period);
+ const unsigned int max_period, const uint32_t page_limit);
public:
ElementPtr response_arguments = Element::createMap();
response_arguments->set("leases", getTestLeases4AsJson());
- factory2_->getResponseCreator()->setArguments("lease4-get-all", response_arguments);
- factory3_->getResponseCreator()->setArguments("lease4-get-all", response_arguments);
+ factory2_->getResponseCreator()->setArguments("lease4-get-page", response_arguments);
+ factory3_->getResponseCreator()->setArguments("lease4-get-page", response_arguments);
// Start the servers.
ASSERT_NO_THROW({
ElementPtr response_arguments = Element::createMap();
response_arguments->set("leases", getTestLeases6AsJson());
- factory2_->getResponseCreator()->setArguments("lease6-get-all", response_arguments);
- factory3_->getResponseCreator()->setArguments("lease6-get-all", response_arguments);
+ factory2_->getResponseCreator()->setArguments("lease6-get-page", response_arguments);
+ factory3_->getResponseCreator()->setArguments("lease6-get-page", response_arguments);
// Start the servers.
ASSERT_NO_THROW({
}
// The following commands should have been sent to the server2: dhcp-disable,
- // lease4-get-all and dhcp-enable.
+ // lease4-get-page and dhcp-enable.
EXPECT_TRUE(factory2_->getResponseCreator()->findRequest("dhcp-disable","20"));
- EXPECT_TRUE(factory2_->getResponseCreator()->findRequest("lease4-get-all",""));
+ EXPECT_TRUE(factory2_->getResponseCreator()->findRequest("lease4-get-page",""));
EXPECT_TRUE(factory2_->getResponseCreator()->findRequest("dhcp-enable",""));
}
// The server2 should only receive dhcp-disable commands. Remaining two should
// not be sent.
EXPECT_TRUE(factory2_->getResponseCreator()->findRequest("dhcp-disable","20"));
- EXPECT_FALSE(factory2_->getResponseCreator()->findRequest("lease4-get-all",""));
+ EXPECT_FALSE(factory2_->getResponseCreator()->findRequest("lease4-get-page",""));
EXPECT_FALSE(factory2_->getResponseCreator()->findRequest("dhcp-enable",""));
}
-// This test verifies that an error is reported when sending a lease4-get-all
+// This test verifies that an error is reported when sending a lease4-get-page
// command causes an error.
TEST_F(HAServiceTest, processSynchronizeLease4GetAllError) {
// Setup the server2 to return an error to dhcp-disable commands.
- factory2_->getResponseCreator()->setControlResult("lease4-get-all",
+ factory2_->getResponseCreator()->setControlResult("lease4-get-page",
CONTROL_RESULT_ERROR);
// Run HAService::processSynchronize and gather a response.
// The server2 should receive all commands. The dhcp-disable was successful, so
// the dhcp-enable command must be sent to re-enable the service after failure.
EXPECT_TRUE(factory2_->getResponseCreator()->findRequest("dhcp-disable","20"));
- EXPECT_TRUE(factory2_->getResponseCreator()->findRequest("lease4-get-all",""));
+ EXPECT_TRUE(factory2_->getResponseCreator()->findRequest("lease4-get-page",""));
EXPECT_TRUE(factory2_->getResponseCreator()->findRequest("dhcp-enable",""));
}
// The server2 should receive all commands.
EXPECT_TRUE(factory2_->getResponseCreator()->findRequest("dhcp-disable","20"));
- EXPECT_TRUE(factory2_->getResponseCreator()->findRequest("lease4-get-all",""));
+ EXPECT_TRUE(factory2_->getResponseCreator()->findRequest("lease4-get-page",""));
EXPECT_TRUE(factory2_->getResponseCreator()->findRequest("dhcp-enable",""));
}
}
// The following commands should have been sent to the server2: dhcp-disable,
- // lease6-get-all and dhcp-enable.
+ // lease6-get-page and dhcp-enable.
EXPECT_TRUE(factory2_->getResponseCreator()->findRequest("dhcp-disable","20"));
- EXPECT_TRUE(factory2_->getResponseCreator()->findRequest("lease6-get-all",""));
+ EXPECT_TRUE(factory2_->getResponseCreator()->findRequest("lease6-get-page",""));
EXPECT_TRUE(factory2_->getResponseCreator()->findRequest("dhcp-enable",""));
}
// The server2 should only receive dhcp-disable commands. Remaining two should
// not be sent.
EXPECT_TRUE(factory2_->getResponseCreator()->findRequest("dhcp-disable","20"));
- EXPECT_FALSE(factory2_->getResponseCreator()->findRequest("lease6-get-all",""));
+ EXPECT_FALSE(factory2_->getResponseCreator()->findRequest("lease6-get-page",""));
EXPECT_FALSE(factory2_->getResponseCreator()->findRequest("dhcp-enable",""));
}
-// This test verifies that an error is reported when sending a lease6-get-all
+// This test verifies that an error is reported when sending a lease6-get-page
// command causes an error.
TEST_F(HAServiceTest, processSynchronizeLease6GetAllError) {
// Setup the server2 to return an error to dhcp-disable commands.
- factory2_->getResponseCreator()->setControlResult("lease6-get-all",
+ factory2_->getResponseCreator()->setControlResult("lease6-get-page",
CONTROL_RESULT_ERROR);
// Run HAService::processSynchronize and gather a response.
// The server2 should receive all commands. The dhcp-disable was successful, so
// the dhcp-enable command must be sent to re-enable the service after failure.
EXPECT_TRUE(factory2_->getResponseCreator()->findRequest("dhcp-disable","20"));
- EXPECT_TRUE(factory2_->getResponseCreator()->findRequest("lease6-get-all",""));
+ EXPECT_TRUE(factory2_->getResponseCreator()->findRequest("lease6-get-page",""));
EXPECT_TRUE(factory2_->getResponseCreator()->findRequest("dhcp-enable",""));
}
// The server2 should receive all commands.
EXPECT_TRUE(factory2_->getResponseCreator()->findRequest("dhcp-disable","20"));
- EXPECT_TRUE(factory2_->getResponseCreator()->findRequest("lease6-get-all",""));
+ EXPECT_TRUE(factory2_->getResponseCreator()->findRequest("lease6-get-page",""));
EXPECT_TRUE(factory2_->getResponseCreator()->findRequest("dhcp-enable",""));
}
/// @brief Enable response to commands required for leases synchronization.
///
- /// Enables dhcp-disable, dhcp-enable and lease4-get-all commands. The last
+ /// Enables dhcp-disable, dhcp-enable and lease4-get-page commands. The last
/// of them returns a bunch of test leases.
void enableRespondLeaseFetching() {
// Create IPv4 leases which will be fetched from the other server.
ElementPtr response_arguments = Element::createMap();
response_arguments->set("leases", getLeasesAsJson(leases4));
- factory_->getResponseCreator()->setArguments("lease4-get-all", response_arguments);
+ factory_->getResponseCreator()->setArguments("lease4-get-page", response_arguments);
}
/// @brief Starts up the partner.
// the partner's IO service in thread (in background).
testSynchronousCommands([this, &partner]() {
- // SYNCING state: the partner is up but it won't respond to the lease4-get-all
+ // SYNCING state: the partner is up but it won't respond to the lease4-get-page
// command correctly. This should leave us in the SYNCING state until we finally
// can synchronize.
service_->runModel(HAService::NOP_EVT);