#include <dhcpsrv/lease_file_loader.h>
#include <dhcpsrv/memfile_lease_mgr.h>
#include <exceptions/exceptions.h>
+#include <util/process_spawn.h>
#include <cstdio>
#include <iostream>
#include <sstream>
/// @brief Maximum number of errors to read the leases from the lease file.
const uint32_t MAX_LEASE_ERRORS = 100;
+const char* KEA_LFC_EXECUTABLE_ENV_NAME = "KEA_LFC_EXECUTABLE";
+
} // end of anonymous namespace
+using namespace isc;
using namespace isc::dhcp;
using namespace isc::util;
Memfile_LeaseMgr::Memfile_LeaseMgr(const ParameterMap& parameters)
- : LeaseMgr(parameters), lfc_timer_(*getIOService()) {
+ : LeaseMgr(parameters), lfc_timer_(*getIOService()),
+ lfc_process_() {
// Check the universe and use v4 file or v6 file.
std::string universe = getParameter("universe");
if (universe == "4") {
LOG_WARN(dhcpsrv_logger, DHCPSRV_MEMFILE_NO_STORAGE);
} else {
- initTimers();
+ lfcSetup();
}
}
}
void
-Memfile_LeaseMgr::initTimers() {
+Memfile_LeaseMgr::lfcSetup() {
std::string lfc_interval_str = "0";
try {
lfc_interval_str = getParameter("lfc-interval");
<< lfc_interval_str << " specified");
}
+ // If LFC is enabled, we have to setup the interval timer and prepare for
+ // executing the kea-lfc process.
if (lfc_interval > 0) {
+ char* c_executable = getenv(KEA_LFC_EXECUTABLE_ENV_NAME);
+
+ // Set the timer to call callback function periodically.
asiolink::IntervalTimer::Callback cb =
boost::bind(&Memfile_LeaseMgr::lfcCallback, this);
LOG_INFO(dhcpsrv_logger, DHCPSRV_MEMFILE_LFC_SETUP).arg(lfc_interval);
lfc_timer_.setup(cb, lfc_interval * 1000);
+
+ // Start preparing the command line for kea-lfc.
+
+ // Gather the base file name.
+ std::string lease_file = lease_file4_ ? lease_file4_->getFilename() :
+ lease_file6_->getFilename();
+
+ // Create the other names by appending suffixes to the base name.
+ util::ProcessArgs args;
+ // Universe: v4 or v6.
+ args.push_back(lease_file4_ ? "-4" : "-6");
+ // Previous file.
+ args.push_back("-p");
+ args.push_back(appendSuffix(lease_file, FILE_PREVIOUS));
+ // Input file.
+ args.push_back("-i");
+ args.push_back(appendSuffix(lease_file, FILE_INPUT));
+ // Output file.
+ args.push_back("-o");
+ args.push_back(appendSuffix(lease_file, FILE_OUTPUT));
+ // Finish file.
+ args.push_back("-f");
+ args.push_back(appendSuffix(lease_file, FILE_FINISH));
+ // The configuration file is currently unused.
+ args.push_back("-c");
+ args.push_back("ignored-path");
+
+ // Create the process (do not start it yet).
+ lfc_process_.reset(new util::ProcessSpawn(std::string(c_executable), args));
}
}
+
void
Memfile_LeaseMgr::lfcCallback() {
- /// @todo Extend this method to spawn the new process which will
- /// perform the Lease File Cleanup in background.
LOG_INFO(dhcpsrv_logger, DHCPSRV_MEMFILE_LFC_START);
// Check if we're in the v4 or v6 space and use the appropriate file.
template<typename LeaseFileType>
void Memfile_LeaseMgr::
leaseFileCleanup(boost::shared_ptr<LeaseFileType>& lease_file) {
+ // Check if the copy of the lease file exists already. If it does, it
+ // is an indication that another LFC instance may be in progress, in
+ // which case we don't want to rotate the current lease file to avoid
+ // overriding the contents of the existing file.
CSVFile lease_file_copy(appendSuffix(lease_file->getFilename(), FILE_INPUT));
if (!lease_file_copy.exists()) {
+ // Close the current file so as we can move it to the copy file.
lease_file->close();
+ // Move the current file to the copy file.
rename(lease_file->getFilename().c_str(),
lease_file_copy.getFilename().c_str());
+ // Now that we moved the current file, we need to create a new one.
lease_file.reset(new LeaseFileType(lease_file->getFilename()));
+ // Leave the new file open for writing.
lease_file->open();
}
+ // Once we have rotated files as needed, start the new kea-lfc process
+ // to perform a cleanup.
+ lfc_process_->spawn();
}
template<typename LeaseObjectType, typename LeaseFileType, typename StorageType>
#include <dhcpsrv/csv_lease_file6.h>
#include <dhcpsrv/memfile_lease_storage.h>
#include <dhcpsrv/lease_mgr.h>
+#include <util/process_spawn.h>
+#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
namespace isc {
private:
- /// @brief Initialize the timers used to perform repeating tasks.
+ /// @brief Setup the periodic Lease File Cleanup.
///
- /// Currently only one timer is supported. This timer executes the
- /// Lease File Cleanup periodically.
- void initTimers();
+ /// This method checks if the @c lfc-interval configuration parameter
+ /// is set to a non-zero value and sets up the interval timer to
+ /// perform the Lease File Cleanup periodically. It also prepares the
+ /// path and arguments for the @c kea-lfc application which will be
+ /// executed to perform the cleanup.
+ void lfcSetup();
+
/// @brief Initialize the location of the lease file.
///
/// This method uses the parameters passed as a map to the constructor to
/// @brief A timer scheduled to perform Lease File Cleanup.
asiolink::IntervalTimer lfc_timer_;
+protected:
+
+ boost::scoped_ptr<util::ProcessSpawn> lfc_process_;
+
};
}; // end of isc::dhcp namespace
#include <iostream>
#include <fstream>
-#include <sstream>
#include <queue>
+#include <sstream>
+#include <unistd.h>
using namespace std;
using namespace isc;
}
using Memfile_LeaseMgr::lfcCallback;
+ using Memfile_LeaseMgr::lfc_process_;
};
/// @brief Test fixture class for @c Memfile_LeaseMgr
io_service_(),
fail_on_callback_(false) {
+ std::ostringstream s;
+ s << KEA_LFC_BUILD_DIR << "/kea-lfc";
+ setenv("KEA_LFC_EXECUTABLE", s.str().c_str(), 1);
+
// Remove lease files and products of Lease File Cleanup.
removeFiles(getLeaseFilePath("leasefile4_0.csv"));
removeFiles(getLeaseFilePath("leasefile6_0.csv"));
}
}
+ /// @brief Waits for the specified process to finish.
+ ///
+ /// @param process An object which started the process.
+ /// @param timeout Timeout in seconds.
+ ///
+ /// @return true if the process ended, false otherwise
+ bool waitForProcess(const util::ProcessSpawn& process,
+ const uint8_t timeout) {
+ uint32_t iterations = 0;
+ const uint32_t iterations_max = timeout * 1000;
+ while (process.isRunning() && (iterations < iterations_max)) {
+ usleep(1000);
+ ++iterations;
+ }
+ return (iterations < iterations_max);
+ }
+
+
/// @brief Object providing access to v4 lease IO.
LeaseFileIO io4_;
ASSERT_TRUE(current_file.exists());
EXPECT_EQ(new_file_contents, current_file.readFile());
+
+ ASSERT_TRUE(waitForProcess(*lease_mgr->lfc_process_, 2));
+
+ EXPECT_EQ(0, lease_mgr->lfc_process_->getExitStatus());
}
// Test that the backend returns a correct value of the interval
// lfc-interval = 10
pmap["lfc-interval"] = "10";
+ lease_mgr.reset();
lease_mgr.reset(new LFCMemfileLeaseMgr(pmap));
EXPECT_EQ(10, lease_mgr->getIOServiceExecInterval());
// lfc-interval = 20
pmap["lfc-interval"] = "20";
+ lease_mgr.reset();
lease_mgr.reset(new LFCMemfileLeaseMgr(pmap));
EXPECT_EQ(20, lease_mgr->getIOServiceExecInterval());