Browse Source

[3669] Memfile spawns kea-lfc for lease file cleanup.

Marcin Siodelski 10 years ago
parent
commit
c1372a95ef

+ 54 - 5
src/lib/dhcpsrv/memfile_lease_mgr.cc

@@ -17,6 +17,7 @@
 #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>
@@ -26,13 +27,17 @@ namespace {
 /// @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") {
@@ -57,7 +62,7 @@ Memfile_LeaseMgr::Memfile_LeaseMgr(const ParameterMap& parameters)
         LOG_WARN(dhcpsrv_logger, DHCPSRV_MEMFILE_NO_STORAGE);
 
     } else  {
-        initTimers();
+        lfcSetup();
     }
 }
 
@@ -511,7 +516,7 @@ Memfile_LeaseMgr::initLeaseFilePath(Universe u) {
 }
 
 void
-Memfile_LeaseMgr::initTimers() {
+Memfile_LeaseMgr::lfcSetup() {
     std::string lfc_interval_str = "0";
     try {
         lfc_interval_str = getParameter("lfc-interval");
@@ -527,18 +532,51 @@ Memfile_LeaseMgr::initTimers() {
                   << 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.
@@ -554,14 +592,25 @@ Memfile_LeaseMgr::lfcCallback() {
 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>

+ 14 - 4
src/lib/dhcpsrv/memfile_lease_mgr.h

@@ -21,7 +21,9 @@
 #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 {
@@ -405,11 +407,15 @@ protected:
 
 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
@@ -485,6 +491,10 @@ private:
     /// @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

+ 1 - 0
src/lib/dhcpsrv/tests/Makefile.am

@@ -4,6 +4,7 @@ AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
 AM_CPPFLAGS += $(BOOST_INCLUDES)
 AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/lib/dhcpsrv/tests\"
 AM_CPPFLAGS += -DDHCP_DATA_DIR=\"$(abs_top_builddir)/src/lib/dhcpsrv/tests\"
+AM_CPPFLAGS += -DKEA_LFC_BUILD_DIR=\"$(abs_top_builddir)/src/bin/lfc\"
 AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
 
 AM_CXXFLAGS = $(KEA_CXXFLAGS)

+ 31 - 1
src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc

@@ -29,8 +29,9 @@
 
 #include <iostream>
 #include <fstream>
-#include <sstream>
 #include <queue>
+#include <sstream>
+#include <unistd.h>
 
 using namespace std;
 using namespace isc;
@@ -90,6 +91,7 @@ public:
     }
 
     using Memfile_LeaseMgr::lfcCallback;
+    using Memfile_LeaseMgr::lfc_process_;
 };
 
 /// @brief Test fixture class for @c Memfile_LeaseMgr
@@ -105,6 +107,10 @@ public:
         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"));
@@ -212,6 +218,24 @@ public:
         }
     }
 
+    /// @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_;
 
@@ -399,6 +423,10 @@ TEST_F(MemfileLeaseMgrTest, leaseFileCleanup) {
 
     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
@@ -416,11 +444,13 @@ TEST_F(MemfileLeaseMgrTest, getIOServiceExecInterval) {
 
     // 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());