]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[5585] Initial LeaseQueryStats, LeaseMgr, and MemfileLeaseMgr extensions
authorThomas Markwalder <tmark@isc.org>
Wed, 11 Apr 2018 18:56:44 +0000 (14:56 -0400)
committerThomas Markwalder <tmark@isc.org>
Wed, 11 Apr 2018 18:56:44 +0000 (14:56 -0400)
    MemfileLeaseMgr unit tests fail for subnet and range query variants, not yet
    implemented

src/lib/dhcpsrv/lease_mgr.*
    LeaseStatsQuery
    - Added SelectMode enum typedef
    - Added instance members: first_subnet_id_, last_subnet_id_, and select_mode_
    - Added constructors for single subnet and subnet range queries

    LeaseMgr
    Added virtual start query variants:
    - startSubnetLeaseStatsQuery4(SubnetID subnet_id);
    - startSubnetRangeLeaseStatsQuery4(SubnetID first, SubnetID last);
    - startSubnetLeaseStatsQuery6(SubnetID subnet_id);
    - startSubnetRangeLeaseStatsQuery6(SubnetID first, SubnetID last);

src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.*
    GenericLeaseMgrTest
    - Added checkQueryAgainstRowSet()
    - Added testLeaseStatsQuery4()

src/lib/dhcpsrv/tests/lease_mgr_unittest.cc
    Added LeaseStatsQuery ctor tests
    - TEST (LeaseStatsQueryTest, defaultCtor)
    - TEST (LeaseStatsQueryTest, singleSubnetCtor)
    - TEST (LeaseStatsQueryTest, subnetRangeCtor)

src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc
    TEST_F(MemfileLeaseMgrTest, leaseStatsQuery4) {

src/lib/dhcpsrv/lease_mgr.cc
src/lib/dhcpsrv/lease_mgr.h
src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc
src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.h
src/lib/dhcpsrv/tests/lease_mgr_unittest.cc
src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc

index 205e565985475fa5e66e39128d423b8c67dc2a67..2ea733258d1142bafaf1be9fe8b6fdd4114e9b91 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2018 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -111,11 +111,52 @@ LeaseMgr::recountLeaseStats4() {
     }
 }
 
+LeaseStatsQuery::LeaseStatsQuery()
+    : first_subnet_id_(0), last_subnet_id_(0), select_mode_(ALL_SUBNETS) {
+}
+
+LeaseStatsQuery::LeaseStatsQuery(SubnetID subnet_id)
+    : first_subnet_id_(subnet_id), last_subnet_id_(0),
+    select_mode_(SINGLE_SUBNET) {
+        if (first_subnet_id_ == 0) {
+            isc_throw(BadValue, "LeaseStatsQuery: subnet_id_ must be > 0");
+        }
+}
+
+LeaseStatsQuery::LeaseStatsQuery(SubnetID first, SubnetID last)
+    : first_subnet_id_(first), last_subnet_id_(last),
+    select_mode_(SUBNET_RANGE) {
+
+    if (first_subnet_id_ == 0) {
+        isc_throw(BadValue, "LeaseStatsQuery: first_subnet_id_ must be > 0");
+    }
+
+    if (last_subnet_id_ == 0) {
+        isc_throw(BadValue, "LeaseStatsQuery: last_subnet_id_ must be > 0");
+    }
+
+    if (last_subnet_id_ <= first_subnet_id_) {
+        isc_throw(BadValue,
+                  "LeaseStatsQuery: last_subnet_id_must be > first_subnet_id_");
+    }
+}
+
 LeaseStatsQueryPtr
 LeaseMgr::startLeaseStatsQuery4() {
     return(LeaseStatsQueryPtr());
 }
 
