// If there is no such option in the destination container,
// add one.
if (std::distance(range.first, range.second) == 0) {
- dest_container.addItem(OptionDescriptor(src_opt), *it);
+ dest_container.addItem(OptionDescriptor(*src_opt), *it);
}
}
}
{MySqlLeaseMgr::INSERT_LEASE4,
"INSERT INTO lease4(address, hwaddr, client_id, "
"valid_lifetime, expire, subnet_id, "
- "fqdn_fwd, fqdn_rev, hostname, state) "
+ "fqdn_fwd, fqdn_rev, hostname, "
+ "state) "
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"},
{MySqlLeaseMgr::INSERT_LEASE6,
"INSERT INTO lease6(address, duid, valid_lifetime, "
"UPDATE lease4 SET address = ?, hwaddr = ?, "
"client_id = ?, valid_lifetime = ?, expire = ?, "
"subnet_id = ?, fqdn_fwd = ?, fqdn_rev = ?, "
- "hostname = ?, state = ? "
+ "hostname = ?, "
+ "state = ? "
"WHERE address = ?"},
{MySqlLeaseMgr::UPDATE_LEASE6,
"UPDATE lease6 SET address = ?, duid = ?, "
}
};
-};
+} // namespace
namespace isc {
namespace dhcp {
}
};
-
/// @brief Exchange MySQL and Lease4 Data
///
/// On any MySQL operation, arrays of MYSQL_BIND structures must be built to
///
/// The initialization of the variables here is only to satisfy cppcheck -
/// all variables are initialized/set in the methods before they are used.
- MySqlLease4Exchange() : addr4_(0), hwaddr_length_(0), client_id_length_(0),
- client_id_null_(MLM_FALSE),
+ MySqlLease4Exchange() : addr4_(0), hwaddr_length_(0), hwaddr_null_(MLM_FALSE),
+ client_id_length_(0), client_id_null_(MLM_FALSE),
subnet_id_(0), valid_lifetime_(0),
fqdn_fwd_(false), fqdn_rev_(false), hostname_length_(0),
state_(0) {
// structure.
try {
- // Address: uint32_t
+ // address: uint32_t
// The address in the Lease structure is an IOAddress object. Convert
// this to an integer for storage.
addr4_ = lease_->addr_.toUint32();
// bind_[0].is_null = &MLM_FALSE; // commented out for performance
// reasons, see memset() above
- // hwaddr: varbinary(128)
- // For speed, we avoid copying the data into temporary storage and
- // instead extract it from the lease structure directly.
- hwaddr_length_ = lease_->hwaddr_->hwaddr_.size();
- bind_[1].buffer_type = MYSQL_TYPE_BLOB;
- bind_[1].buffer = reinterpret_cast<char*>(&(lease_->hwaddr_->hwaddr_[0]));
- bind_[1].buffer_length = hwaddr_length_;
- bind_[1].length = &hwaddr_length_;
- // bind_[1].is_null = &MLM_FALSE; // commented out for performance
- // reasons, see memset() above
+ // hwaddr: varbinary(20) - hardware/MAC address
+ HWAddrPtr hwaddr = lease_->hwaddr_;
+ if (hwaddr) {
+ hwaddr_ = hwaddr->hwaddr_;
+ hwaddr_length_ = hwaddr->hwaddr_.size();
+ bind_[1].buffer_type = MYSQL_TYPE_BLOB;
+ bind_[1].buffer = reinterpret_cast<char*>(&(hwaddr_[0]));
+ bind_[1].buffer_length = hwaddr_length_;
+ bind_[1].length = &hwaddr_length_;
+ } else {
+ bind_[1].buffer_type = MYSQL_TYPE_NULL;
+ // According to http://dev.mysql.com/doc/refman/5.5/en/
+ // c-api-prepared-statement-data-structures.html, the other
+ // fields doesn't matter if type is set to MYSQL_TYPE_NULL,
+ // but let's set them to some sane values in case earlier versions
+ // didn't have that assumption.
+ hwaddr_null_ = MLM_TRUE;
+ bind_[1].buffer = NULL;
+ bind_[1].is_null = &hwaddr_null_;
+ }
// client_id: varbinary(128)
if (lease_->client_id_) {
// reasons, see memset() above
} else {
bind_[2].buffer_type = MYSQL_TYPE_NULL;
-
// According to http://dev.mysql.com/doc/refman/5.5/en/
// c-api-prepared-statement-data-structures.html, the other
// fields doesn't matter if type is set to MYSQL_TYPE_NULL,
// code that explicitly sets is_null is there, but is commented out.
memset(bind_, 0, sizeof(bind_));
- // address: uint32_t
+ // address: uint32_t
bind_[0].buffer_type = MYSQL_TYPE_LONG;
bind_[0].buffer = reinterpret_cast<char*>(&addr4_);
bind_[0].is_unsigned = MLM_TRUE;
// Note: All array lengths are equal to the corresponding variable in the
// schema.
// Note: Arrays are declared fixed length for speed of creation
- uint32_t addr4_; ///< IPv4 address
- MYSQL_BIND bind_[LEASE_COLUMNS]; ///< Bind array
- std::string columns_[LEASE_COLUMNS]; ///< Column names
- my_bool error_[LEASE_COLUMNS]; ///< Error array
- std::vector<uint8_t> hwaddr_; ///< Hardware address
- uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
- ///< Hardware address buffer
- unsigned long hwaddr_length_; ///< Hardware address length
- std::vector<uint8_t> client_id_; ///< Client identification
- uint8_t client_id_buffer_[ClientId::MAX_CLIENT_ID_LEN];
- ///< Client ID buffer
- unsigned long client_id_length_; ///< Client ID address length
- my_bool client_id_null_; ///< Is Client ID null?
-
- MYSQL_TIME expire_; ///< Lease expiry time
- Lease4Ptr lease_; ///< Pointer to lease object
- uint32_t subnet_id_; ///< Subnet identification
- uint32_t valid_lifetime_; ///< Lease time
-
- my_bool fqdn_fwd_; ///< Has forward DNS update been
- ///< performed
- my_bool fqdn_rev_; ///< Has reverse DNS update been
- ///< performed
- char hostname_buffer_[HOSTNAME_MAX_LEN];
- ///< Client hostname
- unsigned long hostname_length_; ///< Client hostname length
- uint32_t state_; ///< Lease state
+ uint32_t addr4_; ///< IPv4 address
+ MYSQL_BIND bind_[LEASE_COLUMNS]; ///< Bind array
+ std::string columns_[LEASE_COLUMNS]; ///< Column names
+ my_bool error_[LEASE_COLUMNS]; ///< Error array
+ std::vector<uint8_t> hwaddr_; ///< Hardware address
+ uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN]; ///< Hardware address buffer
+ unsigned long hwaddr_length_; ///< Hardware address length
+ my_bool hwaddr_null_; ///< Used when HWAddr is null
+ std::vector<uint8_t> client_id_; ///< Client identification
+ uint8_t client_id_buffer_[ClientId::MAX_CLIENT_ID_LEN]; ///< Client ID buffer
+ unsigned long client_id_length_; ///< Client ID address length
+ my_bool client_id_null_; ///< Is Client ID null?
+ MYSQL_TIME expire_; ///< Lease expiry time
+ Lease4Ptr lease_; ///< Pointer to lease object
+ uint32_t subnet_id_; ///< Subnet identification
+ uint32_t valid_lifetime_; ///< Lease time
+ my_bool fqdn_fwd_; ///< Has forward DNS update been performed
+ my_bool fqdn_rev_; ///< Has reverse DNS update been performed
+ char hostname_buffer_[HOSTNAME_MAX_LEN]; ///< Client hostname
+ unsigned long hostname_length_; ///< Client hostname length
+ uint32_t state_; ///< Lease state
};
-
/// @brief Exchange MySQL and Lease6 Data
///
/// On any MySQL operation, arrays of MYSQL_BIND structures must be built to
/// expiry time (expire). The relationship is given by:
//
// expire = cltt_ + valid_lft_
- //
MySqlConnection::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_,
expire_);
bind_[3].buffer_type = MYSQL_TYPE_TIMESTAMP;
if (hwaddr) {
hwaddr_ = hwaddr->hwaddr_;
hwaddr_length_ = hwaddr->hwaddr_.size();
-
bind_[12].buffer_type = MYSQL_TYPE_BLOB;
bind_[12].buffer = reinterpret_cast<char*>(&(hwaddr_[0]));
bind_[12].buffer_length = hwaddr_length_;
bind_[12].length = &hwaddr_length_;
} else {
bind_[12].buffer_type = MYSQL_TYPE_NULL;
-
// According to http://dev.mysql.com/doc/refman/5.5/en/
// c-api-prepared-statement-data-structures.html, the other
// fields doesn't matter if type is set to MYSQL_TYPE_NULL,
bind_[14].is_unsigned = MLM_TRUE;
} else {
hwaddr_source_ = 0;
-
bind_[14].buffer_type = MYSQL_TYPE_NULL;
// According to http://dev.mysql.com/doc/refman/5.5/en/
// c-api-prepared-statement-data-structures.html, the other
setErrorIndicators(bind_, error_, LEASE_COLUMNS);
// .. and check that we have the numbers correct at compile time.
- BOOST_STATIC_ASSERT(14 < LEASE_COLUMNS);
+ BOOST_STATIC_ASSERT(15 < LEASE_COLUMNS);
} catch (const std::exception& ex) {
isc_throw(DbOperationError,
// bind_[11].is_null = &MLM_FALSE; // commented out for performance
// reasons, see memset() above
- // hardware address
// hwaddr: varbinary(20)
hwaddr_null_ = MLM_FALSE;
hwaddr_length_ = sizeof(hwaddr_buffer_);
// Note: All array lengths are equal to the corresponding variable in the
// schema.
// Note: arrays are declared fixed length for speed of creation
- std::string addr6_; ///< String form of address
- char addr6_buffer_[ADDRESS6_TEXT_MAX_LEN + 1]; ///< Character
- ///< array form of V6 address
- unsigned long addr6_length_; ///< Length of the address
- MYSQL_BIND bind_[LEASE_COLUMNS]; ///< Bind array
- std::string columns_[LEASE_COLUMNS]; ///< Column names
- std::vector<uint8_t> duid_; ///< Client identification
- uint8_t duid_buffer_[DUID::MAX_DUID_LEN]; ///< Buffer form of DUID
- unsigned long duid_length_; ///< Length of the DUID
- my_bool error_[LEASE_COLUMNS]; ///< Error indicators
- MYSQL_TIME expire_; ///< Lease expiry time
- uint32_t iaid_; ///< Identity association ID
- Lease6Ptr lease_; ///< Pointer to lease object
- uint8_t lease_type_; ///< Lease type
- uint8_t prefixlen_; ///< Prefix length
- uint32_t pref_lifetime_; ///< Preferred lifetime
- uint32_t subnet_id_; ///< Subnet identification
- uint32_t valid_lifetime_; ///< Lease time
- my_bool fqdn_fwd_; ///< Has forward DNS update been
- ///< performed
- my_bool fqdn_rev_; ///< Has reverse DNS update been
- ///< performed
- char hostname_buffer_[HOSTNAME_MAX_LEN];
- ///< Client hostname
- unsigned long hostname_length_; ///< Client hostname length
- uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
- ///< Buffer for Hardware address
- std::vector<uint8_t> hwaddr_; ///< Hardware address (optional)
- unsigned long hwaddr_length_; ///< Aux. variable denoting hwaddr_ size()
- my_bool hwaddr_null_; ///< Used when HWAddr is null
- uint16_t hwtype_; ///< Hardware type
- uint32_t hwaddr_source_; ///< Source of the hardware address
- uint32_t state_; ///< Lease state.
+ std::string addr6_; ///< String form of address
+ char addr6_buffer_[ADDRESS6_TEXT_MAX_LEN + 1]; ///< Character
+ ///< array form of V6 address
+ unsigned long addr6_length_; ///< Length of the address
+ MYSQL_BIND bind_[LEASE_COLUMNS]; ///< Bind array
+ std::string columns_[LEASE_COLUMNS]; ///< Column names
+ std::vector<uint8_t> duid_; ///< Client identification
+ uint8_t duid_buffer_[DUID::MAX_DUID_LEN]; ///< Buffer form of DUID
+ unsigned long duid_length_; ///< Length of the DUID
+ my_bool error_[LEASE_COLUMNS]; ///< Error indicators
+ MYSQL_TIME expire_; ///< Lease expiry time
+ uint32_t iaid_; ///< Identity association ID
+ Lease6Ptr lease_; ///< Pointer to lease object
+ uint8_t lease_type_; ///< Lease type
+ uint8_t prefixlen_; ///< Prefix length
+ uint32_t pref_lifetime_; ///< Preferred lifetime
+ uint32_t subnet_id_; ///< Subnet identification
+ uint32_t valid_lifetime_; ///< Lease time
+ my_bool fqdn_fwd_; ///< Has forward DNS update been performed
+ my_bool fqdn_rev_; ///< Has reverse DNS update been performed
+ char hostname_buffer_[HOSTNAME_MAX_LEN]; ///< Client hostname
+ unsigned long hostname_length_; ///< Client hostname length
+ uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN]; ///< Buffer form of Hardware address
+ std::vector<uint8_t> hwaddr_; ///< Hardware address (optional)
+ unsigned long hwaddr_length_; ///< Aux. variable denoting hwaddr_ size()
+ my_bool hwaddr_null_; ///< Used when HWAddr is null
+ uint16_t hwtype_; ///< Hardware type
+ uint32_t hwaddr_source_; ///< Source of the hardware address
+ uint32_t state_; ///< Lease state.
};
/// @brief MySql derivation of the statistical lease data query
// Fetch the lease type if we were told to do so.
if (fetch_type_) {
- // lease type: uint32_t
+ // lease type: uint32_t
bind_[col].buffer_type = MYSQL_TYPE_LONG;
bind_[col].buffer = reinterpret_cast<char*>(&lease_type_);
bind_[col].is_unsigned = MLM_TRUE;
fetch_type_ = Lease::TYPE_NA;
}
- // state: uint32_t
+ // state: uint32_t
bind_[col].buffer_type = MYSQL_TYPE_LONG;
bind_[col].buffer = reinterpret_cast<char*>(&lease_state_);
bind_[col].is_unsigned = MLM_TRUE;
conn_.checkError(status, index, what);
}
-}; // end of isc::dhcp namespace
-}; // end of isc namespace
+} // namespace dhcp
+} // namespace isc
MySqlConnection conn_;
};
-}; // end of isc::dhcp namespace
-}; // end of isc namespace
+} // namespace dhcp
+} // namespace isc
#endif // MYSQL_LEASE_MGR_H
namespace {
-/// @todo TKM lease6 needs to accommodate hwaddr, hwtype, and hwaddr source
-/// columns. This is covered by tickets #3557, #4530, and PR#9.
-
/// @brief Catalog of all the SQL statements currently supported. Note
/// that the order columns appear in statement body must match the order they
/// that the occur in the table. This does not apply to the where clause.
"get_lease4",
"SELECT address, hwaddr, client_id, "
"valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
- "fqdn_fwd, fqdn_rev, hostname, state "
+ "fqdn_fwd, fqdn_rev, hostname, "
+ "state "
"FROM lease4"},
// GET_LEASE4_ADDR
"get_lease4_subid",
"SELECT address, hwaddr, client_id, "
"valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
- "fqdn_fwd, fqdn_rev, hostname, state "
+ "fqdn_fwd, fqdn_rev, hostname, "
+ "state "
"FROM lease4 "
"WHERE subnet_id = $1"},
"SELECT address, duid, valid_lifetime, "
"extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
"lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
+ "hwaddr, hwtype, hwaddr_source, "
"state "
"FROM lease6 "
"WHERE address = $1 AND lease_type = $2"},
// GET_LEASE6_DUID_IAID
- { 3, { OID_BYTEA, OID_INT8, OID_INT2 },
- "get_lease6_duid_iaid",
- "SELECT address, duid, valid_lifetime, "
- "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
- "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
- "state "
- "FROM lease6 "
- "WHERE duid = $1 AND iaid = $2 AND lease_type = $3"},
+ { 3, { OID_BYTEA, OID_INT8, OID_INT2 },
+ "get_lease6_duid_iaid",
+ "SELECT address, duid, valid_lifetime, "
+ "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
+ "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
+ "hwaddr, hwtype, hwaddr_source, "
+ "state "
+ "FROM lease6 "
+ "WHERE duid = $1 AND iaid = $2 AND lease_type = $3"},
// GET_LEASE6_DUID_IAID_SUBID
{ 4, { OID_INT2, OID_BYTEA, OID_INT8, OID_INT8 },
"SELECT address, duid, valid_lifetime, "
"extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
"lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
+ "hwaddr, hwtype, hwaddr_source, "
"state "
"FROM lease6 "
"WHERE lease_type = $1 "
"extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
"lease_type, iaid, prefix_len, "
"fqdn_fwd, fqdn_rev, hostname, "
+ "hwaddr, hwtype, hwaddr_source, "
"state "
"FROM lease6 "
"WHERE state != $1 AND expire < $2 "
"VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)"},
// INSERT_LEASE6
- { 13, { OID_VARCHAR, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8,
+ { 16, { OID_VARCHAR, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8,
OID_INT8, OID_INT2, OID_INT8, OID_INT2, OID_BOOL, OID_BOOL,
- OID_VARCHAR, OID_INT8 },
+ OID_VARCHAR, OID_BYTEA, OID_INT2, OID_INT2, OID_INT8 },
"insert_lease6",
"INSERT INTO lease6(address, duid, valid_lifetime, "
"expire, subnet_id, pref_lifetime, "
- "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, state) "
- "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)"},
+ "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
+ "hwaddr, hwtype, hwaddr_source, "
+ "state) "
+ "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)"},
// UPDATE_LEASE4
{ 11, { OID_INT8, OID_BYTEA, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8,
"UPDATE lease4 SET address = $1, hwaddr = $2, "
"client_id = $3, valid_lifetime = $4, expire = $5, "
"subnet_id = $6, fqdn_fwd = $7, fqdn_rev = $8, hostname = $9, "
- "state = $10"
+ "state = $10 "
"WHERE address = $11"},
// UPDATE_LEASE6
- { 14, { OID_VARCHAR, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8, OID_INT8,
+ { 17, { OID_VARCHAR, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8, OID_INT8,
OID_INT2, OID_INT8, OID_INT2, OID_BOOL, OID_BOOL, OID_VARCHAR,
+ OID_BYTEA, OID_INT2, OID_INT2,
OID_INT8, OID_VARCHAR },
"update_lease6",
"UPDATE lease6 SET address = $1, duid = $2, "
"valid_lifetime = $3, expire = $4, subnet_id = $5, "
"pref_lifetime = $6, lease_type = $7, iaid = $8, "
"prefix_len = $9, fqdn_fwd = $10, fqdn_rev = $11, hostname = $12, "
- "state = $13 "
- "WHERE address = $14"},
+ "hwaddr = $13, hwtype = $14, hwaddr_source = $15, "
+ "state = $16 "
+ "WHERE address = $17"},
// RECOUNT_LEASE4_STATS,
{ 0, { OID_NONE },
{ 0, { 0 }, NULL, NULL}
};
-};
+} // namespace
namespace isc {
namespace dhcp {
class PgSqlLeaseExchange : public PgSqlExchange {
public:
PgSqlLeaseExchange()
- : addr_str_(""), valid_lifetime_(0), valid_lft_str_(""),
+ : addr_str_(""), valid_lifetime_(0), valid_lifetime_str_(""),
expire_(0), expire_str_(""), subnet_id_(0), subnet_id_str_(""),
cltt_(0), fqdn_fwd_(false), fqdn_rev_(false), hostname_(""),
state_str_("") {
protected:
/// @brief Common Instance members used for binding and conversion
//@{
- std::string addr_str_;
- uint32_t valid_lifetime_;
- std::string valid_lft_str_;
- time_t expire_;
- std::string expire_str_;
- uint32_t subnet_id_;
- std::string subnet_id_str_;
- time_t cltt_;
- bool fqdn_fwd_;
- bool fqdn_rev_;
- std::string hostname_;
- std::string state_str_;
+ std::string addr_str_;
+ uint32_t valid_lifetime_;
+ std::string valid_lifetime_str_;
+ time_t expire_;
+ std::string expire_str_;
+ uint32_t subnet_id_;
+ std::string subnet_id_str_;
+ time_t cltt_;
+ bool fqdn_fwd_;
+ bool fqdn_rev_;
+ std::string hostname_;
+ std::string state_str_;
//@}
-
};
/// @brief Supports exchanging IPv4 leases with PostgreSQL.
<< " exceeds maximum allowed of: "
<< HWAddr::MAX_HWADDR_LEN);
}
-
bind_array.add(lease->hwaddr_->hwaddr_);
} else {
bind_array.add("");
bind_array.add("");
}
- valid_lft_str_ = boost::lexical_cast<std::string>
- (lease->valid_lft_);
- bind_array.add(valid_lft_str_);
+ valid_lifetime_str_ = boost::lexical_cast<std::string>(lease->valid_lft_);
+ bind_array.add(valid_lifetime_str_);
expire_str_ = convertToDatabaseTime(lease->cltt_, lease_->valid_lft_);
bind_array.add(expire_str_);
- subnet_id_str_ = boost::lexical_cast<std::string>
- (lease->subnet_id_);
+ subnet_id_str_ = boost::lexical_cast<std::string>(lease->subnet_id_);
bind_array.add(subnet_id_str_);
bind_array.add(lease->fqdn_fwd_);
+
bind_array.add(lease->fqdn_rev_);
bind_array.add(lease->hostname_);
cltt_ = expire_ - valid_lifetime_;
getColumnValue(r, row, FQDN_FWD_COL, fqdn_fwd_);
+
getColumnValue(r, row, FQDN_REV_COL, fqdn_rev_);
hostname_ = getRawColumnValue(r, row, HOSTNAME_COL);
/// @brief Lease4 object currently being sent to the database.
/// Storing this value ensures that it remains in scope while any bindings
/// that refer to its contents are in use.
- Lease4Ptr lease_;
-
- /// @Brief Lease4 specific members used for binding and conversion.
- uint32_t addr4_;
- size_t hwaddr_length_;
- std::vector<uint8_t> hwaddr_;
- uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
- size_t client_id_length_;
- uint8_t client_id_buffer_[ClientId::MAX_CLIENT_ID_LEN];
+ Lease4Ptr lease_;
+
+ /// @brief Lease4 specific members for binding and conversion.
+ uint32_t addr4_;
+ size_t hwaddr_length_;
+ std::vector<uint8_t> hwaddr_;
+ uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
+ size_t client_id_length_;
+ uint8_t client_id_buffer_[ClientId::MAX_CLIENT_ID_LEN];
};
/// @brief Supports exchanging IPv6 leases with PostgreSQL.
static const int FQDN_FWD_COL = 9;
static const int FQDN_REV_COL = 10;
static const int HOSTNAME_COL = 11;
- static const int STATE_COL = 12;
+ static const int HWADDR_COL = 12;
+ static const int HWTYPE_COL = 13;
+ static const int HWADDR_SOURCE_COL = 14;
+ static const int STATE_COL = 15;
//@}
/// @brief Number of columns in the table holding DHCPv6 leases.
- static const size_t LEASE_COLUMNS = 13;
+ static const size_t LEASE_COLUMNS = 16;
public:
PgSqlLease6Exchange()
: lease_(), duid_length_(0), duid_(), iaid_u_(0), iaid_str_(""),
lease_type_(Lease6::TYPE_NA), lease_type_str_(""), prefix_len_(0),
- prefix_len_str_(""), pref_lifetime_(0), preferred_lft_str_("") {
+ prefix_len_str_(""), pref_lifetime_(0), preferred_lifetime_str_("") {
- BOOST_STATIC_ASSERT(12 < LEASE_COLUMNS);
+ BOOST_STATIC_ASSERT(15 < LEASE_COLUMNS);
memset(duid_buffer_, 0, sizeof(duid_buffer_));
columns_.push_back("fqdn_fwd");
columns_.push_back("fqdn_rev");
columns_.push_back("hostname");
+ columns_.push_back("hwaddr");
+ columns_.push_back("hwtype");
+ columns_.push_back("hwaddr_source");
columns_.push_back("state");
}
isc_throw (BadValue, "IPv6 Lease cannot have a null DUID");
}
- valid_lft_str_ = boost::lexical_cast<std::string>
- (lease->valid_lft_);
- bind_array.add(valid_lft_str_);
+ valid_lifetime_str_ = boost::lexical_cast<std::string>(lease->valid_lft_);
+ bind_array.add(valid_lifetime_str_);
expire_str_ = convertToDatabaseTime(lease->cltt_, lease_->valid_lft_);
bind_array.add(expire_str_);
- subnet_id_str_ = boost::lexical_cast<std::string>
- (lease->subnet_id_);
+ subnet_id_str_ = boost::lexical_cast<std::string>(lease->subnet_id_);
bind_array.add(subnet_id_str_);
- preferred_lft_str_ = boost::lexical_cast<std::string>
- (lease_->preferred_lft_);
- bind_array.add(preferred_lft_str_);
+ preferred_lifetime_str_ = boost::lexical_cast<std::string>(lease_->preferred_lft_);
+ bind_array.add(preferred_lifetime_str_);
lease_type_str_ = boost::lexical_cast<std::string>(lease_->type_);
bind_array.add(lease_type_str_);
prefix_len_str_ = boost::lexical_cast<std::string>
(static_cast<unsigned int>(lease_->prefixlen_));
-
bind_array.add(prefix_len_str_);
bind_array.add(lease->fqdn_fwd_);
+
bind_array.add(lease->fqdn_rev_);
bind_array.add(lease->hostname_);
+ if (lease->hwaddr_ && !lease->hwaddr_->hwaddr_.empty()) {
+ // PostgreSql does not provide MAX on variable length types
+ // so we have to enforce it ourselves.
+ if (lease->hwaddr_->hwaddr_.size() > HWAddr::MAX_HWADDR_LEN) {
+ isc_throw(DbOperationError, "Hardware address length : "
+ << lease_->hwaddr_->hwaddr_.size()
+ << " exceeds maximum allowed of: "
+ << HWAddr::MAX_HWADDR_LEN);
+ }
+ bind_array.add(lease->hwaddr_->hwaddr_);
+ } else {
+ bind_array.add("");
+ }
+
+ if (lease->hwaddr_) {
+ hwtype_str_ = boost::lexical_cast<std::string>
+ (static_cast<unsigned int>(lease_->hwaddr_->htype_));
+ hwaddr_source_str_ = boost::lexical_cast<std::string>
+ (static_cast<unsigned int>(lease_->hwaddr_->source_));
+ } else {
+ hwtype_str_ = boost::lexical_cast<std::string>
+ (static_cast<unsigned int>(HTYPE_UNDEFINED));
+ hwaddr_source_str_ = boost::lexical_cast<std::string>
+ (static_cast<unsigned int>(HWAddr::HWADDR_SOURCE_UNKNOWN));
+ }
+
+ bind_array.add(hwtype_str_);
+
+ bind_array.add(hwaddr_source_str_);
+
state_str_ = boost::lexical_cast<std::string>(lease->state_);
bind_array.add(state_str_);
isc::asiolink::IOAddress addr(getIPv6Value(r, row, ADDRESS_COL));
- convertFromBytea(r, row, DUID_COL, duid_buffer_,
- sizeof(duid_buffer_), duid_length_);
+ convertFromBytea(r, row, DUID_COL, duid_buffer_, sizeof(duid_buffer_), duid_length_);
DuidPtr duid_ptr(new DUID(duid_buffer_, duid_length_));
getColumnValue(r, row, VALID_LIFETIME_COL, valid_lifetime_);
getColumnValue(r, row , PREFIX_LEN_COL, prefix_len_);
getColumnValue(r, row, FQDN_FWD_COL, fqdn_fwd_);
+
getColumnValue(r, row, FQDN_REV_COL, fqdn_rev_);
hostname_ = getRawColumnValue(r, row, HOSTNAME_COL);
+ convertFromBytea(r, row, HWADDR_COL, hwaddr_buffer_,
+ sizeof(hwaddr_buffer_), hwaddr_length_);
+
+ getColumnValue(r, row , HWTYPE_COL, hwtype_);
+
+ getColumnValue(r, row , HWADDR_SOURCE_COL, hwaddr_source_);
+
+ HWAddrPtr hwaddr(new HWAddr(hwaddr_buffer_, hwaddr_length_,
+ hwtype_));
+
+ hwaddr->source_ = hwaddr_source_;
+
uint32_t state;
getColumnValue(r, row , STATE_COL, state);
- /// @todo: implement this in #3557.
- HWAddrPtr hwaddr;
-
Lease6Ptr result(new Lease6(lease_type_, addr, duid_ptr,
iaid_u_.uval_, pref_lifetime_,
valid_lifetime_, 0, 0,
/// @brief Lease6 object currently being sent to the database.
/// Storing this value ensures that it remains in scope while any bindings
/// that refer to its contents are in use.
- Lease6Ptr lease_;
+ Lease6Ptr lease_;
/// @brief Lease6 specific members for binding and conversion.
//@{
- size_t duid_length_;
- vector<uint8_t> duid_;
- uint8_t duid_buffer_[DUID::MAX_DUID_LEN];
+ size_t duid_length_;
+ vector<uint8_t> duid_;
+ uint8_t duid_buffer_[DUID::MAX_DUID_LEN];
/// @brief Union for marshalling IAID into and out of the database
/// IAID is defined in the RFC as 4 octets, which Kea code handles as
Uiaid(int32_t val) : ival_(val){};
uint32_t uval_;
int32_t ival_;
- } iaid_u_;
-
- std::string iaid_str_;
- Lease6::Type lease_type_;
- std::string lease_type_str_;
- uint8_t prefix_len_;
- std::string prefix_len_str_;
- uint32_t pref_lifetime_;
- std::string preferred_lft_str_;
+ } iaid_u_;
+
+ std::string iaid_str_;
+ Lease6::Type lease_type_;
+ std::string lease_type_str_;
+ uint8_t prefix_len_;
+ std::string prefix_len_str_;
+ uint32_t pref_lifetime_;
+ std::string preferred_lifetime_str_;
+ size_t hwaddr_length_;
+ vector<uint8_t> hwaddr_;
+ uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
+ uint32_t hwtype_;
+ std::string hwtype_str_;
+ uint32_t hwaddr_source_;
+ std::string hwaddr_source_str_;
//@}
};
PgSqlConnection conn_;
};
-}; // end of isc::dhcp namespace
-}; // end of isc namespace
+} // namespace dhcp
+} // namespace isc
#endif // PGSQL_LEASE_MGR_H
#include <config.h>
#include <asiolink/io_address.h>
+#include <dhcpsrv/tests/test_utils.h>
+#include <exceptions/exceptions.h>
+#include <dhcpsrv/host.h>
#include <dhcpsrv/cql_connection.h>
#include <dhcpsrv/cql_host_data_source.h>
-#include <dhcpsrv/cql_lease_mgr.h>
-#include <dhcpsrv/host.h>
-#include <dhcpsrv/host_data_source_factory.h>
+#include <dhcpsrv/cql_exchange.h>
#include <dhcpsrv/tests/generic_host_data_source_unittest.h>
-#include <dhcpsrv/tests/test_utils.h>
#include <dhcpsrv/testutils/cql_schema.h>
#include <dhcpsrv/testutils/host_data_source_utils.h>
-#include <exceptions/exceptions.h>
+#include <dhcpsrv/host_data_source_factory.h>
#include <gtest/gtest.h>
#include <algorithm>
+#include <iostream>
#include <sstream>
#include <string>
#include <utility>
-namespace {
-
using namespace isc;
using namespace isc::asiolink;
using namespace isc::dhcp;
using namespace isc::dhcp::test;
+using namespace isc::data;
+using namespace std;
+
+namespace {
-/// @brief Fixture class for testing Cassandra host data source
class CqlHostDataSourceTest : public GenericHostDataSourceTest {
public:
/// @brief Clears the database and opens connection to it.
try {
HostDataSourceFactory::create(validCqlConnectionString());
} catch (...) {
- std::cerr << "*** ERROR: unable to open database. The test"
- "*** environment is broken and must be fixed before"
- "*** the CQL tests will run correctly."
- "*** The reason for the problem is described in the"
- "*** accompanying exception output.";
+ std::cerr << "*** ERROR: unable to open database. The test\n"
+ "*** environment is broken and must be fixed before\n"
+ "*** the CQL tests will run correctly.\n"
+ "*** The reason for the problem is described in the\n"
+ "*** accompanying exception output.\n";
throw;
}
/// @brief Destructor
///
- /// Rolls back all pending transactions. The deletion of myhdsptr_ will
- /// close the database. Then reopen it and delete everything created by the
- /// test.
+ /// Rolls back all pending transactions. The deletion of hdsptr_ will close
+ /// the database. Then reopen it and delete everything created by the test.
virtual ~CqlHostDataSourceTest() {
destroyTest();
}
/// opened: the fixtures assume that and check basic operations.
TEST(CqlHostDataSource, OpenDatabase) {
+
// Schema needs to be created for the test to work.
destroyCqlSchema(false, true);
createCqlSchema(false, true);
// If it fails, print the error message.
try {
HostDataSourceFactory::create(validCqlConnectionString());
- EXPECT_NO_THROW((void)HostDataSourceFactory::getHostDataSourcePtr());
+ EXPECT_NO_THROW((void) HostDataSourceFactory::getHostDataSourcePtr());
HostDataSourceFactory::destroy();
} catch (const isc::Exception& ex) {
FAIL() << "*** ERROR: unable to open database, reason:\n"
// Check that lease manager open the database opens correctly with a longer
// timeout. If it fails, print the error message.
try {
- std::string connection_string = validCqlConnectionString() + std::string(" ") +
- std::string(VALID_TIMEOUT);
+ string connection_string = validCqlConnectionString() + string(" ") +
+ string(VALID_TIMEOUT);
HostDataSourceFactory::create(connection_string);
- EXPECT_NO_THROW((void)HostDataSourceFactory::getHostDataSourcePtr());
+ EXPECT_NO_THROW((void) HostDataSourceFactory::getHostDataSourcePtr());
HostDataSourceFactory::destroy();
} catch (const isc::Exception& ex) {
FAIL() << "*** ERROR: unable to open database, reason:\n"
// (This is really a check on HostDataSourceFactory, but is convenient to
// perform here.)
EXPECT_THROW(HostDataSourceFactory::create(connectionString(
- NULL, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
- InvalidParameter);
+ NULL, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
+ InvalidParameter);
EXPECT_THROW(HostDataSourceFactory::create(connectionString(
- INVALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
- InvalidType);
+ INVALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
+ InvalidType);
// Check that invalid login data does not cause an exception, CQL should use
// default values.
- EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
- INVALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)));
- EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
- VALID_NAME, INVALID_HOST, VALID_USER, VALID_PASSWORD)));
- EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
- VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)));
- EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
- VALID_NAME, VALID_HOST, VALID_USER, INVALID_PASSWORD)));
+ EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(
+ CQL_VALID_TYPE, INVALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)));
+ EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(
+ CQL_VALID_TYPE, VALID_NAME, INVALID_HOST, VALID_USER, VALID_PASSWORD)));
+ EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(
+ CQL_VALID_TYPE, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)));
+ EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(
+ CQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, INVALID_PASSWORD)));
// Check that invalid timeouts throw DbOperationError.
- EXPECT_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
- VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_1)),
- DbOperationError);
- EXPECT_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
- VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_2)),
- DbOperationError);
+ EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ CQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_1)),
+ DbOperationError);
+ EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ CQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_2)),
+ DbOperationError);
// Check that CQL allows the hostname to not be specified.
- EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
- NULL, VALID_HOST, INVALID_USER, VALID_PASSWORD)));
+ EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(
+ CQL_VALID_TYPE, NULL, VALID_HOST, INVALID_USER, VALID_PASSWORD)));
// Tidy up after the test
destroyCqlSchema(false, true);
}
-/// @brief Check conversion methods
+/// @brief Check conversion functions
///
/// The server works using cltt and valid_filetime. In the database, the
/// information is stored as expire_time and valid-lifetime, which are
EXPECT_EQ(cltt, converted_cltt);
}
+// This test verifies that database backend can operate in Read-Only mode.
+TEST_F(CqlHostDataSourceTest, testReadOnlyDatabase) {
+ testReadOnlyDatabase(CQL_VALID_TYPE);
+}
+
// Test verifies if a host reservation can be added and later retrieved by IPv4
// address. Host uses hw address as identifier.
TEST_F(CqlHostDataSourceTest, basic4HWAddr) {
testGet4ByIdentifier(Host::IDENT_CIRCUIT_ID);
}
+// Test verifies if a host reservation can be added and later retrieved by
+// client-id.
+TEST_F(CqlHostDataSourceTest, get4ByClientId) {
+ testGet4ByIdentifier(Host::IDENT_CLIENT_ID);
+}
+
// Test verifies if hardware address and client identifier are not confused.
TEST_F(CqlHostDataSourceTest, hwaddrNotClientId1) {
testHWAddrNotClientId();
testHostname("foo.example.org", 100);
}
-// Test verifies if a host without any hostname specified can be stored and
-// later retrieved.
+// Test verifies if a host without any hostname specified can be stored and later
+// retrieved.
TEST_F(CqlHostDataSourceTest, noHostname) {
testHostname("", 1);
}
+// Test verifies if a host with user context can be stored and later retrieved.
+TEST_F(CqlHostDataSourceTest, usercontext) {
+ string comment = "{ \"comment\": \"a host reservation\" }";
+ testUserContext(Element::fromJSON(comment));
+}
+
// Test verifies if the hardware or client-id query can match hardware address.
TEST_F(CqlHostDataSourceTest, DISABLED_hwaddrOrClientId1) {
/// @todo: The logic behind ::get4(subnet_id, hwaddr, duid) call needs to
testMultipleReservationsDifferentOrder();
}
-// Test verifies if multiple client classes for IPv4 can be stored.
-TEST_F(CqlHostDataSourceTest, DISABLED_multipleClientClasses4) {
- /// @todo: Implement this test as part of #5503.
-
- /// Add host reservation with a multiple v4 client-classes, retrieve it and
- /// make sure that all client classes are retrieved properly.
+// Test that multiple client classes for IPv4 can be inserted and
+// retrieved for a given host reservation.
+TEST_F(CqlHostDataSourceTest, multipleClientClasses4) {
+ testMultipleClientClasses4();
}
-// Test verifies if multiple client classes for IPv6 can be stored.
-TEST_F(CqlHostDataSourceTest, DISABLED_multipleClientClasses6) {
- /// @todo: Implement this test as part of #5503.
-
- /// Add host reservation with a multiple v6 client-classes, retrieve it and
- /// make sure that all client classes are retrieved properly.
+// Test that multiple client classes for IPv6 can be inserted and
+// retrieved for a given host reservation.
+TEST_F(CqlHostDataSourceTest, multipleClientClasses6) {
+ testMultipleClientClasses6();
}
-// Test verifies if multiple client classes for both IPv4 and IPv6 can be
-// stored.
-TEST_F(CqlHostDataSourceTest, DISABLED_multipleClientClassesBoth) {
- /// @todo: Implement this test as part of #5503.
-
- /// Add host reservation with a multiple v4 and v6 client-classes, retrieve
- /// it and make sure that all client classes are retrieved properly. Also,
- /// check that the classes are not confused.
+// Test that multiple client classes for both IPv4 and IPv6 can
+// be inserted and retrieved for a given host reservation.
+TEST_F(CqlHostDataSourceTest, multipleClientClassesBoth) {
+ testMultipleClientClassesBoth();
}
// Test if the same host can have reservations in different subnets (with the
testMultipleSubnets(10, Host::IDENT_DUID);
}
-// Test if host reservations made for different IPv6 subnets are handled
-// correctly. The test logic is as follows:
+// Test if host reservations made for different IPv6 subnets are handled correctly.
+// The test logic is as follows:
//
// Insert 10 host reservations for different subnets. Make sure that
// get6(subnet-id, ...) calls return correct reservation.
testAddDuplicate6WithSameHWAddr();
}
-// Test if the duplicate IPv4 host instances can't be inserted. The test logic
-// is as follows: try to add multiple instances of the same host reservation and
+// Test if the duplicate IPv4 host instances can't be inserted. The test logic is as
+// follows: try to add multiple instances of the same host reservation and
// verify that the second and following attempts will throw exceptions.
TEST_F(CqlHostDataSourceTest, addDuplicate4) {
testAddDuplicate4();
// This test verifies that DHCPv4 options can be inserted in a binary format
/// and retrieved from the CQL host database.
TEST_F(CqlHostDataSourceTest, optionsReservations4) {
- testOptionsReservations4(false);
+ string comment = "{ \"comment\": \"a host reservation\" }";
+ testOptionsReservations4(false, Element::fromJSON(comment));
}
// This test verifies that DHCPv6 options can be inserted in a binary format
/// and retrieved from the CQL host database.
TEST_F(CqlHostDataSourceTest, optionsReservations6) {
- testOptionsReservations6(false);
+ string comment = "{ \"comment\": \"a host reservation\" }";
+ testOptionsReservations6(false, Element::fromJSON(comment));
}
// This test verifies that DHCPv4 and DHCPv6 options can be inserted in a
// This test verifies that DHCPv4 options can be inserted in a textual format
/// and retrieved from the CQL host database.
TEST_F(CqlHostDataSourceTest, formattedOptionsReservations4) {
- testOptionsReservations4(true);
+ string comment = "{ \"comment\": \"a host reservation\" }";
+ testOptionsReservations4(true, Element::fromJSON(comment));
}
// This test verifies that DHCPv6 options can be inserted in a textual format
/// and retrieved from the CQL host database.
TEST_F(CqlHostDataSourceTest, formattedOptionsReservations6) {
- testOptionsReservations6(true);
+ string comment = "{ \"comment\": \"a host reservation\" }";
+ testOptionsReservations6(true, Element::fromJSON(comment));
}
// This test verifies that DHCPv4 and DHCPv6 options can be inserted in a
// retrieve the data from ipv6_reservations table. The query should
// pass but return no host because the (insert) transaction is expected
// to be rolled back.
- ASSERT_THROW(
- hdsptr_->get4(host->getIPv4SubnetID(), host->getIdentifierType(),
- &host->getIdentifier()[0], host->getIdentifier().size()),
- DbOperationError);
+ ASSERT_THROW(hdsptr_->get4(host->getIPv4SubnetID(),
+ host->getIdentifierType(),
+ &host->getIdentifier()[0],
+ host->getIdentifier().size()),
+ DbOperationError);
}
TEST_F(CqlHostDataSourceTest, DISABLED_stressTest) {
// This test checks that siaddr, sname, file fields can be retrieved
/// from a database for a host.
-/// @todo: Uncomment this after 5507 is implemented.
-TEST_F(CqlHostDataSourceTest, DISABLED_messageFields) {
+TEST_F(CqlHostDataSourceTest, messageFields) {
testMessageFields4();
}
// Tests that multiple reservations without IPv4 addresses can be
// specified within a subnet.
/// @todo: Uncomment this after #5506 is implemented.
-TEST_F(CqlHostDataSourceTest, DISABLED_testMultipleHostsNoAddress4) {
+TEST_F(CqlHostDataSourceTest, testMultipleHostsNoAddress4) {
testMultipleHostsNoAddress4();
}
// Tests that multiple hosts can be specified within an IPv6 subnet.
/// @todo: Uncomment this after #5506 is implemented.
-TEST_F(CqlHostDataSourceTest, DISABLED_testMultipleHosts6) {
+TEST_F(CqlHostDataSourceTest, testMultipleHosts6) {
testMultipleHosts6();
}
+// Copyright (C) 2012-2018 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2015-2017 Deutsche Telekom AG.
//
// Authors: Razvan Becheriu <razvan.becheriu@qualitance.com>
#include <config.h>
-#include <gtest/gtest.h>
-
#include <asiolink/io_address.h>
+#include <dhcpsrv/lease_mgr_factory.h>
#include <dhcpsrv/cql_connection.h>
#include <dhcpsrv/cql_lease_mgr.h>
-#include <dhcpsrv/lease_mgr_factory.h>
-#include <dhcpsrv/tests/generic_lease_mgr_unittest.h>
#include <dhcpsrv/tests/test_utils.h>
+#include <dhcpsrv/tests/generic_lease_mgr_unittest.h>
#include <dhcpsrv/testutils/cql_schema.h>
#include <exceptions/exceptions.h>
+#include <gtest/gtest.h>
+
#include <algorithm>
+#include <iostream>
#include <sstream>
#include <string>
#include <utility>
using namespace isc::asiolink;
using namespace isc::dhcp;
using namespace isc::dhcp::test;
+using namespace std;
namespace {
+
/// @brief Test fixture class for testing Cassandra Lease Manager
///
/// Opens the database prior to each test and closes it afterwards.
/// All pending transactions are deleted prior to closure.
+
class CqlLeaseMgrTest : public GenericLeaseMgrTest {
public:
/// @brief Clears the database and opens connection to it.
/// @brief Destructor
///
- /// Rolls back all pending transactions. The deletion of lmptr_ will close
- /// the database. Then reopen it and delete everything created by the test.
+ /// Rolls back all pending transactions. The deletion of lmptr_ will close
+ /// the database. Then reopen it and delete everything created by the test.
virtual ~CqlLeaseMgrTest() {
destroyTest();
}
/// @brief Reopen the database
///
- /// Closes the database and re-open it. Anything committed should be
+ /// Closes the database and re-open it. Anything committed should be
/// visible.
///
- /// Parameter is ignored for CQL backend as the v4 and v6 leases share the
- /// same keyspace.
+ /// Parameter is ignored for CQL backend as the v4 and v6 leases share
+ /// the same database.
void reopen(Universe) {
LeaseMgrFactory::destroy();
LeaseMgrFactory::create(validCqlConnectionString());
/// @brief Check that database can be opened
///
-/// This test checks if the CqlLeaseMgr can be instantiated. This happens
-/// only if the database can be opened. Note that this is not part of the
-/// CqlLeaseMgr test fixure set. This test checks that the database can be
+/// This test checks if the CqlLeaseMgr can be instantiated. This happens
+/// only if the database can be opened. Note that this is not part of the
+/// CqlLeaseMgr test fixure set. This test checks that the database can be
/// opened: the fixtures assume that and check basic operations.
-/// Unlike other backend implementations, this one doesn't check for lacking
-/// parameters. In that scenario, Cassandra defaults to configured parameters.
+
TEST(CqlOpenTest, OpenDatabase) {
+
// Schema needs to be created for the test to work.
destroyCqlSchema(false, true);
createCqlSchema(false, true);
}
// Check that lease manager open the database opens correctly with a longer
- // timeout. If it fails, print the error message.
+ // timeout. If it fails, print the error message.
try {
- std::string connection_string = validCqlConnectionString() +
- std::string(" ") +
- std::string(VALID_TIMEOUT);
+ string connection_string = validCqlConnectionString() + string(" ") +
+ string(VALID_TIMEOUT);
LeaseMgrFactory::create(connection_string);
- EXPECT_NO_THROW((void)LeaseMgrFactory::instance());
+ EXPECT_NO_THROW((void) LeaseMgrFactory::instance());
LeaseMgrFactory::destroy();
} catch (const isc::Exception& ex) {
FAIL() << "*** ERROR: unable to open database, reason:\n"
// Check that wrong specification of backend throws an exception.
// (This is really a check on LeaseMgrFactory, but is convenient to
// perform here.)
- EXPECT_THROW(
- LeaseMgrFactory::create(connectionString(NULL, VALID_NAME, VALID_HOST,
- INVALID_USER, VALID_PASSWORD)),
+ EXPECT_THROW(LeaseMgrFactory::create(connectionString(
+ NULL, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
InvalidParameter);
- EXPECT_THROW(
- LeaseMgrFactory::create(connectionString(
- INVALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
+
+ EXPECT_THROW(LeaseMgrFactory::create(connectionString(
+ INVALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
InvalidType);
// Check that invalid login data does not cause an exception, CQL should use
// default values.
EXPECT_NO_THROW(LeaseMgrFactory::create(connectionString(
CQL_VALID_TYPE, INVALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)));
+
EXPECT_NO_THROW(LeaseMgrFactory::create(connectionString(
CQL_VALID_TYPE, VALID_NAME, INVALID_HOST, VALID_USER, VALID_PASSWORD)));
+
EXPECT_NO_THROW(LeaseMgrFactory::create(connectionString(
CQL_VALID_TYPE, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)));
+
EXPECT_NO_THROW(LeaseMgrFactory::create(connectionString(
CQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, INVALID_PASSWORD)));
- // Check that invalid timeouts throw DbOperationError.
+ // Check for invalid timeouts
EXPECT_THROW(LeaseMgrFactory::create(connectionString(
- CQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER,
- VALID_PASSWORD, INVALID_TIMEOUT_1)),
- DbOperationError);
+ CQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_1)),
+ DbOperationError);
+
EXPECT_THROW(LeaseMgrFactory::create(connectionString(
- CQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER,
- VALID_PASSWORD, INVALID_TIMEOUT_2)),
- DbOperationError);
+ CQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_2)),
+ DbOperationError);
- // Check that CQL allows the hostname to not be specified.
+ // Check for missing parameters
EXPECT_NO_THROW(LeaseMgrFactory::create(connectionString(
CQL_VALID_TYPE, NULL, VALID_HOST, INVALID_USER, VALID_PASSWORD)));
// default values.
EXPECT_NO_THROW(LeaseMgrFactory::create(connectionString(
CQL_VALID_TYPE, INVALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)));
+
EXPECT_NO_THROW(LeaseMgrFactory::create(connectionString(
CQL_VALID_TYPE, VALID_NAME, INVALID_HOST, VALID_USER, VALID_PASSWORD)));
+
EXPECT_NO_THROW(LeaseMgrFactory::create(connectionString(
CQL_VALID_TYPE, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)));
+
EXPECT_NO_THROW(LeaseMgrFactory::create(connectionString(
CQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, INVALID_PASSWORD)));
// Check that invalid timeouts throw DbOperationError.
EXPECT_THROW(LeaseMgrFactory::create(connectionString(
- CQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER,
- VALID_PASSWORD, INVALID_TIMEOUT_1)),
- DbOperationError);
+ CQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD,
+ INVALID_TIMEOUT_1)),
+ DbOperationError);
EXPECT_THROW(LeaseMgrFactory::create(connectionString(
- CQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER,
- VALID_PASSWORD, INVALID_TIMEOUT_2)),
- DbOperationError);
+ CQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD,
+ INVALID_TIMEOUT_2)),
+ DbOperationError);
// Check that CQL allows the hostname to not be specified.
EXPECT_NO_THROW(LeaseMgrFactory::create(connectionString(
EXPECT_EQ(std::string("cql"), lmptr_->getType());
}
-/// @brief Check conversion methods
+/// @brief Check conversion functions
///
-/// The server works using cltt and valid_filetime. In the database, the
+/// The server works using cltt and valid_filetime. In the database, the
/// information is stored as expire_time and valid-lifetime, which are
/// related by
///
// Convert to the database time.
CqlExchange::convertToDatabaseTime(cltt, valid_lft, cql_expire);
- // Convert back.
+ // Convert back
time_t converted_cltt = 0;
CqlExchange::convertFromDatabaseTime(cql_expire, valid_lft, converted_cltt);
EXPECT_EQ(cltt, converted_cltt);
}
-/// @brief Check getName() returns correct keyspace name.
+/// @brief Check getName() returns correct database name
TEST_F(CqlLeaseMgrTest, getName) {
EXPECT_EQ(std::string("keatest"), lmptr_->getName());
}
/// @brief Check that getVersion() returns the expected version
TEST_F(CqlLeaseMgrTest, checkVersion) {
// Check version
- VersionPair version;
+ pair<uint32_t, uint32_t> version;
ASSERT_NO_THROW(version = lmptr_->getVersion());
EXPECT_EQ(CQL_SCHEMA_VERSION_MAJOR, version.first);
EXPECT_EQ(CQL_SCHEMA_VERSION_MINOR, version.second);
testGetLease4ClientIdSubnetId();
}
+// This test checks that all IPv4 leases for a specified subnet id are returned.
+TEST_F(CqlLeaseMgrTest, getLeases4SubnetId) {
+ testGetLeases4SubnetId();
+}
+
+// This test checks that all IPv4 leases are returned.
+TEST_F(CqlLeaseMgrTest, getLeases4) {
+ testGetLeases4();
+}
+
/// @brief Basic Lease4 Checks
///
-/// Checks that the addLease, getLease4(by address), getLease4(hwaddr,
-/// subnet_id),
+/// Checks that the addLease, getLease4(by address), getLease4(hwaddr,subnet_id),
/// updateLease4() and deleteLease can handle NULL client-id.
/// (client-id is optional and may not be present)
TEST_F(CqlLeaseMgrTest, lease4NullClientId) {
testLease4InvalidHostname();
}
+/// @brief Check that the expired DHCPv4 leases can be retrieved.
+///
+/// This test adds a number of leases to the lease database and marks
+/// some of them as expired. Then it queries for expired leases and checks
+/// whether only expired leases are returned, and that they are returned in
+/// the order from most to least expired. It also checks that the lease
+/// which is marked as 'reclaimed' is not returned.
+TEST_F(CqlLeaseMgrTest, getExpiredLeases4) {
+ testCqlGetExpiredLeases4();
+}
+
+/// @brief Check that expired reclaimed DHCPv4 leases are removed.
+TEST_F(CqlLeaseMgrTest, deleteExpiredReclaimedLeases4) {
+ testDeleteExpiredReclaimedLeases4();
+}
+
////////////////////////////////////////////////////////////////////////////////
/// LEASE6 /////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
testLease6HWTypeAndSource();
}
-/// @brief Check that the expired DHCPv4 leases can be retrieved.
-///
-/// This test adds a number of leases to the lease database and marks
-/// some of them as expired. Then it queries for expired leases and checks
-/// whether only expired leases are returned, and that they are returned in
-/// the order from most to least expired. It also checks that the lease
-/// which is marked as 'reclaimed' is not returned.
-TEST_F(CqlLeaseMgrTest, getExpiredLeases4) {
- testCqlGetExpiredLeases4();
-}
-
/// @brief Check that the expired DHCPv6 leases can be retrieved.
///
/// This test adds a number of leases to the lease database and marks
testDeleteExpiredReclaimedLeases6();
}
-/// @brief Check that expired reclaimed DHCPv4 leases are removed.
-TEST_F(CqlLeaseMgrTest, deleteExpiredReclaimedLeases4) {
- testDeleteExpiredReclaimedLeases4();
-}
-
// Verifies that IPv4 lease statistics can be recalculated.
/// @todo: uncomment this once stats recalculation is implemented
/// for Cassandra (see #5487)
}
} // namespace
-
/// @brief Destructor
///
- /// Rolls back all pending transactions. The deletion of myhdsptr_ will close
+ /// Rolls back all pending transactions. The deletion of hdsptr_ will close
/// the database. Then reopen it and delete everything created by the test.
virtual ~MySqlHostDataSourceTest() {
destroyTest();
/// @brief Destructor
///
- /// Rolls back all pending transactions. The deletion of myhdsptr_ will close
+ /// Rolls back all pending transactions. The deletion of hdsptr_ will close
/// the database. Then reopen it and delete everything created by the test.
virtual ~PgSqlHostDataSourceTest() {
destroyTest();
#include <asiolink/io_address.h>
#include <dhcpsrv/lease_mgr_factory.h>
+#include <dhcpsrv/pgsql_connection.h>
#include <dhcpsrv/pgsql_lease_mgr.h>
#include <dhcpsrv/tests/test_utils.h>
#include <dhcpsrv/tests/generic_lease_mgr_unittest.h>
#include <gtest/gtest.h>
+#include <algorithm>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <utility>
+
using namespace isc;
using namespace isc::asiolink;
using namespace isc::dhcp;
namespace {
+
/// @brief Test fixture class for testing PostgreSQL Lease Manager
///
/// Opens the database prior to each test and closes it afterwards.
class PgSqlLeaseMgrTest : public GenericLeaseMgrTest {
public:
- /// @brief Constructor
- ///
- /// Deletes everything from the database and opens it.
- PgSqlLeaseMgrTest() {
-
+ /// @brief Clears the database and opens connection to it.
+ void initializeTest() {
// Ensure schema is the correct one.
destroyPgSQLSchema();
createPgSQLSchema();
"*** accompanying exception output.\n";
throw;
}
+
lmptr_ = &(LeaseMgrFactory::instance());
}
+ /// @brief Destroys the LM and the schema.
+ void destroyTest() {
+ try {
+ lmptr_->rollback();
+ } catch (...) {
+ // Rollback may fail if backend is in read only mode. That's ok.
+ }
+ LeaseMgrFactory::destroy();
+ destroyPgSQLSchema();
+ }
+
+ /// @brief Constructor
+ ///
+ /// Deletes everything from the database and opens it.
+ PgSqlLeaseMgrTest() {
+ initializeTest();
+ }
+
/// @brief Destructor
///
/// Rolls back all pending transactions. The deletion of lmptr_ will close
/// the database. Then reopen it and delete everything created by the test.
virtual ~PgSqlLeaseMgrTest() {
- lmptr_->rollback();
- LeaseMgrFactory::destroy();
- destroyPgSQLSchema();
+ destroyTest();
}
/// @brief Reopen the database
/// Closes the database and re-open it. Anything committed should be
/// visible.
///
- /// Parameter is ignored for Postgres backend as the v4 and v6 leases share
+ /// Parameter is ignored for PostgreSQL backend as the v4 and v6 leases share
/// the same database.
void reopen(Universe) {
LeaseMgrFactory::destroy();
LeaseMgrFactory::create(validPgSQLConnectionString());
lmptr_ = &(LeaseMgrFactory::instance());
}
-
};
/// @brief Check that database can be opened
// If it fails, print the error message.
try {
LeaseMgrFactory::create(validPgSQLConnectionString());
- EXPECT_NO_THROW((void) LeaseMgrFactory::instance());
+ EXPECT_NO_THROW((void)LeaseMgrFactory::instance());
LeaseMgrFactory::destroy();
} catch (const isc::Exception& ex) {
FAIL() << "*** ERROR: unable to open database, reason:\n"
EXPECT_THROW(LeaseMgrFactory::create(connectionString(
PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_1)),
DbInvalidTimeout);
+
EXPECT_THROW(LeaseMgrFactory::create(connectionString(
PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_2)),
DbInvalidTimeout);
/// @brief Basic Lease4 Checks
///
/// Checks that the addLease, getLease4(by address), getLease4(hwaddr,subnet_id),
-/// updateLease4() and deleteLease (IPv4 address) can handle NULL client-id.
+/// updateLease4() and deleteLease can handle NULL client-id.
/// (client-id is optional and may not be present)
TEST_F(PgSqlLeaseMgrTest, lease4NullClientId) {
testLease4NullClientId();
testUpdateLease6();
}
+/// @brief DHCPv4 Lease recreation tests
+///
+/// Checks that the lease can be created, deleted and recreated with
+/// different parameters. It also checks that the re-created lease is
+/// correctly stored in the lease database.
+TEST_F(PgSqlLeaseMgrTest, testRecreateLease4) {
+ testRecreateLease4();
+}
+
+/// @brief DHCPv6 Lease recreation tests
+///
+/// Checks that the lease can be created, deleted and recreated with
+/// different parameters. It also checks that the re-created lease is
+/// correctly stored in the lease database.
+TEST_F(PgSqlLeaseMgrTest, testRecreateLease6) {
+ testRecreateLease6();
+}
+
+/// @brief Checks that null DUID is not allowed.
TEST_F(PgSqlLeaseMgrTest, nullDuid) {
testNullDuid();
}
+/// @brief Tests whether memfile can store and retrieve hardware addresses
+TEST_F(PgSqlLeaseMgrTest, testLease6Mac) {
+ testLease6MAC();
+}
+
+/// @brief Tests whether memfile can store and retrieve hardware addresses
+TEST_F(PgSqlLeaseMgrTest, testLease6HWTypeAndSource) {
+ testLease6HWTypeAndSource();
+}
+
/// @brief Check that the expired DHCPv6 leases can be retrieved.
///
/// This test adds a number of leases to the lease database and marks
testGetExpiredLeases6();
}
+/// @brief Check that expired reclaimed DHCPv6 leases are removed.
+TEST_F(PgSqlLeaseMgrTest, deleteExpiredReclaimedLeases6) {
+ testDeleteExpiredReclaimedLeases6();
+}
+
// Verifies that IPv4 lease statistics can be recalculated.
TEST_F(PgSqlLeaseMgrTest, recountLeaseStats4) {
testRecountLeaseStats4();
testWipeLeases6();
}
-}; // namespace
+} // namespace