Browse Source

[3669] Memfile backend rotates the lease file before running LFC.

Marcin Siodelski 10 years ago
parent
commit
8b3b3f6cf0

+ 53 - 3
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 <cstdio>
 #include <iostream>
 #include <sstream>
 
@@ -28,6 +29,7 @@ const uint32_t MAX_LEASE_ERRORS = 100;
 } // end of anonymous namespace
 
 using namespace isc::dhcp;
+using namespace isc::util;
 
 Memfile_LeaseMgr::Memfile_LeaseMgr(const ParameterMap& parameters)
     : LeaseMgr(parameters), lfc_timer_(*getIOService()) {
@@ -51,7 +53,7 @@ Memfile_LeaseMgr::Memfile_LeaseMgr(const ParameterMap& parameters)
     // issue a warning. It is ok not to write leases to disk when
     // doing testing, but it should not be done in normal server
     // operation.
-    if (!persistLeases(V4) && !persistLeases(V6)) {
+   if (!persistLeases(V4) && !persistLeases(V6)) {
         LOG_WARN(dhcpsrv_logger, DHCPSRV_MEMFILE_NO_STORAGE);
 
     } else  {
@@ -418,6 +420,32 @@ Memfile_LeaseMgr::rollback() {
               DHCPSRV_MEMFILE_ROLLBACK);
 }
 
+std::string
+Memfile_LeaseMgr::appendSuffix(const std::string& file_name,
+                               const LFCFileType& file_type) {
+    std::string name(file_name);
+    switch (file_type) {
+    case FILE_INPUT:
+        name += ".1";
+        break;
+    case FILE_PREVIOUS:
+        name += ".2";
+        break;
+    case FILE_OUTPUT:
+        name += ".output";
+        break;
+    case FILE_FINISH:
+        name += ".completed";
+        break;
+    default:
+        // Do not append any suffix for the FILE_CURRENT.
+        ;
+    }
+
+    return (name);
+}
+
+
 uint32_t
 Memfile_LeaseMgr::getIOServiceExecInterval() const {
     return (static_cast<uint32_t>(lfc_timer_.getInterval() / 1000));
@@ -512,6 +540,28 @@ 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.
+    if (lease_file4_) {
+        leaseFileCleanup(lease_file4_);
+
+    } else if (lease_file6_) {
+        leaseFileCleanup(lease_file6_);
+
+    }
+}
+
+template<typename LeaseFileType>
+void Memfile_LeaseMgr::
+leaseFileCleanup(boost::shared_ptr<LeaseFileType>& lease_file) {
+    CSVFile lease_file_copy(appendSuffix(lease_file->getFilename(), FILE_INPUT));
+    if (!lease_file_copy.exists()) {
+        lease_file->close();
+        rename(lease_file->getFilename().c_str(),
+               lease_file_copy.getFilename().c_str());
+        lease_file.reset(new LeaseFileType(lease_file->getFilename()));
+        lease_file->open();
+    }
 }
 
 template<typename LeaseObjectType, typename LeaseFileType, typename StorageType>
@@ -530,13 +580,13 @@ loadLeasesFromFiles(const std::string& filename,
     } else {
         // If the leasefile.completed doesn't exist, let's load the leases
         // from leasefile.2 and leasefile.1, if they exist.
-        lease_file.reset(new LeaseFileType(std::string(filename + ".2")));
+        lease_file.reset(new LeaseFileType(appendSuffix(filename, FILE_PREVIOUS)));
         if (lease_file->exists()) {
             LeaseFileLoader::load<LeaseObjectType>(*lease_file, storage,
                                                    MAX_LEASE_ERRORS);
         }
 
-        lease_file.reset(new LeaseFileType(std::string(filename + ".1")));
+        lease_file.reset(new LeaseFileType(appendSuffix(filename, FILE_INPUT)));
         if (lease_file->exists()) {
             LeaseFileLoader::load<LeaseObjectType>(*lease_file, storage,
                                                    MAX_LEASE_ERRORS);

+ 34 - 1
src/lib/dhcpsrv/memfile_lease_mgr.h

@@ -112,6 +112,18 @@ public:
         V6
     };
 
+    /// @brief Types of the lease files used by the Lease File Cleanup.
+    ///
+    /// This enumeration is used by a method which appends the appropriate
+    /// suffix to the lease file name.
+    enum LFCFileType {
+        FILE_CURRENT,
+        FILE_INPUT,
+        FILE_PREVIOUS,
+        FILE_OUTPUT,
+        FILE_FINISH
+    };
+
     /// @brief The sole lease manager constructor
     ///
     /// dbconfig is a generic way of passing parameters. Parameters
@@ -320,6 +332,24 @@ public:
     /// support transactions, this is a no-op.
     virtual void rollback();
 
+    /// @brief Appends appropriate suffix to the file name.
+    ///
+    /// The suffix is selected using the LFC file type specified as a
+    /// parameter. Each file type uses a unique suffix or no suffix:
+    /// - Current File: no suffix
+    /// - Lease File Copy or Input File: ".1"
+    /// - Previous File: ".2"
+    /// - LFC Output File: ".output"
+    /// - LFC Finish File: ".completed"
+    ///
+    /// See http://kea.isc.org/wiki/LFCDesign for details.
+    ///
+    /// @param file_name A base file name to which suffix is appended.
+    /// @param file_type An LFC file type.
+    /// @return A lease file name with a suffix appended.
+    static std::string appendSuffix(const std::string& file_name,
+                                    const LFCFileType& file_type);
+
     /// @brief Returns the interval at which the @c IOService events should
     /// be released.
     ///
@@ -359,7 +389,7 @@ public:
     /// server shut down.
     bool persistLeases(Universe u) const;
 
-private:
+protected:
 
     /// @brief A callback function triggering Lease File Cleanup.
     ///
@@ -397,6 +427,9 @@ private:
     /// argument to this function.
     std::string initLeaseFilePath(Universe u);
 
+    template<typename LeaseFileType>
+    void leaseFileCleanup(boost::shared_ptr<LeaseFileType>& lease_file);
+
     /// @brief Load leases from the persistent storage.
     ///
     /// This method loads DHCPv4 or DHCPv6 leases from lease files in the

+ 9 - 5
src/lib/dhcpsrv/tests/lease_file_io.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
@@ -20,13 +20,17 @@ namespace isc {
 namespace dhcp {
 namespace test {
 
-LeaseFileIO::LeaseFileIO(const std::string& filename)
-    : testfile_(filename) {
-    removeFile();
+LeaseFileIO::LeaseFileIO(const std::string& filename, const bool recreate)
+    : testfile_(filename), recreate_(recreate)  {
+    if (recreate_) {
+        removeFile();
+    }
 }
 
 LeaseFileIO::~LeaseFileIO() {
-    removeFile();
+    if (recreate_) {
+        removeFile();
+    }
 }
 
 bool

+ 7 - 1
src/lib/dhcpsrv/tests/lease_file_io.h

@@ -32,7 +32,9 @@ public:
     /// @brief Constructor
     ///
     /// @param filename Abolsute path to the file.
-    LeaseFileIO(const std::string& filename);
+    /// @param recreate A boolean flag indicating if the new file should
+    /// be created, even if one exists.
+    LeaseFileIO(const std::string& filename, const bool recreate = true);
 
     /// @brief Destructor.
     ~LeaseFileIO();
@@ -56,6 +58,10 @@ public:
     /// @brief Absolute path to the file used in the tests.
     std::string testfile_;
 
+    /// @brief Indicates if the file should be recreated during object
+    /// construction and removed during destruction.
+    bool recreate_;
+
 };
 
 }

+ 73 - 3
src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc

@@ -30,6 +30,7 @@
 #include <iostream>
 #include <fstream>
 #include <sstream>
+#include <queue>
 
 using namespace std;
 using namespace isc;
@@ -77,6 +78,20 @@ private:
 
 };
 
+/// @brief A derivation of the lease manager exposing protected methods.
+class NakedMemfileLeaseMgr : public Memfile_LeaseMgr {
+public:
+
+    /// @brief Constructor.
+    ///
+    /// Creates instance of the lease manager.
+    NakedMemfileLeaseMgr(const ParameterMap& parameters)
+        : Memfile_LeaseMgr(parameters) {
+    }
+
+    using Memfile_LeaseMgr::lfcCallback;
+};
+
 /// @brief Test fixture class for @c Memfile_LeaseMgr
 class MemfileLeaseMgrTest : public GenericLeaseMgrTest {
 public:
@@ -90,9 +105,9 @@ public:
         io_service_(),
         fail_on_callback_(false) {
 
-        // Make sure there are no dangling files after previous tests.
-        io4_.removeFile();
-        io6_.removeFile();
+        // Remove lease files and products of Lease File Cleanup.
+        removeFiles(getLeaseFilePath("leasefile4_0.csv"));
+        removeFiles(getLeaseFilePath("leasefile6_0.csv"));
     }
 
     /// @brief Reopens the connection to the backend.
@@ -112,6 +127,30 @@ public:
     /// destroys lease manager backend.
     virtual ~MemfileLeaseMgrTest() {
         LeaseMgrFactory::destroy();
+        // Remove lease files and products of Lease File Cleanup.
+        removeFiles(getLeaseFilePath("leasefile4_0.csv"));
+        removeFiles(getLeaseFilePath("leasefile6_0.csv"));
+    }
+
+
+    /// @brief Remove files being products of Lease File Cleanup.
+    ///
+    /// @param base_name Path to the lease file name. This file is removed
+    /// and all files which names are crated from this name (having specific
+    /// suffixes used by Lease File Cleanup mechanism).
+    void removeFiles(const std::string& base_name) const {
+        // Generate suffixes and append them to the base name. The
+        // resulting file names are the ones that may exist as a
+        // result of LFC.
+        for (int i = static_cast<int>(Memfile_LeaseMgr::FILE_CURRENT);
+             i <= static_cast<int>(Memfile_LeaseMgr::FILE_FINISH);
+             ++i) {
+            Memfile_LeaseMgr::LFCFileType type = static_cast<
+                Memfile_LeaseMgr::LFCFileType>(i);
+            std::string suffix = Memfile_LeaseMgr::appendSuffix(base_name, type);
+            LeaseFileIO io(Memfile_LeaseMgr::appendSuffix(base_name, type));
+            io.removeFile();
+        }
     }
 
     /// @brief Return path to the lease file used by unit tests.
@@ -331,6 +370,37 @@ TEST_F(MemfileLeaseMgrTest, lfcTimerDisabled) {
     EXPECT_EQ(0, lease_mgr->getLFCCount());
 }
 
+// This test that the callback function performing a Lease File Cleanup
+// works as expected.
+TEST_F(MemfileLeaseMgrTest, leaseFileCleanup) {
+    std::string new_file_contents =
+        "address,hwaddr,client_id,valid_lifetime,expire,"
+        "subnet_id,fqdn_fwd,fqdn_rev,hostname\n";
+
+    std::string current_file_contents = new_file_contents +
+        "192.0.2.2,02:02:02:02:02:02,,200,200,8,1,1,,\n";
+    LeaseFileIO current_file(getLeaseFilePath("leasefile4_0.csv"));
+    current_file.writeFile(current_file_contents);
+
+    LeaseMgr::ParameterMap pmap;
+    pmap["type"] = "memfile";
+    pmap["universe"] = "4";
+    pmap["name"] = getLeaseFilePath("leasefile4_0.csv");
+    pmap["lfc-interval"] = "1";
+
+    boost::scoped_ptr<NakedMemfileLeaseMgr>
+        lease_mgr(new NakedMemfileLeaseMgr(pmap));
+
+    ASSERT_NO_THROW(lease_mgr->lfcCallback());
+
+    LeaseFileIO input_file(getLeaseFilePath("leasefile4_0.csv.1"), false);
+    ASSERT_TRUE(input_file.exists());
+    EXPECT_EQ(current_file_contents, input_file.readFile());
+
+    ASSERT_TRUE(current_file.exists());
+    EXPECT_EQ(new_file_contents, current_file.readFile());
+}
+
 // Test that the backend returns a correct value of the interval
 // at which the IOService must be executed to run the handlers
 // for the installed timers.