]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[master] Merge in log support for LFC
authorShawn Routhier <sar@isc.org>
Sat, 14 Feb 2015 03:31:39 +0000 (19:31 -0800)
committerShawn Routhier <sar@isc.org>
Sat, 14 Feb 2015 03:31:39 +0000 (19:31 -0800)
Add log support for LFC

Add statistics support in lease files used
by LFC to report stats for leases.

Update memfile tests to check that LFC
did the right thing.

Merge branch 'trac3667'

Conflicts:
ChangeLog
src/lib/util/csv_file.h

1  2 
ChangeLog
src/lib/dhcpsrv/Makefile.am
src/lib/dhcpsrv/csv_lease_file4.cc
src/lib/dhcpsrv/csv_lease_file4.h
src/lib/dhcpsrv/csv_lease_file6.cc
src/lib/dhcpsrv/csv_lease_file6.h
src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc
src/lib/util/csv_file.h

diff --cc ChangeLog
index 9b4ff09be4f2cba26f7c280b80b2932b02f4c924,9fdce0fad9aab311c28aec8e3eedd3dc37238249..3cbb8324f404b3bbb113c6288490f479efd31fcf
+++ b/ChangeLog
@@@ -1,30 -1,10 +1,37 @@@
+ XXX.  [func]          sar
+       A class, LeaseFileStats, has been added to provide simple
+       statistics for use with lease files.  Also added logging
+       to the kea-lfc process per the design.
+       See http://kea.isc.org/wiki/LFCDesign for the design.
+       (Trac #3667, git )
 +891.  [func]          tomek
 +      libdhcpsrv: Allocation Engine now uses statically assigned
 +      addresses when processing DHCPv6 renewals.
 +      (Trac #3677, git 9ce50790c91624937ff2b622e4afff36d5d3cc2d)
 +
 +890.  [func]          marcin
 +      It is now possible to specify whether the DHCPv4 server
 +      should use raw sockets or IP/UDP datagram sockets to
 +      receive and send DHCP messages. The configuration format
 +      has been changed for the selection of interfaces on which
 +      the DHCPv4 and DHCPv6 servers should listen. The
 +      configuration files using an old format are incompatible
 +      with the latest version of Kea.
 +      (Trac #3604, git c726bbc4eae0f576f6791c7490bfba8c30a401d9)
 +
 +889.  [bug]           marcin
 +      Resolved a bug in the DHCPv4 allocation engine whereby the
 +      client could request and obtain an address reserved for
 +      another client.
 +      (Trac #3690, git 1afa4e24b0fcdd6d3a2e596663ce1102ffe2340d)
 +
 +888.  [func]          marcin
 +      DHCPv4 and DHCPv6 servers launch the kea-lfc program, according
 +      to the value of lfc-interval configuration parameter for the
 +      Memfile lease database backend.
 +      (Trac #3669, git c92665ce05d71e9e5cad9a0679018e9e3f7e3be5)
 +
  887.  [func]          sar
        A new process, kea-lfc, has been added. It is meant to
        be periodically executed by the DHCPv4 and DHCPv6 servers
Simple merge
index e48d47e0b4a70fc5f8b41a19df0c176f2d988ff0,2cfb9aaaeec2bff3c5088b4fc19c96915084a11d..d4d60fff69f03dfed4c90cf7b6ac729e4e8aad5a
@@@ -26,7 -26,19 +26,19 @@@ CSVLeaseFile4::CSVLeaseFile4(const std:
  }
  
  void
- CSVLeaseFile4::append(const Lease4& lease) const {
 -CSVLeaseFile4::open() {
++CSVLeaseFile4::open(const bool seek_to_end) {
+     // Call the base class to open the file
 -    CSVFile::open();
++    CSVFile::open(seek_to_end);
+     // and clear any statistics we may have
+     clearStatistics();
+ }
+ void
+ CSVLeaseFile4::append(const Lease4& lease) {
+     // Bump the number of write attempts
+     ++writes_;
      CSVRow row(getColumnCount());
      row.writeAt(getColumnIndex("address"), lease.addr_.toText());
      if (!lease.hwaddr_) {
index 57862f659dcb45cdfe560d87c8a020b468d588f3,dc34760e632639e9f9cac74a279c67a9e9f9ef13..736316209d635862d5d0215296415374dc613d98
@@@ -48,6 -49,15 +49,15 @@@ public
      /// @param filename Name of the lease file.
      CSVLeaseFile4(const std::string& filename);
  
 -    virtual void open();
+     /// @brief Opens a lease file.
+     ///
+     /// This function calls the base class open to do the
+     /// work of opening a file.  It is used to clear any
+     /// statistics associated with any previous use of the file
+     /// While it doesn't throw any exceptions of its own
+     /// the base class may do so.
++    virtual void open(const bool seek_to_end = false);
      /// @brief Appends the lease record to the CSV file.
      ///
      /// This function doesn't throw exceptions itself. In theory, exceptions
index 7157e2e79c1f13f5a10d606916254f30e60bbe59,f0158c0ff26feb419eae42569112ec0b5115ab69..2b1cfd887abdcede3e1670e37fb39fac016426a5
@@@ -27,7 -27,19 +27,19 @@@ CSVLeaseFile6::CSVLeaseFile6(const std:
  }
  
  void
- CSVLeaseFile6::append(const Lease6& lease) const {
 -CSVLeaseFile6::open() {
++CSVLeaseFile6::open(const bool seek_to_end) {
+     // Call the base class to open the file
 -    CSVFile::open();
++    CSVFile::open(seek_to_end);
+     // and clear any statistics we may have
+     clearStatistics();
+ }
+ void
+ CSVLeaseFile6::append(const Lease6& lease) {
+     // Bump the number of write attempts
+     ++writes_;
      CSVRow row(getColumnCount());
      row.writeAt(getColumnIndex("address"), lease.addr_.toText());
      row.writeAt(getColumnIndex("duid"), lease.duid_->toText());
index 105b4e505c17cb591ca12df62e3d5797d9a94a9b,64b402d9af16a3380e43fd681f5378a9ba23090b..2c2a0f6f86e141446ea8411111037e92a9c76ea8
@@@ -47,6 -48,15 +48,15 @@@ public
      /// @param filename Name of the lease file.
      CSVLeaseFile6(const std::string& filename);
  
 -    virtual void open();
+     /// @brief Opens a lease file.
+     ///
+     /// This function calls the base class open to do the
+     /// work of opening a file.  It is used to clear any
+     /// statistics associated with any previous use of the file
+     /// While it doesn't throw any exceptions of its own
+     /// the base class may do so.
++    virtual void open(const bool seek_to_end = false);
      /// @brief Appends the lease record to the CSV file.
      ///
      /// This function doesn't throw exceptions itself. In theory, exceptions
index ad4b34994cd5e8be444d8aa12b976918495124ea,5a99170b18c03d4857df72905176f9007e36b891..13b015caf415b37664a4404ff2bcf24b2ac9b258
@@@ -396,200 -331,6 +396,206 @@@ TEST_F(MemfileLeaseMgrTest, lfcTimerDis
      EXPECT_EQ(0, lease_mgr->getLFCCount());
  }
  
-     /// @todo Replace the following with the checks that the LFC has
-     /// completed successfully, i.e. the leasefile4_0.csv.2 exists
-     /// and it holds the cleaned up lease information.
-     // Until the kea-lfc is implemented and performs the cleanup, we can
-     // only check that the backend has moved the lease file to a lease
-     // file with suffix ".1".
-     LeaseFileIO input_file(getLeaseFilePath("leasefile4_0.csv.1"), false);
 +// This test that the callback function executing the cleanup of the
 +// DHCPv4 lease file works as expected.
 +TEST_F(MemfileLeaseMgrTest, leaseFileCleanup4) {
 +    // This string contains the lease file header, which matches
 +    // the contents of the new file in which no leases have been
 +    // stored.
 +    std::string new_file_contents =
 +        "address,hwaddr,client_id,valid_lifetime,expire,"
 +        "subnet_id,fqdn_fwd,fqdn_rev,hostname\n";
 +
 +    // This string contains the contents of the lease file with exactly
 +    // one lease, but two entries. One of the entries should be removed
 +    // as a result of lease file cleanup.
 +    std::string current_file_contents = new_file_contents +
 +        "192.0.2.2,02:02:02:02:02:02,,200,200,8,1,1,,\n"
 +        "192.0.2.2,02:02:02:02:02:02,,200,800,8,1,1,,\n";
 +    LeaseFileIO current_file(getLeaseFilePath("leasefile4_0.csv"));
 +    current_file.writeFile(current_file_contents);
 +
 +    std::string previous_file_contents = new_file_contents +
 +        "192.0.2.3,03:03:03:03:03:03,,200,200,8,1,1,,\n"
 +        "192.0.2.3,03:03:03:03:03:03,,200,800,8,1,1,,\n";
 +    LeaseFileIO previous_file(getLeaseFilePath("leasefile4_0.csv.2"));
 +    previous_file.writeFile(previous_file_contents);
 +
 +    // Create the backend.
 +    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));
 +
 +    // Try to run the lease file cleanup.
 +    ASSERT_NO_THROW(lease_mgr->lfcCallback());
 +
 +    // The new lease file should have been created and it should contain
 +    // no leases.
 +    ASSERT_TRUE(current_file.exists());
 +    EXPECT_EQ(new_file_contents, current_file.readFile());
 +
 +    // Wait for the LFC process to complete.
 +    ASSERT_TRUE(waitForProcess(*lease_mgr, 2));
 +
 +    // And make sure it has returned an exit status of 0.
 +    EXPECT_EQ(0, lease_mgr->getLFCExitStatus())
 +        << "Executing the LFC process failed: make sure that"
 +        " the kea-lfc program has been compiled.";
 +
 +    // Check if we can still write to the lease file.
 +    std::vector<uint8_t> hwaddr_vec(6);
 +    HWAddrPtr hwaddr(new HWAddr(hwaddr_vec, HTYPE_ETHER));
 +    Lease4Ptr new_lease(new Lease4(IOAddress("192.0.2.45"), hwaddr, 0, 0,
 +                                   100, 50, 60, 0, 1));
 +    ASSERT_NO_THROW(lease_mgr->addLease(new_lease));
 +
 +    std::string updated_file_contents = new_file_contents +
 +        "192.0.2.45,00:00:00:00:00:00,,100,100,1,0,0,\n";
 +    EXPECT_EQ(updated_file_contents, current_file.readFile());
 +
-     // And this file should contain the contents of the original file.
-     EXPECT_EQ(current_file_contents, input_file.readFile());
++    // This string contains the contents of the lease file we
++    // expect after the LFC run.  It has two leases with one
++    // entry each.
++    std::string result_file_contents = new_file_contents +
++        "192.0.2.2,02:02:02:02:02:02,,200,800,8,1,1,\n"
++        "192.0.2.3,03:03:03:03:03:03,,200,800,8,1,1,\n";
++
++    // The LFC should have created a file with the two leases and moved it
++    // to leasefile4_0.csv.2
++    LeaseFileIO input_file(getLeaseFilePath("leasefile4_0.csv.2"), false);
 +    ASSERT_TRUE(input_file.exists());
-     /// @todo Replace the following with the checks that the LFC has
-     /// completed successfully, i.e. the leasefile6_0.csv.2 exists
-     /// and it holds the cleaned up lease information.
++    // And this file should contain the contents of the result file.
++    EXPECT_EQ(result_file_contents, input_file.readFile());
 +}
 +
 +// This test that the callback function executing the cleanup of the
 +// DHCPv6 lease file works as expected.
 +TEST_F(MemfileLeaseMgrTest, leaseFileCleanup6) {
 +    // This string contains the lease file header, which matches
 +    // the contents of the new file in which no leases have been
 +    // stored.
 +    std::string new_file_contents =
 +        "address,duid,valid_lifetime,expire,subnet_id,"
 +        "pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,"
 +        "fqdn_rev,hostname,hwaddr\n";
 +
 +    // This string contains the contents of the lease file with exactly
 +    // one lease, but two entries. One of the entries should be removed
 +    // as a result of lease file cleanup.
 +    std::string current_file_contents = new_file_contents +
 +        "2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,200,200,"
 +        "8,100,0,7,0,1,1,,\n"
 +        "2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,200,800,"
 +        "8,100,0,7,0,1,1,,\n";
 +    LeaseFileIO current_file(getLeaseFilePath("leasefile6_0.csv"));
 +    current_file.writeFile(current_file_contents);
 +
 +    std::string previous_file_contents = new_file_contents +
 +        "2001:db8:1::2,01:01:01:01:01:01:01:01:01:01:01:01:01,200,200,"
 +        "8,100,0,7,0,1,1,,\n"
 +        "2001:db8:1::2,01:01:01:01:01:01:01:01:01:01:01:01:01,200,800,"
 +        "8,100,0,7,0,1,1,,\n";
 +    LeaseFileIO previous_file(getLeaseFilePath("leasefile6_0.csv.2"));
 +    previous_file.writeFile(previous_file_contents);
 +
 +    // Create the backend.
 +    LeaseMgr::ParameterMap pmap;
 +    pmap["type"] = "memfile";
 +    pmap["universe"] = "6";
 +    pmap["name"] = getLeaseFilePath("leasefile6_0.csv");
 +    pmap["lfc-interval"] = "1";
 +    boost::scoped_ptr<NakedMemfileLeaseMgr> lease_mgr(new NakedMemfileLeaseMgr(pmap));
 +
 +    // Try to run the lease file cleanup.
 +    ASSERT_NO_THROW(lease_mgr->lfcCallback());
 +
 +    // The new lease file should have been created and it should contain
 +    // no leases.
 +    ASSERT_TRUE(current_file.exists());
 +    EXPECT_EQ(new_file_contents, current_file.readFile());
 +
 +    // Wait for the LFC process to complete.
 +    ASSERT_TRUE(waitForProcess(*lease_mgr, 2));
 +
 +    // And make sure it has returned an exit status of 0.
 +    EXPECT_EQ(0, lease_mgr->getLFCExitStatus())
 +        << "Executing the LFC process failed: make sure that"
 +        " the kea-lfc program has been compiled.";
 +
 +
 +    // Check if we can still write to the lease file.
 +    std::vector<uint8_t> duid_vec(13);
 +    DuidPtr duid(new DUID(duid_vec));
 +    Lease6Ptr new_lease(new Lease6(Lease::TYPE_NA, IOAddress("3000::1"),duid,
 +                                   123, 300, 400, 100, 300, 2));
 +    new_lease->cltt_ = 0;
 +    ASSERT_NO_THROW(lease_mgr->addLease(new_lease));
 +
 +    std::string update_file_contents = new_file_contents +
 +        "3000::1,00:00:00:00:00:00:00:00:00:00:00:00:00,400,"
 +        "400,2,300,0,123,128,0,0,,\n";
 +    EXPECT_EQ(update_file_contents, current_file.readFile());
 +
-     // Until the kea-lfc is implemented and performs the cleanup, we can
-     // only check that the backend has moved the lease file to a lease
-     // file with suffix ".1".
-     LeaseFileIO input_file(getLeaseFilePath("leasefile6_0.csv.1"), false);
++    // This string contains the contents of the lease file we
++    // expect after the LFC run.  It has two leases with one
++    // entry each.
++    std::string result_file_contents = new_file_contents +
++        "2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,200,800,"
++        "8,100,0,7,0,1,1,,\n"
++        "2001:db8:1::2,01:01:01:01:01:01:01:01:01:01:01:01:01,200,800,"
++        "8,100,0,7,0,1,1,,\n";
 +
-     // And this file should contain the contents of the original file.
-     EXPECT_EQ(current_file_contents, input_file.readFile());
++    // The LFC should have created a file with the two leases and moved it
++    // to leasefile6_0.csv.2
++    LeaseFileIO input_file(getLeaseFilePath("leasefile6_0.csv.2"), false);
 +    ASSERT_TRUE(input_file.exists());
++    // And this file should contain the contents of the result file.
++    EXPECT_EQ(result_file_contents, input_file.readFile());
 +}
 +
 +// This test verifies that EXIT_FAILURE status code is returned when
 +// the LFC process fails to start.
 +TEST_F(MemfileLeaseMgrTest, leaseFileCleanupStartFail) {
 +    // This string contains the lease file header, which matches
 +    // the contents of the new file in which no leases have been
 +    // stored.
 +    std::string new_file_contents =
 +        "address,hwaddr,client_id,valid_lifetime,expire,"
 +        "subnet_id,fqdn_fwd,fqdn_rev,hostname\n";
 +
 +    // Create the lease file to be used by the backend.
 +    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);
 +
 +    // Specify invalid path to the kea-lfc executable. This should result
 +    // in failure status code returned by the child process.
 +    setenv("KEA_LFC_EXECUTABLE", "foobar", 1);
 +
 +    // Create the backend.
 +    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));
 +
 +    // Try to run the lease file cleanup.
 +    ASSERT_NO_THROW(lease_mgr->lfcCallback());
 +
 +    // Wait for the LFC process to complete.
 +    ASSERT_TRUE(waitForProcess(*lease_mgr, 2));
 +
 +    // And make sure it has returned an error.
 +    EXPECT_EQ(EXIT_FAILURE, lease_mgr->getLFCExitStatus())
 +        << "Executing the LFC process failed: make sure that"
 +        " the kea-lfc program has been compiled.";
 +}
 +
  // 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.
index 3296349d84cfa9393b78fa35713fcf5ffbb95dcc,4f900a5f36a35eed973638938902d17176d8f5e3..d2474cb7fdc4fd1c7c76db3bdb2b7871578e49a8
@@@ -385,17 -385,12 +385,18 @@@ public
      /// greater than 0. If the file doesn't exist or has size of 0, the
      /// file is recreated. If the existing file has been opened, the header
      /// is parsed and column names are initialized in the @c CSVFile object.
 -    /// The data pointer in the file is set to the beginning of the first
 -    /// row. In order to retrieve the row contents the @c next function should
 -    /// be called.
 +    /// By default, the data pointer in the file is set to the beginning of
 +    /// the first row. In order to retrieve the row contents the @c next
 +    /// function should be called. If a @c seek_to_end parameter is set to
 +    /// true, the file will be opened and the interal pointer will be set
 +    /// to the end of file.
 +    ///
 +    /// @param seek_to_end A boolean value which indicates if the intput and
 +    /// output file pointer should be set at the end of file.
      ///
      /// @throw CSVFileError when IO operation fails.
-     void open(const bool seek_to_end = false);
 -    virtual void open();
++
++    virtual void open(const bool seek_to_end = false);
  
      /// @brief Creates a new CSV file.
      ///