+LeaseStatsQueryPtr
+LeaseMgr::startSubnetLeaseStatsQuery4(SubnetID /* subnet_id */) {
+    return(LeaseStatsQueryPtr());
+}
+
+LeaseStatsQueryPtr
+LeaseMgr::startSubnetRangeLeaseStatsQuery4(SubnetID /* first */,
+                                           SubnetID  /* last */) {
+    return(LeaseStatsQueryPtr());
+}
+
 bool
 LeaseStatsQuery::getNextRow(LeaseStatsRow& /*row*/) {
     return (false);
@@ -218,6 +259,17 @@ LeaseMgr::startLeaseStatsQuery6() {
     return(LeaseStatsQueryPtr());
 }
 
+LeaseStatsQueryPtr
+LeaseMgr::startSubnetLeaseStatsQuery6(SubnetID /* subnet_id */) {
+    return(LeaseStatsQueryPtr());
+}
+
+LeaseStatsQueryPtr
+LeaseMgr::startSubnetRangeLeaseStatsQuery6(SubnetID /* first */,
+                                           SubnetID /* last */) {
+    return(LeaseStatsQueryPtr());
+}
+
 std::string
 LeaseMgr::getDBVersion() {
     isc_throw(NotImplemented, "LeaseMgr::getDBVersion() called");
index f0fd431cc4e23d0cbbd7bf9c86998692690a81e9..d4062e22ce099f4312fdef4a876078c80aa562e0 100644 (file)
@@ -114,7 +114,7 @@ struct LeaseStatsRow {
 
         if (subnet_id_ == rhs.subnet_id_ &&
             lease_type_ == rhs.lease_type_ &&
-            lease_state_ < rhs.lease_state_) {      
+            lease_state_ < rhs.lease_state_) {
                 return (true);
         }
 
@@ -138,8 +138,34 @@ struct LeaseStatsRow {
 /// instances. The rows must be accessible in ascending order by subnet id.
 class LeaseStatsQuery {
 public:
+    /// @brief Defines the types of selection criteria supported
+    typedef enum {
+        ALL_SUBNETS,
+        SINGLE_SUBNET,
+        SUBNET_RANGE
+    } SelectMode;
+
     /// @brief Default constructor
-    LeaseStatsQuery() {};
+    /// The query created will return statistics for all subnets
+    LeaseStatsQuery();
+
+    /// @brief Constructor to query for a single subnet's stats
+    ///
+    /// The query created will return statistics for a single subnet
+    ///
+    /// @param subnet_id id of the subnet for which stats are desired
+    /// @throw BadValue if sunbet_id given is 0.
+    LeaseStatsQuery(SubnetID subnet_id);
+
+    /// @brief Constructor to query for the stats for a range of subnets
+    ///
+    /// The query created will return statistics for the inclusive range of
+    /// subnets described by first and last sunbet IDs.
+    ///
+    /// @param first first subnet in the range of subnets
+    /// @param last last subnet in the range of subnets
+    /// @throw BadValue if either value given is 0 or if last <= first.
+    LeaseStatsQuery(SubnetID first, SubnetID last);
 
     /// @brief virtual destructor
     virtual ~LeaseStatsQuery() {};
@@ -158,6 +184,27 @@ public:
     /// @return True if a row was fetched, false if there are no
     /// more rows.
     virtual bool getNextRow(LeaseStatsRow& row);
+
+    /// @brief Returns the value of first subnet ID specified (or zero)
+    SubnetID getFirstSubnetID() const { return first_subnet_id_; };
+
+    /// @brief Returns the value of last subnet ID specified (or zero)
+    SubnetID getLastSubnetID() const { return last_subnet_id_; };
+
+    /// @brief Returns the selection criteria mode
+    /// The value returned is based upon the constructor variant used
+    /// and it indicates which query variant will be executed.
+    SelectMode getSelectMode() const { return select_mode_;  };
+
+private:
+    /// @brief First (or only) subnet_id in the selection criteria
+    SubnetID first_subnet_id_;
+
+    /// @brief Last subnet_id in the selection criteria when a range is given
+    SubnetID last_subnet_id_;
+
+    /// @brief Indicates the type of selection criteria specified
+    SelectMode select_mode_;
 };
 
 /// @brief Defines a pointer to a LeaseStatsQuery.
@@ -464,16 +511,42 @@ public:
     /// adding to the appropriate global statistic.
     void recountLeaseStats4();
 
-    /// @brief Virtual method which creates and runs the IPv4 lease stats query
+    /// @brief Creates and runs the IPv4 lease stats query for all subnets
     ///
     /// LeaseMgr derivations implement this method such that it creates and
     /// returns an instance of an LeaseStatsQuery whose result set has been
-    /// populated with up to date IPv4 lease statistical data.  Each row of the
-    /// result set is an LeaseStatRow which ordered ascending by subnet ID.
+    /// populated with up to date IPv4 lease statistical data for all subnets.
+    /// Each row of the result set is an LeaseStatRow which ordered ascending
+    /// by subnet ID.
     ///
     /// @return A populated LeaseStatsQuery
     virtual LeaseStatsQueryPtr startLeaseStatsQuery4();
 
+    /// @brief Creates and runs the IPv4 lease stats query for a single subnet
+    ///
+    /// LeaseMgr derivations implement this method such that it creates and
+    /// returns an instance of an LeaseStatsQuery whose result set has been
+    /// populated with up to date IPv4 lease statistical data for a single
+    /// subnet.  Each row of the result set is an LeaseStatRow.
+    ///
+    /// @param subnet_id id of the subnet for which stats are desired
+    /// @return A populated LeaseStatsQuery
+    virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery4(SubnetID subnet_id);
+
+    /// @brief Creates and runs the IPv4 lease stats query for a single subnet
+    ///
+    /// LeaseMgr derivations implement this method such that it creates and
+    /// returns an instance of an LeaseStatsQuery whose result set has been
+    /// populated with up to date IPv4 lease statistical data for an inclusive
+    /// range of subnets. Each row of the result set is an LeaseStatRow which
+    /// ordered ascending by subnet ID.
+    ///
+    /// @param first first subnet in the range of subnets
+    /// @param last last subnet in the range of subnets
+    /// @return A populated LeaseStatsQuery
+    virtual LeaseStatsQueryPtr startSubnetRangeLeaseStatsQuery4(SubnetID first,
+                                                                SubnetID last);
+
     /// @brief Recalculates per-subnet and global stats for IPv6 leases
     ///
     /// This method recalculates the following statistics:
@@ -495,16 +568,42 @@ public:
     /// per subnet and adding to the appropriate global statistic.
     void recountLeaseStats6();
 
-    /// @brief Virtual method which creates and runs the IPv6 lease stats query
+    /// @brief Creates and runs the IPv6 lease stats query for all subnets
     ///
     /// LeaseMgr derivations implement this method such that it creates and
     /// returns an instance of an LeaseStatsQuery whose result set has been
-    /// populated with up to date IPv6 lease statistical data.  Each row of the
-    /// result set is an LeaseStatRow which ordered ascending by subnet ID.
+    /// populated with up to date IPv6 lease statistical data for all subnets.
+    /// Each row of the result set is an LeaseStatRow which ordered ascending
+    /// by subnet ID.
     ///
     /// @return A populated LeaseStatsQuery
     virtual LeaseStatsQueryPtr startLeaseStatsQuery6();
 
+    /// @brief Creates and runs the IPv6 lease stats query for a single subnet
+    ///
+    /// LeaseMgr derivations implement this method such that it creates and
+    /// returns an instance of an LeaseStatsQuery whose result set has been
+    /// populated with up to date IPv6 lease statistical data for a single
+    /// subnet.  Each row of the result set is an LeaseStatRow.
+    ///
+    /// @param subnet_id id of the subnet for which stats are desired
+    /// @return A populated LeaseStatsQuery
+    virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery6(SubnetID subnet_id);
+
+    /// @brief Creates and runs the IPv6 lease stats query for a single subnet
+    ///
+    /// LeaseMgr derivations implement this method such that it creates and
+    /// returns an instance of an LeaseStatsQuery whose result set has been
+    /// populated with up to date IPv6 lease statistical data for an inclusive
+    /// range of subnets. Each row of the result set is an LeaseStatRow which
+    /// ordered ascending by subnet ID.
+    ///
+    /// @param first first subnet in the range of subnets
+    /// @param last last subnet in the range of subnets
+    /// @return A populated LeaseStatsQuery
+    virtual LeaseStatsQueryPtr startSubnetRangeLeaseStatsQuery6(SubnetID first,
+                                                                SubnetID last);
+
     /// @brief Virtual method which removes specified leases.
     ///
     /// This rather dangerous method is able to remove all leases from specified
index f0a9f0b306bf79c34e33de14980aa7cd35ec9031..41950543d7d02cd205327bbadc87485f43273bcc 100644 (file)
@@ -2857,6 +2857,112 @@ LeaseMgrDbLostCallbackTest::testDbLostCallback() {
     EXPECT_TRUE(callback_called_);
 }
 
+void
+GenericLeaseMgrTest::checkQueryAgainstRowSet(LeaseStatsQueryPtr query,
+                                             RowSet& expected_rows) {
+    ASSERT_TRUE(query) << "query is null";
+
+    int rows_matched = 0;
+    LeaseStatsRow row;
+    while (query->getNextRow(row)) {
+        auto found_row = expected_rows.find(row);
+        if (found_row == expected_rows.end()) {
+            ADD_FAILURE() << "query row not in expected set"
+                << " id: " << row.subnet_id_
+                << " type: " << row.lease_type_
+                << " state: " << row.lease_state_
+                << " count: " << row.state_count_;
+        } else {
+           ++rows_matched;
+        }
+    }
+
+    ASSERT_EQ(rows_matched, expected_rows.size()) << "rows mismatched";
+}
+
+void
+GenericLeaseMgrTest::testLeaseStatsQuery4() {
+    // Create three subnets.
+    int num_subnets = 3;
+    CfgSubnets4Ptr cfg = CfgMgr::instance().getStagingCfg()->getCfgSubnets4();
+    Subnet4Ptr subnet;
+    Pool4Ptr pool;
+
+    subnet.reset(new Subnet4(IOAddress("192.0.1.0"), 24, 1, 2, 3, 1));
+    pool.reset(new Pool4(IOAddress("192.0.1.0"), 24));
+    subnet->addPool(pool);
+    cfg->add(subnet);
+
+    subnet.reset(new Subnet4(IOAddress("192.0.2.0"), 24, 1, 2, 3, 2));
+    pool.reset(new Pool4(IOAddress("192.0.2.0"), 24));
+    subnet->addPool(pool);
+    cfg->add(subnet);
+
+    subnet.reset(new Subnet4(IOAddress("192.0.3.0"), 24, 1, 2, 3, 3));
+    pool.reset(new Pool4(IOAddress("192.0.3.0"), 24));
+    subnet->addPool(pool);
+    cfg->add(subnet);
+
+    ASSERT_NO_THROW(CfgMgr::instance().commit());
+
+    // Now let's insert some leases into subnet 1.
+    // Two leases in  the default state, i.e. assigned.
+    // One lease in declined state.
+    // One lease in the expired state.
+    int subnet_id = 1;
+    makeLease4("192.0.1.1", subnet_id);
+    makeLease4("192.0.1.2", subnet_id, Lease::STATE_DECLINED);
+    makeLease4("192.0.1.3", subnet_id, Lease::STATE_EXPIRED_RECLAIMED);
+    makeLease4("192.0.1.4", subnet_id);
+
+    // Now let's add leases to subnet 2.
+    // One declined lease.
+    subnet_id = 2;
+    makeLease4("192.0.2.2", subnet_id, Lease::STATE_DECLINED);
+
+    // Now add leases to subnet 3
+    // Two leases in default state, i.e. assigned.
+    // One declined lease.
+    subnet_id = 3;
+    makeLease4("192.0.3.1", subnet_id);
+    makeLease4("192.0.3.2", subnet_id);
+    makeLease4("192.0.3.3", subnet_id, Lease::STATE_DECLINED);
+
+    LeaseStatsQueryPtr query;
+    RowSet expected_rows;
+
+    // Test a non-matching single subnet
+    ASSERT_NO_THROW(query = lmptr_->startSubnetLeaseStatsQuery4(777));
+    checkQueryAgainstRowSet(query, expected_rows);
+
+    // Test a single subnet
+    // Add expected row for Subnet 2
+    expected_rows.insert(LeaseStatsRow(2, Lease::STATE_DEFAULT, 0));
+    expected_rows.insert(LeaseStatsRow(2, Lease::STATE_DECLINED, 1));
+    // Start the query
+    ASSERT_NO_THROW(query = lmptr_->startSubnetLeaseStatsQuery4(2));
+    // Verify contents
+    checkQueryAgainstRowSet(query, expected_rows);
+
+    // Test a range of subnets
+    // Add expected rows for Subnet 3
+    expected_rows.insert(LeaseStatsRow(3, Lease::STATE_DEFAULT, 2));
+    expected_rows.insert(LeaseStatsRow(3, Lease::STATE_DECLINED, 1));
+    // Start the query
+    ASSERT_NO_THROW(query = lmptr_->startSubnetRangeLeaseStatsQuery4(2,3));
+    // Verify contents
+    checkQueryAgainstRowSet(query, expected_rows);
+
+    // Test all subnets
+    // Add expected rows for Subnet 1
+    expected_rows.insert(LeaseStatsRow(1, Lease::STATE_DEFAULT, 2));
+    expected_rows.insert(LeaseStatsRow(1, Lease::STATE_DECLINED, 1));
+    // Start the query
+    ASSERT_NO_THROW(query = lmptr_->startLeaseStatsQuery4());
+    // Verify contents
+    checkQueryAgainstRowSet(query, expected_rows);
+}
+
 }; // namespace test
 }; // namespace dhcp
 }; // namespace isc
index cd62825eb34e9aa5d5fbe9d8eaf9123bacd878c4..2d78dd8440710a7c023d13848455802edfdf81d5 100644 (file)
@@ -10,6 +10,7 @@
 #include <dhcpsrv/lease_mgr.h>
 #include <gtest/gtest.h>
 #include <vector>
+#include <set>
 
 namespace isc {
 namespace dhcp {
@@ -19,6 +20,7 @@ namespace test {
 typedef std::map<std::string, int64_t> StatValMap;
 typedef std::pair<std::string, int64_t> StatValPair;
 typedef std::vector<StatValMap> StatValMapList;
+typedef std::set<LeaseStatsRow> RowSet;
 
 /// @brief Test Fixture class with utility functions for LeaseMgr backends
 ///
@@ -394,6 +396,24 @@ public:
     /// attempts to delete them, one subnet at a time.
     void testWipeLeases6();
 
+    /// @brief Checks operation of v4 LeaseStatsQuery variants
+    ///
+    /// It creates three subnets with leasese in various states in
+    /// each.  It runs and verifies the returned query contents for
+    /// each of the v4 startLeaseQuery variants:
+    ///
+    /// - startSubnetLeaseQuery()
+    /// - startSubneRangetLeaseQuery()
+    /// - startLeaseQuery()
+    ///
+    void testLeaseStatsQuery4();
+
+    /// @brief Compares LeaseQueryStats content to expected set of rows
+    ///
+    /// @param qry - a started LeaseStatsQuery
+    /// @param row_set - set of rows expected to be found in the query rows
+    void checkQueryAgainstRowSet(LeaseStatsQueryPtr qry, RowSet& row_set);
+
     /// @brief String forms of IPv4 addresses
     std::vector<std::string>  straddress4_;
 
index 88ea5a064a38d16f06c6ed3cf91a4cc85ff31bd9..7f015f00281bf7314928d9ce10943dd49469d35a 100644 (file)
@@ -368,10 +368,45 @@ TEST_F(LeaseMgrTest, getLease6) {
                  MultipleRecords);
 }
 
+// Verify LeaseStatsQuery default construction
+TEST (LeaseStatsQueryTest, defaultCtor) {
+    LeaseStatsQueryPtr qry;
+
+    ASSERT_NO_THROW(qry.reset(new LeaseStatsQuery()));
+    ASSERT_EQ(0, qry->getFirstSubnetID());
+    ASSERT_EQ(0, qry->getLastSubnetID());
+    ASSERT_EQ(LeaseStatsQuery::ALL_SUBNETS, qry->getSelectMode());
+}
+
+// Verify LeaseStatsQuery single-subnet construction
+TEST (LeaseStatsQueryTest, singleSubnetCtor) {
+    LeaseStatsQueryPtr qry;
+
+    ASSERT_THROW(qry.reset(new LeaseStatsQuery(0)), BadValue);
+    ASSERT_NO_THROW(qry.reset(new LeaseStatsQuery(77)));
+    ASSERT_EQ(77, qry->getFirstSubnetID());
+    ASSERT_EQ(0, qry->getLastSubnetID());
+    ASSERT_EQ(LeaseStatsQuery::SINGLE_SUBNET, qry->getSelectMode());
+}
+
+// Verify LeaseStatsQuery subnet-range construction
+TEST (LeaseStatsQueryTest, subnetRangeCtor) {
+    LeaseStatsQueryPtr qry;
+
+    // Either ID set to 0, or a backward range should throw
+    ASSERT_THROW(qry.reset(new LeaseStatsQuery(0,1)), BadValue);
+    ASSERT_THROW(qry.reset(new LeaseStatsQuery(1,0)), BadValue);
+    ASSERT_THROW(qry.reset(new LeaseStatsQuery(2,1)), BadValue);
+
+    // Valid values should work and set mode accordingly.
+    ASSERT_NO_THROW(qry.reset(new LeaseStatsQuery(1,2)));
+    ASSERT_EQ(1, qry->getFirstSubnetID());
+    ASSERT_EQ(2, qry->getLastSubnetID());
+    ASSERT_EQ(LeaseStatsQuery::SUBNET_RANGE, qry->getSelectMode());
+}
+
 // There's no point in calling any other methods in LeaseMgr, as they
 // are purely virtual, so we would only call ConcreteLeaseMgr methods.
 // Those methods are just stubs that do not return anything.
 
-
-
 }; // end of anonymous namespace
index cdcf55eef71266c26a7f851b085b4140d38cf60d..09f803219715b4b59c380647a737c65748fe61c2 100644 (file)
@@ -1935,4 +1935,10 @@ TEST_F(MemfileLeaseMgrTest, wipeLeases6) {
     testWipeLeases6();
 }
 
+TEST_F(MemfileLeaseMgrTest, leaseStatsQuery4) {
+    startBackend(V4);
+    testLeaseStatsQuery4();
+}
+
+
 }  // namespace