Browse Source

[2404] Add getLease4(const IOAddress&, SubnetId)

Add ability to select IPv4 leases by address and Subnet ID.
Stephen Morris 12 years ago
parent
commit
af71689ee4
2 changed files with 145 additions and 58 deletions
  1. 60 39
      src/lib/dhcpsrv/mysql_lease_mgr.cc
  2. 85 19
      src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc

+ 60 - 39
src/lib/dhcpsrv/mysql_lease_mgr.cc

@@ -110,8 +110,6 @@ TaggedStatement tagged_statements[] = {
 namespace isc {
 namespace dhcp {
 
-
-
 /// @brief Exchange MySQL and Lease4 Data
 ///
 /// On any MySQL operation, arrays of MYSQL_BIND structures must be built to
@@ -306,9 +304,9 @@ private:
     MYSQL_TIME      expire_;            ///< Lease expiry time
     const my_bool   false_;             ///< "false" for MySql
     Lease4Ptr       lease_;             ///< Pointer to lease object
-    uint32_t        valid_lifetime_;    ///< Lease time
     uint32_t        subnet_id_;         ///< Subnet identification
     const my_bool   true_;              ///< "true_" for MySql
+    uint32_t        valid_lifetime_;    ///< Lease time
 };
 
 
@@ -598,12 +596,12 @@ private:
     const my_bool   false_;             ///< "false" for MySql
     uint32_t        iaid_;              ///< Identity association ID
     Lease6Ptr       lease_;             ///< Pointer to lease object
-    uint32_t        valid_lifetime_;    ///< Lease time
     uint8_t         lease_type_;        ///< Lease type
     uint8_t         prefixlen_;         ///< Prefix length
     uint32_t        pref_lifetime_;     ///< Preferred lifetime
     uint32_t        subnet_id_;         ///< Subnet identification
     const my_bool   true_;              ///< "true_" for MySql
+    uint32_t        valid_lifetime_;    ///< Lease time
 };
 
 
@@ -611,7 +609,7 @@ private:
 ///
 /// When a MySQL statement is exected, to fetch the results the function
 /// mysql_stmt_fetch() must be called.  As well as getting data, this
-/// allocated internal state.  Subsequent calls to mysql_stmt_fetch
+/// allocates internal state.  Subsequent calls to mysql_stmt_fetch
 /// can be made, but when all the data is retrieved, mysql_stmt_free_result
 /// must be called to free up the resources allocated.
 ///
@@ -648,7 +646,7 @@ private:
 };
 
 
-// MySqlLeaseMgr Methods
+// MySqlLeaseMgr Constructor and Destructor
 
 MySqlLeaseMgr::MySqlLeaseMgr(const LeaseMgr::ParameterMap& parameters) 
     : LeaseMgr(parameters), mysql_(NULL) {
@@ -751,6 +749,9 @@ MySqlLeaseMgr::convertFromDatabaseTime(const MYSQL_TIME& expire,
 }
 
 
+
+// Database acess method
+
 void
 MySqlLeaseMgr::openDatabase() {
 
@@ -812,7 +813,7 @@ MySqlLeaseMgr::openDatabase() {
     // changed and so the "affected rows" (retrievable from MySQL) is zero.
     // This makes it hard to distinguish whether the UPDATE changed no rows
     // because no row matching the WHERE clause was found, or because a
-    // row was found by no data was altered.
+    // row was found but no data was altered.
     MYSQL* status = mysql_real_connect(mysql_, host, user, password, name,
                                        0, NULL, CLIENT_FOUND_ROWS);
     if (status != mysql_) {
@@ -820,6 +821,12 @@ MySqlLeaseMgr::openDatabase() {
     }
 }
 
+// Prepared statement setup.  The textual form of the SQL statement is stored
+// in a vector of strings (text_statements_) and is used in the output of
+// error messages.  The SQL statement is also compiled into a "prepared
+// statement" (stored in statements_), which avoids the overhead of compilation
+// during use.  As these allocate resources, the class destructor explicitly
+// destroys the prepared statements.
 
 void
 MySqlLeaseMgr::prepareStatement(StatementIndex index, const char* text) {
@@ -865,7 +872,7 @@ MySqlLeaseMgr::prepareStatements() {
 }
 
 
-// Common add lease code
+// Add leases to the database
 
 bool
 MySqlLeaseMgr::addLease(StatementIndex stindex, std::vector<MYSQL_BIND>& bind) {
@@ -909,6 +916,36 @@ MySqlLeaseMgr::addLease(const Lease6Ptr& lease) {
     return (addLease(INSERT_LEASE6, bind));
 }
 
+// A convenience function used in the various getLease() methods.  It binds
+// the selection parameters to the prepared statement, and binds the variables
+// that will receive the data.  These are stored in the MySqlLease6Exchange
+// object associated with the lease manager and converted to a Lease6 object
+// when retrieved.
+template <typename Exchange>
+void
+MySqlLeaseMgr::bindAndExecute(StatementIndex stindex, Exchange& exchange,
+                              MYSQL_BIND* inbind) const {
+
+    // Bind the input parameters to the statement
+    int status = mysql_stmt_bind_param(statements_[stindex], inbind);
+    checkError(status, stindex, "unable to bind WHERE clause parameter");
+
+    // Set up the SELECT clause
+    std::vector<MYSQL_BIND> outbind = exchange->createBindForReceive();
+
+    // Bind the output parameters to the statement
+    status = mysql_stmt_bind_result(statements_[stindex], &outbind[0]);
+    checkError(status, stindex, "unable to bind SELECT caluse parameters");
+
+    // Execute the statement
+    status = mysql_stmt_execute(statements_[stindex]);
+    checkError(status, stindex, "unable to execute");
+}
+
+// Extraction of leases from the database.  Much the code has common logic
+// with the difference between V4 and V6 being the data types of the
+// objects involved.  For this reason, the common logic is inside a
+// template method.
 
 template <typename Exchange, typename LeasePtr>
 void MySqlLeaseMgr::getLease(StatementIndex stindex, MYSQL_BIND* inbind,
@@ -918,7 +955,7 @@ void MySqlLeaseMgr::getLease(StatementIndex stindex, MYSQL_BIND* inbind,
     // to fields in the exchange object, then execute the prepared statement.
     bindAndExecute(stindex, exchange, inbind);
 
-    // Fetch the data and set up the "release" object to release associated
+    // Fetch the data and set up the "free result" object to release associated
     // resources when this method exits.
     MySqlFreeResult fetch_release(statements_[stindex]);
     int status = mysql_stmt_fetch(statements_[stindex]);
@@ -967,11 +1004,20 @@ MySqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& addr) const {
 
 
 Lease4Ptr
-MySqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& /* addr */,
-                         SubnetID /* subnet_id */) const {
-    isc_throw(NotImplemented, "MySqlLeaseMgr::getLease4(const IOAddress&, SubnetID) "
-              "not implemented yet");
-    return (Lease4Ptr());
+MySqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& addr,
+                         SubnetID subnet_id) const {
+
+    // As the address is the unique primary key of the lease4 table, there can
+    // only be one lease with a given address.  Therefore we will get that
+    // lease and do the filtering on subnet ID here.
+    Lease4Ptr result = getLease4(addr);
+    if (result && (result->subnet_id_ != subnet_id)) {
+
+        // Lease found but IDs do not match.  Return null pointer
+        result.reset();
+    }
+
+    return (result);
 }
 
 
@@ -1009,31 +1055,6 @@ MySqlLeaseMgr::getLease4(const ClientId& /* clientid */,
 }
 
 
-// A convenience function used in the various getLease() methods.  It binds
-// the selection parameters to the prepared statement, and binds the variables
-// that will receive the data.  These are stored in the MySqlLease6Exchange
-// object associated with the lease manager and converted to a Lease6 object
-// when retrieved.
-template <typename Exchange>
-void
-MySqlLeaseMgr::bindAndExecute(StatementIndex stindex, Exchange& exchange,
-                              MYSQL_BIND* inbind) const {
-
-    // Bind the input parameters to the statement
-    int status = mysql_stmt_bind_param(statements_[stindex], inbind);
-    checkError(status, stindex, "unable to bind WHERE clause parameter");
-
-    // Set up the SELECT clause
-    std::vector<MYSQL_BIND> outbind = exchange->createBindForReceive();
-
-    // Bind the output parameters to the statement
-    status = mysql_stmt_bind_result(statements_[stindex], &outbind[0]);
-    checkError(status, stindex, "unable to bind SELECT caluse parameters");
-
-    // Execute the statement
-    status = mysql_stmt_execute(statements_[stindex]);
-    checkError(status, stindex, "unable to execute");
-}
 
 
 Lease6Ptr

+ 85 - 19
src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc

@@ -477,13 +477,13 @@ public:
 
         // Check they were created
         for (int i = 0; i < leases.size(); ++i) {
-            EXPECT_TRUE(leases[i]);
+            ASSERT_TRUE(leases[i]);
         }
 
         // Check they are different
         for (int i = 0; i < (leases.size() - 1); ++i) {
             for (int j = (i + 1); j < leases.size(); ++j) {
-                EXPECT_TRUE(leases[i] != leases[j]);
+                ASSERT_TRUE(leases[i] != leases[j]);
             }
         }
     }
@@ -731,15 +731,15 @@ TEST_F(MySqlLeaseMgrTest, basicLease4) {
     reopen();
 
     Lease4Ptr l_returned = lmptr_->getLease4(ioaddress4_[1]);
-    EXPECT_TRUE(l_returned);
+    ASSERT_TRUE(l_returned);
     detailCompareLease(leases[1], l_returned);
 
     l_returned = lmptr_->getLease4(ioaddress4_[2]);
-    EXPECT_TRUE(l_returned);
+    ASSERT_TRUE(l_returned);
     detailCompareLease(leases[2], l_returned);
 
     l_returned = lmptr_->getLease4(ioaddress4_[3]);
-    EXPECT_TRUE(l_returned);
+    ASSERT_TRUE(l_returned);
     detailCompareLease(leases[3], l_returned);
 
     // Check that we can't add a second lease with the same address
@@ -754,7 +754,7 @@ TEST_F(MySqlLeaseMgrTest, basicLease4) {
 
     // Check that the second address is still there.
     l_returned = lmptr_->getLease4(ioaddress4_[2]);
-    EXPECT_TRUE(l_returned);
+    ASSERT_TRUE(l_returned);
     detailCompareLease(leases[2], l_returned);
 }
 
@@ -782,15 +782,15 @@ TEST_F(MySqlLeaseMgrTest, basicLease6) {
     reopen();
 
     Lease6Ptr l_returned = lmptr_->getLease6(ioaddress6_[1]);
-    EXPECT_TRUE(l_returned);
+    ASSERT_TRUE(l_returned);
     detailCompareLease(leases[1], l_returned);
 
     l_returned = lmptr_->getLease6(ioaddress6_[2]);
-    EXPECT_TRUE(l_returned);
+    ASSERT_TRUE(l_returned);
     detailCompareLease(leases[2], l_returned);
 
     l_returned = lmptr_->getLease6(ioaddress6_[3]);
-    EXPECT_TRUE(l_returned);
+    ASSERT_TRUE(l_returned);
     detailCompareLease(leases[3], l_returned);
 
     // Check that we can't add a second lease with the same address
@@ -805,18 +805,84 @@ TEST_F(MySqlLeaseMgrTest, basicLease6) {
 
     // Check that the second address is still there.
     l_returned = lmptr_->getLease6(ioaddress6_[2]);
-    EXPECT_TRUE(l_returned);
+    ASSERT_TRUE(l_returned);
     detailCompareLease(leases[2], l_returned);
 }
 
+// @brief Check GetLease4 methods - Access by Address and SubnetID
+//
+// Adds leases to the database and checks that they can be accessed via
+// a combination of Address, SubnetID
+TEST_F(MySqlLeaseMgrTest, getLease4AddressSubnetId) {
+    // Get the leases to be used for the test.
+    vector<Lease4Ptr> leases = createLeases4();
+
+    // Add just one to the database.
+    EXPECT_TRUE(lmptr_->addLease(leases[1]));
+
+    // Look for a known lease with a valid Subnet ID
+    Lease4Ptr l_returned = lmptr_->getLease4(ioaddress4_[1], 73);
+    ASSERT_TRUE(l_returned);
+    detailCompareLease(leases[1], l_returned);
+
+    // Look for a lease known to be in the database with an invalid Subnet ID
+    l_returned = lmptr_->getLease4(ioaddress4_[1], 74);
+    EXPECT_FALSE(l_returned);
+
+    // Look for a lease known not to be in the database with a valid Subnet ID
+    l_returned = lmptr_->getLease4(ioaddress4_[2], 73);
+    EXPECT_FALSE(l_returned);
+
+    // Look for a lease known not to be in the database with and invalid
+    l_returned = lmptr_->getLease4(ioaddress4_[2], 74);
+    EXPECT_FALSE(l_returned);
+}
+
+// @brief Check GetLease4 methods - Access by Hardware Address
+//
+// Adds leases to the database and checks that they can be accessed via
+// hardware address
+TEST_F(MySqlLeaseMgrTest, getLease4AddressHwaddr) {
+    FAIL() << "Test not complete";
+/*
+    // Get the leases to be used for the test and add to the database.
+    vector<Lease4Ptr> leases = createLeases4();
+    for (int i = 0; i < leases.size(); ++i) {
+        EXPECT_TRUE(lmptr_->addLease(leases[i]));
+    }
+
+    // Get a known hardware address
+    vector<uint8_t> hwaddr = leases[1]->hwaddr_;
+    EXPECT_FALSE(hwaddr.empty());
+
+    // Look for a lease with a valid hardware address
+    Lease4Ptr l_returned = lmptr_->getLease4(hwaddr);
+    ASSERT_TRUE(l_returned);
+    detailCompareLease(leases[1], l_returned);
+
+    // Look for a lease with an invalid valid hardware address
+    hwaddr[0] += 1;
+    Lease4Ptr l_returned = lmptr_->getLease4(hwaddr);
+    EXPECT_FALSE(l_returned);
+
+    // Check it handles an empty hardware address
+    hwaddr.clear();
+    Lease4Ptr l_returned = lmptr_->getLease4(hwaddr);
+    EXPECT_FALSE(l_returned);
+
+    // Add a lease with an empty hardware address to the database and
+    // check that it find that.
+*/
+}
+
 // @brief Check GetLease6 methods - Access by DUID/IAID
 //
 // Adds leases to the database and checks that they can be accessed via
 // a combination of DIUID and IAID.
-TEST_F(MySqlLeaseMgrTest, getLease6Extended1) {
+TEST_F(MySqlLeaseMgrTest, getLease6DuidIaid) {
     // Get the leases to be used for the test.
     vector<Lease6Ptr> leases = createLeases6();
-    EXPECT_LE(6, leases.size());    // Expect to access leases 0 through 5
+    ASSERT_LE(6, leases.size());    // Expect to access leases 0 through 5
 
     // Add them to the database
     for (int i = 0; i < leases.size(); ++i) {
@@ -860,10 +926,10 @@ TEST_F(MySqlLeaseMgrTest, getLease6Extended1) {
 //
 // Adds leases to the database and checks that they can be accessed via
 // a combination of DIUID and IAID.
-TEST_F(MySqlLeaseMgrTest, getLease6Extended2) {
+TEST_F(MySqlLeaseMgrTest, getLease6DuidIaidSubnetId) {
     // Get the leases to be used for the test.
     vector<Lease6Ptr> leases = createLeases6();
-    EXPECT_LE(6, leases.size());    // Expect to access leases 0 through 5
+    ASSERT_LE(6, leases.size());    // Expect to access leases 0 through 5
 
     // Add them to the database
     for (int i = 0; i < leases.size(); ++i) {
@@ -904,7 +970,7 @@ TEST_F(MySqlLeaseMgrTest, getLease6Extended2) {
 TEST_F(MySqlLeaseMgrTest, updateLease6) {
     // Get the leases to be used for the test.
     vector<Lease6Ptr> leases = createLeases6();
-    EXPECT_LE(3, leases.size());    // Expect to access leases 0 through 5
+    ASSERT_LE(3, leases.size());    // Expect to access leases 0 through 2
 
     // Add a lease to the database and check that the lease is there.
     EXPECT_TRUE(lmptr_->addLease(leases[1]));
@@ -912,7 +978,7 @@ TEST_F(MySqlLeaseMgrTest, updateLease6) {
 
     reopen();
     Lease6Ptr l_returned = lmptr_->getLease6(ioaddress6_[1]);
-    EXPECT_TRUE(l_returned);
+    ASSERT_TRUE(l_returned);
     detailCompareLease(leases[1], l_returned);
 
     // Modify some fields in lease 1 (not the address) and update it.
@@ -926,7 +992,7 @@ TEST_F(MySqlLeaseMgrTest, updateLease6) {
     // ... and check what is returned is what is expected.
     l_returned.reset();
     l_returned = lmptr_->getLease6(ioaddress6_[1]);
-    EXPECT_TRUE(l_returned);
+    ASSERT_TRUE(l_returned);
     detailCompareLease(leases[1], l_returned);
 
     // Alter the lease again and check.
@@ -938,14 +1004,14 @@ TEST_F(MySqlLeaseMgrTest, updateLease6) {
 
     l_returned.reset();
     l_returned = lmptr_->getLease6(ioaddress6_[1]);
-    EXPECT_TRUE(l_returned);
+    ASSERT_TRUE(l_returned);
     detailCompareLease(leases[1], l_returned);
 
     // Check we can do an update without changing data.
     lmptr_->updateLease6(leases[1]);
     l_returned.reset();
     l_returned = lmptr_->getLease6(ioaddress6_[1]);
-    EXPECT_TRUE(l_returned);
+    ASSERT_TRUE(l_returned);
     detailCompareLease(leases[1], l_returned);
 
     // Try updating a lease not in the database.