Commit af71689e authored by Stephen Morris's avatar Stephen Morris

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

Add ability to select IPv4 leases by address and Subnet ID.
parent 61071513
......@@ -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
......
......@@ -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.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment