mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-09-01 22:45:18 +00:00
[master] kea-dhcp4 and kea-dhcp6 now recalculate lease stats after reconfigure
Merges in trac4294
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include <dhcp/iface_mgr.h>
|
||||
#include <dhcpsrv/cfg_subnets4.h>
|
||||
#include <dhcpsrv/dhcpsrv_log.h>
|
||||
#include <dhcpsrv/lease_mgr_factory.h>
|
||||
#include <dhcpsrv/subnet_id.h>
|
||||
#include <dhcpsrv/addr_utilities.h>
|
||||
#include <asiolink/io_address.h>
|
||||
@@ -232,18 +233,21 @@ CfgSubnets4::removeStatistics() {
|
||||
using namespace isc::stats;
|
||||
|
||||
// For each v4 subnet currently configured, remove the statistic.
|
||||
/// @todo: May move this to CfgSubnets4 class if there will be more
|
||||
/// statistics here.
|
||||
StatsMgr& stats_mgr = StatsMgr::instance();
|
||||
for (Subnet4Collection::const_iterator subnet4 = subnets_.begin();
|
||||
subnet4 != subnets_.end(); ++subnet4) {
|
||||
|
||||
StatsMgr::instance().del(StatsMgr::generateName("subnet",
|
||||
(*subnet4)->getID(),
|
||||
SubnetID subnet_id = (*subnet4)->getID();
|
||||
stats_mgr.del(StatsMgr::generateName("subnet", subnet_id,
|
||||
"total-addresses"));
|
||||
|
||||
StatsMgr::instance().del(StatsMgr::generateName("subnet",
|
||||
(*subnet4)->getID(),
|
||||
stats_mgr.del(StatsMgr::generateName("subnet", subnet_id,
|
||||
"assigned-addresses"));
|
||||
|
||||
stats_mgr.del(StatsMgr::generateName("subnet", subnet_id,
|
||||
"declined-addresses"));
|
||||
|
||||
stats_mgr.del(StatsMgr::generateName("subnet", subnet_id,
|
||||
"declined-reclaimed-addresses"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,14 +255,21 @@ void
|
||||
CfgSubnets4::updateStatistics() {
|
||||
using namespace isc::stats;
|
||||
|
||||
/// @todo: May move this to CfgSubnets4 class if there will be more
|
||||
/// statistics here.
|
||||
for (Subnet4Collection::const_iterator subnet = subnets_.begin();
|
||||
subnet != subnets_.end(); ++subnet) {
|
||||
StatsMgr& stats_mgr = StatsMgr::instance();
|
||||
for (Subnet4Collection::const_iterator subnet4 = subnets_.begin();
|
||||
subnet4 != subnets_.end(); ++subnet4) {
|
||||
SubnetID subnet_id = (*subnet4)->getID();
|
||||
|
||||
StatsMgr::instance().setValue(
|
||||
StatsMgr::generateName("subnet", (*subnet)->getID(), "total-addresses"),
|
||||
static_cast<int64_t>((*subnet)->getPoolCapacity(Lease::TYPE_V4)));
|
||||
stats_mgr.setValue(StatsMgr::
|
||||
generateName("subnet", subnet_id, "total-addresses"),
|
||||
static_cast<int64_t>
|
||||
((*subnet4)->getPoolCapacity(Lease::
|
||||
TYPE_V4)));
|
||||
}
|
||||
|
||||
// Only recount the stats if we have subnets.
|
||||
if (subnets_.begin() != subnets_.end()) {
|
||||
LeaseMgrFactory::instance().recountLeaseStats4();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
|
||||
// Copyright (C) 2014-2016 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
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <config.h>
|
||||
#include <dhcpsrv/cfg_subnets6.h>
|
||||
#include <dhcpsrv/dhcpsrv_log.h>
|
||||
#include <dhcpsrv/lease_mgr_factory.h>
|
||||
#include <dhcpsrv/subnet_id.h>
|
||||
#include <stats/stats_mgr.h>
|
||||
|
||||
@@ -176,25 +177,26 @@ void
|
||||
CfgSubnets6::removeStatistics() {
|
||||
using namespace isc::stats;
|
||||
|
||||
StatsMgr& stats_mgr = StatsMgr::instance();
|
||||
// For each v6 subnet currently configured, remove the statistics.
|
||||
for (Subnet6Collection::const_iterator subnet6 = subnets_.begin();
|
||||
subnet6 != subnets_.end(); ++subnet6) {
|
||||
SubnetID subnet_id = (*subnet6)->getID();
|
||||
stats_mgr.del(StatsMgr::generateName("subnet", subnet_id, "total-nas"));
|
||||
|
||||
StatsMgr::instance().del(StatsMgr::generateName("subnet",
|
||||
(*subnet6)->getID(),
|
||||
"total-nas"));
|
||||
|
||||
StatsMgr::instance().del(StatsMgr::generateName("subnet",
|
||||
(*subnet6)->getID(),
|
||||
stats_mgr.del(StatsMgr::generateName("subnet", subnet_id,
|
||||
"assigned-nas"));
|
||||
|
||||
StatsMgr::instance().del(StatsMgr::generateName("subnet",
|
||||
(*subnet6)->getID(),
|
||||
"total-pds"));
|
||||
stats_mgr.del(StatsMgr::generateName("subnet", subnet_id, "total-pds"));
|
||||
|
||||
StatsMgr::instance().del(StatsMgr::generateName("subnet",
|
||||
(*subnet6)->getID(),
|
||||
stats_mgr.del(StatsMgr::generateName("subnet", subnet_id,
|
||||
"assigned-pds"));
|
||||
|
||||
stats_mgr.del(StatsMgr::generateName("subnet", subnet_id,
|
||||
"declined-addresses"));
|
||||
|
||||
stats_mgr.del(StatsMgr::generateName("subnet", subnet_id,
|
||||
"declined-reclaimed-addresses"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,16 +204,26 @@ void
|
||||
CfgSubnets6::updateStatistics() {
|
||||
using namespace isc::stats;
|
||||
|
||||
for (Subnet6Collection::const_iterator subnet = subnets_.begin();
|
||||
subnet != subnets_.end(); ++subnet) {
|
||||
StatsMgr& stats_mgr = StatsMgr::instance();
|
||||
// For each v6 subnet currently configured, calculate totals
|
||||
for (Subnet6Collection::const_iterator subnet6 = subnets_.begin();
|
||||
subnet6 != subnets_.end(); ++subnet6) {
|
||||
SubnetID subnet_id = (*subnet6)->getID();
|
||||
|
||||
StatsMgr::instance().setValue(
|
||||
StatsMgr::generateName("subnet", (*subnet)->getID(), "total-nas"),
|
||||
static_cast<int64_t>((*subnet)->getPoolCapacity(Lease::TYPE_NA)));
|
||||
stats_mgr.setValue(StatsMgr::generateName("subnet", subnet_id,
|
||||
"total-nas"),
|
||||
static_cast<int64_t>
|
||||
((*subnet6)->getPoolCapacity(Lease::TYPE_NA)));
|
||||
|
||||
StatsMgr::instance().setValue(
|
||||
StatsMgr::generateName("subnet", (*subnet)->getID(), "total-pds"),
|
||||
static_cast<int64_t>((*subnet)->getPoolCapacity(Lease::TYPE_PD)));
|
||||
stats_mgr.setValue(StatsMgr::generateName("subnet", subnet_id,
|
||||
"total-pds"),
|
||||
static_cast<int64_t>
|
||||
((*subnet6)->getPoolCapacity(Lease::TYPE_PD)));
|
||||
}
|
||||
|
||||
// Only recount the stats if we have subnets.
|
||||
if (subnets_.begin() != subnets_.end()) {
|
||||
LeaseMgrFactory::instance().recountLeaseStats6();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -52,8 +52,6 @@ struct Lease {
|
||||
/// @brief Expired and reclaimed lease.
|
||||
static const uint32_t STATE_EXPIRED_RECLAIMED;
|
||||
|
||||
//@}
|
||||
|
||||
/// @brief Returns name(s) of the basic lease state(s).
|
||||
///
|
||||
/// @param state A numeric value holding a state information.
|
||||
|
@@ -6,8 +6,11 @@
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <dhcpsrv/cfgmgr.h>
|
||||
#include <dhcpsrv/dhcpsrv_log.h>
|
||||
#include <dhcpsrv/lease_mgr.h>
|
||||
#include <exceptions/exceptions.h>
|
||||
#include <stats/stats_mgr.h>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
@@ -44,6 +47,166 @@ LeaseMgr::getLease6(Lease::Type type, const DUID& duid,
|
||||
return (*col.begin());
|
||||
}
|
||||
|
||||
void
|
||||
LeaseMgr::recountLeaseStats4() {
|
||||
using namespace stats;
|
||||
|
||||
StatsMgr& stats_mgr = StatsMgr::instance();
|
||||
|
||||
LeaseStatsQueryPtr query = startLeaseStatsQuery4();
|
||||
if (!query) {
|
||||
/// NULL means not backend does not support recounting.
|
||||
return;
|
||||
}
|
||||
|
||||
// Zero out the global stats.
|
||||
int64_t zero = 0;
|
||||
stats_mgr.setValue("declined-addresses", zero);
|
||||
stats_mgr.setValue("declined-reclaimed-addresses", zero);
|
||||
|
||||
// Clear subnet level stats. This ensures we don't end up with corner
|
||||
// cases that leave stale values in place.
|
||||
const Subnet4Collection* subnets =
|
||||
CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
|
||||
|
||||
for (Subnet4Collection::const_iterator subnet = subnets->begin();
|
||||
subnet != subnets->end(); ++subnet) {
|
||||
SubnetID subnet_id = (*subnet)->getID();
|
||||
stats_mgr.setValue(StatsMgr::generateName("subnet", subnet_id,
|
||||
"assigned-addresses"),
|
||||
zero);
|
||||
|
||||
stats_mgr.setValue(StatsMgr::generateName("subnet", subnet_id,
|
||||
"declined-addresses"),
|
||||
zero);
|
||||
stats_mgr.setValue(StatsMgr::generateName("subnet", subnet_id,
|
||||
"declined-reclaimed-addresses"),
|
||||
zero);
|
||||
}
|
||||
|
||||
// Get counts per state per subnet. Iterate over the result set
|
||||
// updating the subnet and global values.
|
||||
LeaseStatsRow row;
|
||||
while (query->getNextRow(row)) {
|
||||
if (row.lease_state_ == Lease::STATE_DEFAULT) {
|
||||
// Set subnet level value.
|
||||
stats_mgr.setValue(StatsMgr::generateName("subnet", row.subnet_id_,
|
||||
"assigned-addresses"),
|
||||
row.state_count_);
|
||||
} else if (row.lease_state_ == Lease::STATE_DECLINED) {
|
||||
// Set subnet level value.
|
||||
stats_mgr.setValue(StatsMgr::generateName("subnet", row.subnet_id_,
|
||||
"declined-addresses"),
|
||||
row.state_count_);
|
||||
|
||||
// Add to the global value.
|
||||
stats_mgr.addValue("declined-addresses", row.state_count_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LeaseStatsQueryPtr
|
||||
LeaseMgr::startLeaseStatsQuery4() {
|
||||
return(LeaseStatsQueryPtr());
|
||||
}
|
||||
|
||||
bool
|
||||
LeaseStatsQuery::getNextRow(LeaseStatsRow& /*row*/) {
|
||||
return (false);
|
||||
}
|
||||
|
||||
void
|
||||
LeaseMgr::recountLeaseStats6() {
|
||||
using namespace stats;
|
||||
|
||||
StatsMgr& stats_mgr = StatsMgr::instance();
|
||||
|
||||
LeaseStatsQueryPtr query = startLeaseStatsQuery6();
|
||||
if (!query) {
|
||||
/// NULL means not backend does not support recounting.
|
||||
return;
|
||||
}
|
||||
|
||||
// Zero out the global stats. (Ok, so currently there's only one
|
||||
// that should be cleared. "reclaimed-declined-addresses" never
|
||||
// gets zeroed. @todo discuss with Tomek the rational of not
|
||||
// clearing it when we clear the rest.
|
||||
int64_t zero = 0;
|
||||
stats_mgr.setValue("declined-addresses", zero);
|
||||
stats_mgr.setValue("declined-reclaimed-addresses", zero);
|
||||
|
||||
// Clear subnet level stats. This ensures we don't end up with corner
|
||||
// cases that leave stale values in place.
|
||||
const Subnet6Collection* subnets =
|
||||
CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
|
||||
|
||||
for (Subnet6Collection::const_iterator subnet = subnets->begin();
|
||||
subnet != subnets->end(); ++subnet) {
|
||||
SubnetID subnet_id = (*subnet)->getID();
|
||||
stats_mgr.setValue(StatsMgr::generateName("subnet", subnet_id,
|
||||
"assigned-nas"),
|
||||
zero);
|
||||
|
||||
stats_mgr.setValue(StatsMgr::generateName("subnet", subnet_id,
|
||||
"declined-addresses"),
|
||||
zero);
|
||||
|
||||
stats_mgr.setValue(StatsMgr::
|
||||
generateName("subnet", subnet_id,
|
||||
"declined-reclaimed-addresses"),
|
||||
zero);
|
||||
|
||||
stats_mgr.setValue(StatsMgr::generateName("subnet", subnet_id,
|
||||
"assigned-pds"),
|
||||
zero);
|
||||
}
|
||||
|
||||
// Get counts per state per subnet. Iterate over the result set
|
||||
// updating the subnet and global values.
|
||||
LeaseStatsRow row;
|
||||
while (query->getNextRow(row)) {
|
||||
switch(row.lease_type_) {
|
||||
case Lease::TYPE_NA:
|
||||
if (row.lease_state_ == Lease::STATE_DEFAULT) {
|
||||
// Set subnet level value.
|
||||
stats_mgr.setValue(StatsMgr::
|
||||
generateName("subnet", row.subnet_id_,
|
||||
"assigned-nas"),
|
||||
row.state_count_);
|
||||
} if (row.lease_state_ == Lease::STATE_DECLINED) {
|
||||
// Set subnet level value.
|
||||
stats_mgr.setValue(StatsMgr::
|
||||
generateName("subnet", row.subnet_id_,
|
||||
"declined-addresses"),
|
||||
row.state_count_);
|
||||
|
||||
// Add to the global value.
|
||||
stats_mgr.addValue("declined-addresses", row.state_count_);
|
||||
}
|
||||
break;
|
||||
|
||||
case Lease::TYPE_PD:
|
||||
if (row.lease_state_ == Lease::STATE_DEFAULT) {
|
||||
// Set subnet level value.
|
||||
stats_mgr.setValue(StatsMgr::
|
||||
generateName("subnet", row.subnet_id_,
|
||||
"assigned-pds"),
|
||||
row.state_count_);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// We dont' support TYPE_TAs yet
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LeaseStatsQueryPtr
|
||||
LeaseMgr::startLeaseStatsQuery6() {
|
||||
return(LeaseStatsQueryPtr());
|
||||
}
|
||||
|
||||
std::string
|
||||
LeaseMgr::getDBVersion() {
|
||||
isc_throw(NotImplemented, "LeaseMgr::getDBVersion() called");
|
||||
|
@@ -146,6 +146,86 @@ public:
|
||||
virtual ~SqlExchange() {};
|
||||
ExchangeColumnInfoContainer parameters_; ///< Column names and types
|
||||
};
|
||||
|
||||
/// @brief Contains a single row of lease statistical data
|
||||
///
|
||||
/// The contents of the row consist of a subnet ID, a lease
|
||||
/// type, a lease state, and the number of leases in that state
|
||||
/// for that type for that subnet ID.
|
||||
struct LeaseStatsRow {
|
||||
/// @brief Default constructor
|
||||
LeaseStatsRow() :
|
||||
subnet_id_(0), lease_type_(Lease::TYPE_NA),
|
||||
lease_state_(Lease::STATE_DEFAULT), state_count_(0) {
|
||||
}
|
||||
|
||||
/// @brief Constructor
|
||||
///
|
||||
/// Constructor which defaults the type to TYPE_NA.
|
||||
///
|
||||
/// @param subnet_id The subnet id to which this data applies
|
||||
/// @param lease_state The lease state counted
|
||||
/// @param state_count The count of leases in the lease state
|
||||
LeaseStatsRow(const SubnetID& subnet_id, const uint32_t lease_state,
|
||||
const int64_t state_count)
|
||||
: subnet_id_(subnet_id), lease_type_(Lease::TYPE_NA),
|
||||
lease_state_(lease_state), state_count_(state_count) {
|
||||
}
|
||||
|
||||
/// @brief Constructor
|
||||
///
|
||||
/// @param subnet_id The subnet id to which this data applies
|
||||
/// @param lease_type The lease type for this state count
|
||||
/// @param lease_state The lease state counted
|
||||
/// @param state_count The count of leases in the lease state
|
||||
LeaseStatsRow(const SubnetID& subnet_id, const Lease::Type& lease_type,
|
||||
const uint32_t lease_state, const int64_t state_count)
|
||||
: subnet_id_(subnet_id), lease_type_(lease_type),
|
||||
lease_state_(lease_state), state_count_(state_count) {
|
||||
}
|
||||
|
||||
/// @brief The subnet ID to which this data applies
|
||||
SubnetID subnet_id_;
|
||||
/// @brief The lease_type to which the count applies
|
||||
Lease::Type lease_type_;
|
||||
/// @brief The lease_state to which the count applies
|
||||
uint32_t lease_state_;
|
||||
/// @brief state_count The count of leases in the lease state
|
||||
int64_t state_count_;
|
||||
};
|
||||
|
||||
/// @brief Base class for fulfilling a statistical lease data query
|
||||
///
|
||||
/// LeaseMgr derivations implement this class such that it provides
|
||||
/// upto date statistical lease data organized as rows of LeaseStatsRow
|
||||
/// instances. The rows must be accessible in ascending order by subnet id.
|
||||
class LeaseStatsQuery {
|
||||
public:
|
||||
/// @brief Default constructor
|
||||
LeaseStatsQuery() {};
|
||||
|
||||
/// @brief virtual destructor
|
||||
virtual ~LeaseStatsQuery() {};
|
||||
|
||||
/// @brief Executes the query
|
||||
///
|
||||
/// This method should conduct whatever steps are required to
|
||||
/// calculate the lease statistical data by examining the
|
||||
/// lease data and making that results available row by row.
|
||||
virtual void start() {};
|
||||
|
||||
/// @brief Fetches the next row of data
|
||||
///
|
||||
/// @param[out] row Storage into which the row is fetched
|
||||
///
|
||||
/// @return True if a row was fetched, false if there are no
|
||||
/// more rows.
|
||||
virtual bool getNextRow(LeaseStatsRow& row);
|
||||
};
|
||||
|
||||
/// @brief Defines a pointer to an LeaseStatsQuery.
|
||||
typedef boost::shared_ptr<LeaseStatsQuery> LeaseStatsQueryPtr;
|
||||
|
||||
/// @brief Abstract Lease Manager
|
||||
///
|
||||
/// This is an abstract API for lease database backends. It provides unified
|
||||
@@ -397,6 +477,68 @@ public:
|
||||
/// @return Number of leases deleted.
|
||||
virtual uint64_t deleteExpiredReclaimedLeases6(const uint32_t secs) = 0;
|
||||
|
||||
/// @brief Recalculates per-subnet and global stats for IPv4 leases
|
||||
///
|
||||
/// This method recalculates the following statistics:
|
||||
/// per-subnet:
|
||||
/// - assigned-addresses
|
||||
/// - declined-addresses
|
||||
/// - declined-reclaimed-addresses (reset to zero)
|
||||
/// global:
|
||||
/// - declined-addresses
|
||||
/// - declined-reclaimed-addresses (reset to zero)
|
||||
///
|
||||
/// It invokes the virtual method, startLeaseStatsQuery4(), which
|
||||
/// returns an instance of an LeaseStatsQuery. The query
|
||||
/// query contains a "result set" where each row is an LeaseStatRow
|
||||
/// that contains a subnet id, a lease type (currently always TYPE_NA),
|
||||
/// a lease state, and the number of leases of that type, in that state
|
||||
/// and is ordered by subnet id. The method iterates over the
|
||||
/// result set rows, setting the appropriate statistic per subnet and
|
||||
/// adding to the approporate global statistic.
|
||||
void recountLeaseStats4();
|
||||
|
||||
/// @brief Virtual method which creates and runs the IPv4 lease stats query
|
||||
///
|
||||
/// LeaseMgr derivations implement this method such that it creates and
|
||||
/// returns an instance of an LeaseStatsQuery whose result set has been
|
||||
/// populated with upto date IPv4 lease statistical data. Each row of the
|
||||
/// result set is an LeaseStatRow which ordered ascending by subnet ID.
|
||||
///
|
||||
/// @return A populated LeaseStatsQuery
|
||||
virtual LeaseStatsQueryPtr startLeaseStatsQuery4();
|
||||
|
||||
/// @brief Recalculates per-subnet and global stats for IPv6 leases
|
||||
///
|
||||
/// This method recalculates the following statistics:
|
||||
/// per-subnet:
|
||||
/// - assigned-addresses
|
||||
/// - declined-addresses
|
||||
/// - declined-reclaimed-addresses (reset to zero)
|
||||
/// - assigned-pds
|
||||
/// global:
|
||||
/// - declined-addresses
|
||||
/// - declined-reclaimed-addresses (reset to zero)
|
||||
///
|
||||
/// It invokes the virtual method, startLeaseStatsQuery6(), which
|
||||
/// returns an instance of an LeaseStatsQuery. The query contains
|
||||
/// a "result set" where each row is an LeaseStatRow that contains
|
||||
/// a subnet id, a lease type, a lease state, and the number of leases
|
||||
/// of that type, in that state and is ordered by subnet id. The method
|
||||
/// iterates over the result set rows, setting the appropriate statistic
|
||||
/// per subnet and adding to the approporate global statistic.
|
||||
void recountLeaseStats6();
|
||||
|
||||
/// @brief Virtual method which creates and runs the IPv6 lease stats query
|
||||
///
|
||||
/// LeaseMgr derivations implement this method such that it creates and
|
||||
/// returns an instance of an LeaseStatsQuery whose result set has been
|
||||
/// populated with upto date IPv6 lease statistical data. Each row of the
|
||||
/// result set is an LeaseStatRow which ordered ascending by subnet ID.
|
||||
///
|
||||
/// @return A populated LeaseStatsQuery
|
||||
virtual LeaseStatsQueryPtr startLeaseStatsQuery6();
|
||||
|
||||
/// @brief Return backend type
|
||||
///
|
||||
/// Returns the type of the backend (e.g. "mysql", "memfile" etc.)
|
||||
|
@@ -101,6 +101,11 @@ LeaseMgrFactory::destroy() {
|
||||
getLeaseMgrPtr().reset();
|
||||
}
|
||||
|
||||
bool
|
||||
LeaseMgrFactory::haveInstance() {
|
||||
return (getLeaseMgrPtr().get());
|
||||
}
|
||||
|
||||
LeaseMgr&
|
||||
LeaseMgrFactory::instance() {
|
||||
LeaseMgr* lmptr = getLeaseMgrPtr().get();
|
||||
|
@@ -85,7 +85,10 @@ public:
|
||||
/// create() to create one before calling this method.
|
||||
static LeaseMgr& instance();
|
||||
|
||||
|
||||
/// @brief Indicates if the lease manager has been instantiated.
|
||||
///
|
||||
/// @return True if the lease manager instance exists, false otherwise.
|
||||
static bool haveInstance();
|
||||
|
||||
private:
|
||||
/// @brief Hold pointer to lease manager
|
||||
|
@@ -256,6 +256,268 @@ LFCSetup::getExitStatus() const {
|
||||
return (process_->getExitStatus(pid_));
|
||||
}
|
||||
|
||||
|
||||
/// @brief Base Memfile derivation of the statistical lease data query
|
||||
///
|
||||
/// This class provides the functionality such as results storage and row
|
||||
/// fetching common to fulfilling the statistical lease data query.
|
||||
///
|
||||
class MemfileLeaseStatsQuery : public LeaseStatsQuery {
|
||||
public:
|
||||
/// @brief Constructor
|
||||
///
|
||||
MemfileLeaseStatsQuery()
|
||||
: rows_(0), next_pos_(rows_.end()) {
|
||||
};
|
||||
|
||||
/// @brief Destructor
|
||||
virtual ~MemfileLeaseStatsQuery() {};
|
||||
|
||||
/// @brief Fetches the next row in the result set
|
||||
///
|
||||
/// Once the internal result set has been populated by invoking the
|
||||
/// the start() method, this method is used to iterate over the
|
||||
/// result set rows. Once the last row has been fetched, subsequent
|
||||
/// calls will return false.
|
||||
/// @param row Storage for the fetched row
|
||||
///
|
||||
/// @return True if the fetch succeeded, false if there are no more
|
||||
/// rows to fetch.
|
||||
virtual bool getNextRow(LeaseStatsRow& row) {
|
||||
if (next_pos_ == rows_.end()) {
|
||||
return (false);
|
||||
}
|
||||
|
||||
row = *next_pos_;
|
||||
++next_pos_;
|
||||
return (true);
|
||||
}
|
||||
|
||||
/// @brief Returns the number of rows in the result set
|
||||
int getRowCount() const {
|
||||
return (rows_.size());
|
||||
}
|
||||
|
||||
protected:
|
||||
/// @brief A vector containing the "result set"
|
||||
std::vector<LeaseStatsRow> rows_;
|
||||
|
||||
/// @brief An iterator for accessing the next row within the result set
|
||||
std::vector<LeaseStatsRow>::iterator next_pos_;
|
||||
};
|
||||
|
||||
/// @brief Memfile derivation of the IPv4 statistical lease data query
|
||||
///
|
||||
/// This class is used to recalculate IPv4 lease statistics for Memfile
|
||||
/// lease storage. It does so by iterating over the given storage,
|
||||
/// accumulating counts of leases in each of the monitored lease states
|
||||
/// for each subnet and storing these counts in an internal collection.
|
||||
/// The populated result set will contain one entry per monitored state
|
||||
/// per subnet.
|
||||
///
|
||||
class MemfileLeaseStatsQuery4 : public MemfileLeaseStatsQuery {
|
||||
public:
|
||||
/// @brief Constructor
|
||||
///
|
||||
/// @param storage4 A pointer to the v4 lease storage to be counted
|
||||
MemfileLeaseStatsQuery4(Lease4Storage& storage4)
|
||||
: MemfileLeaseStatsQuery(), storage4_(storage4) {
|
||||
};
|
||||
|
||||
/// @brief Destructor
|
||||
virtual ~MemfileLeaseStatsQuery4() {};
|
||||
|
||||
/// @brief Creates the IPv4 lease statistical data result set
|
||||
///
|
||||
/// The result set is populated by iterating over the IPv4 leases in
|
||||
/// storage, in ascending order by address, accumulating the lease state
|
||||
/// counts per subnet. Note that walking the leases by address should
|
||||
/// inherently group them by subnet, and while this does not gaurantee
|
||||
/// ascending order of subnet id, it should be sufficient to accumulate
|
||||
/// state counts per subnet. This avoids introducing an additional
|
||||
/// subnet_id index.
|
||||
/// At the completion of all entries for a given subnet, the counts are
|
||||
/// used to create LeaseStatsRow instances which are appended to an
|
||||
/// internal vector. The process results in a vector containing one entry
|
||||
/// per state per subnet.
|
||||
///
|
||||
/// Currently the states counted are:
|
||||
///
|
||||
/// - Lease::STATE_DEFAULT (i.e. assigned)
|
||||
/// - Lease::STATE_DECLINED
|
||||
void start() {
|
||||
const Lease4StorageAddressIndex& idx
|
||||
= storage4_.get<AddressIndexTag>();
|
||||
|
||||
// Iterate over the leases in order by subnet, accumulating per
|
||||
// subnet counts for each state of interest. As we finish each
|
||||
// subnet, add the appropriate rows to our result set.
|
||||
SubnetID cur_id = 0;
|
||||
int64_t assigned = 0;
|
||||
int64_t declined = 0;
|
||||
for(Lease4StorageAddressIndex::const_iterator lease = idx.begin();
|
||||
lease != idx.end(); ++lease) {
|
||||
// If we've hit the next subnet, add rows for the current subnet
|
||||
// and wipe the accumulators
|
||||
if ((*lease)->subnet_id_ != cur_id) {
|
||||
if (cur_id > 0) {
|
||||
rows_.push_back(LeaseStatsRow(cur_id, Lease::STATE_DEFAULT,
|
||||
assigned));
|
||||
assigned = 0;
|
||||
rows_.push_back(LeaseStatsRow(cur_id, Lease::STATE_DECLINED,
|
||||
declined));
|
||||
declined = 0;
|
||||
}
|
||||
|
||||
// Update current subnet id
|
||||
cur_id = (*lease)->subnet_id_;
|
||||
}
|
||||
|
||||
// Bump the appropriate accumulator
|
||||
if ((*lease)->state_ == Lease::STATE_DEFAULT) {
|
||||
++assigned;
|
||||
} else if ((*lease)->state_ == Lease::STATE_DECLINED) {
|
||||
++declined;
|
||||
}
|
||||
}
|
||||
|
||||
// Make the rows for last subnet, unless there were no rows
|
||||
if (idx.begin() != idx.end()) {
|
||||
rows_.push_back(LeaseStatsRow(cur_id, Lease::STATE_DEFAULT,
|
||||
assigned));
|
||||
rows_.push_back(LeaseStatsRow(cur_id, Lease::STATE_DECLINED,
|
||||
declined));
|
||||
}
|
||||
|
||||
// Set the next row position to the beginning of the rows.
|
||||
next_pos_ = rows_.begin();
|
||||
}
|
||||
|
||||
private:
|
||||
/// @brief The Memfile storage containing the IPv4 leases to analyze
|
||||
Lease4Storage& storage4_;
|
||||
};
|
||||
|
||||
|
||||
/// @brief Memfile derivation of the IPv6 statistical lease data query
|
||||
///
|
||||
/// This class is used to recalculate IPv6 lease statistics for Memfile
|
||||
/// lease storage. It does so by iterating over the given storage,
|
||||
/// accumulating counts of leases in each of the monitored lease states
|
||||
/// for each subnet and storing these counts in an internal collection.
|
||||
/// The populated result set will contain one entry per monitored state
|
||||
/// per subnet.
|
||||
///
|
||||
class MemfileLeaseStatsQuery6 : public MemfileLeaseStatsQuery {
|
||||
public:
|
||||
/// @brief Constructor
|
||||
///
|
||||
/// @param storage6 A pointer to the v6 lease storage to be counted
|
||||
MemfileLeaseStatsQuery6(Lease6Storage& storage6)
|
||||
: MemfileLeaseStatsQuery(), storage6_(storage6) {
|
||||
};
|
||||
|
||||
/// @brief Destructor
|
||||
virtual ~MemfileLeaseStatsQuery6() {};
|
||||
|
||||
/// @brief Creates the IPv6 lease statistical data result set
|
||||
///
|
||||
/// The result set is populated by iterating over the IPv6 leases in
|
||||
/// storage, in ascending order by address, accumulating the lease state
|
||||
/// counts per subnet. Note that walking the leases by address should
|
||||
/// inherently group them by subnet, and while this does not gaurantee
|
||||
/// ascending order of subnet id, it should be sufficient to accumulate
|
||||
/// state counts per subnet. This avoids introducing an additional
|
||||
/// subnet_id index.
|
||||
/// At the completion of all entries for a given subnet, the counts
|
||||
/// are used to create LeaseStatsRow instances which are appended to an
|
||||
/// internal vector. The process results in a vector containing one entry
|
||||
/// per state per lease type per subnet.
|
||||
///
|
||||
/// Currently the states counted are:
|
||||
///
|
||||
/// - Lease::STATE_DEFAULT (i.e. assigned)
|
||||
/// - Lease::STATE_DECLINED
|
||||
virtual void start() {
|
||||
// Get the subnet_id index
|
||||
const Lease6StorageAddressIndex& idx
|
||||
= storage6_.get<AddressIndexTag>();
|
||||
|
||||
// Iterate over the leases in order by subnet, accumulating per
|
||||
// subnet counts for each state of interest. As we finish each
|
||||
// subnet, add the appropriate rows to our result set.
|
||||
SubnetID cur_id = 0;
|
||||
int64_t assigned = 0;
|
||||
int64_t declined = 0;
|
||||
int64_t assigned_pds = 0;
|
||||
|
||||
for(Lease6StorageAddressIndex::const_iterator lease = idx.begin();
|
||||
lease != idx.end(); ++lease) {
|
||||
|
||||
// If we've hit the next subnet, add rows for the current subnet
|
||||
// and wipe the accumulators
|
||||
if ((*lease)->subnet_id_ != cur_id) {
|
||||
if (cur_id > 0) {
|
||||
rows_.push_back(LeaseStatsRow(cur_id, Lease::TYPE_NA,
|
||||
Lease::STATE_DEFAULT,
|
||||
assigned));
|
||||
assigned = 0;
|
||||
rows_.push_back(LeaseStatsRow(cur_id, Lease::TYPE_NA,
|
||||
Lease::STATE_DECLINED,
|
||||
declined));
|
||||
declined = 0;
|
||||
rows_.push_back(LeaseStatsRow(cur_id, Lease::TYPE_PD,
|
||||
Lease::STATE_DEFAULT,
|
||||
assigned_pds));
|
||||
assigned_pds = 0;
|
||||
}
|
||||
|
||||
// Update current subnet id
|
||||
cur_id = (*lease)->subnet_id_;
|
||||
}
|
||||
|
||||
// Bump the appropriate accumulator
|
||||
if ((*lease)->state_ == Lease::STATE_DEFAULT) {
|
||||
switch((*lease)->type_) {
|
||||
case Lease::TYPE_NA:
|
||||
++assigned;
|
||||
break;
|
||||
case Lease::TYPE_PD:
|
||||
++assigned_pds;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if ((*lease)->state_ == Lease::STATE_DECLINED) {
|
||||
// In theory only NAs can be declined
|
||||
if (((*lease)->type_) == Lease::TYPE_NA) {
|
||||
++declined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make the rows for last subnet, unless there were no rows
|
||||
if (idx.begin() != idx.end()) {
|
||||
rows_.push_back(LeaseStatsRow(cur_id, Lease::TYPE_NA,
|
||||
Lease::STATE_DEFAULT,
|
||||
assigned));
|
||||
rows_.push_back(LeaseStatsRow(cur_id, Lease::TYPE_NA,
|
||||
Lease::STATE_DECLINED,
|
||||
declined));
|
||||
rows_.push_back(LeaseStatsRow(cur_id, Lease::TYPE_PD,
|
||||
Lease::STATE_DEFAULT,
|
||||
assigned_pds));
|
||||
}
|
||||
|
||||
// Set the next row position to the beginning of the rows.
|
||||
next_pos_ = rows_.begin();
|
||||
}
|
||||
|
||||
private:
|
||||
/// @brief The Memfile storage containing the IPv6 leases to analyze
|
||||
Lease6Storage& storage6_;
|
||||
};
|
||||
|
||||
// Explicit definition of class static constants. Values are given in the
|
||||
// declaration so they're not needed here.
|
||||
const int Memfile_LeaseMgr::MAJOR_VERSION;
|
||||
@@ -299,6 +561,7 @@ Memfile_LeaseMgr::Memfile_LeaseMgr(const DatabaseConnection::ParameterMap& param
|
||||
}
|
||||
lfcSetup(conversion_needed);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Memfile_LeaseMgr::~Memfile_LeaseMgr() {
|
||||
@@ -1048,5 +1311,19 @@ void Memfile_LeaseMgr::lfcExecute(boost::shared_ptr<LeaseFileType>& lease_file)
|
||||
}
|
||||
}
|
||||
|
||||
LeaseStatsQueryPtr
|
||||
Memfile_LeaseMgr::startLeaseStatsQuery4() {
|
||||
LeaseStatsQueryPtr query(new MemfileLeaseStatsQuery4(storage4_));
|
||||
query->start();
|
||||
return(query);
|
||||
}
|
||||
|
||||
LeaseStatsQueryPtr
|
||||
Memfile_LeaseMgr::startLeaseStatsQuery6() {
|
||||
LeaseStatsQueryPtr query(new MemfileLeaseStatsQuery6(storage6_));
|
||||
query->start();
|
||||
return(query);
|
||||
}
|
||||
|
||||
} // end of namespace isc::dhcp
|
||||
} // end of namespace isc
|
||||
|
@@ -92,6 +92,7 @@ public:
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
/// @brief Specifies universe (V4, V6)
|
||||
///
|
||||
/// This enumeration is used by various functions in Memfile %Lease Manager,
|
||||
@@ -594,6 +595,23 @@ public:
|
||||
int getLFCExitStatus() const;
|
||||
//@}
|
||||
|
||||
/// @brief Creates and runs the IPv4 lease stats query
|
||||
///
|
||||
/// It creates an instance of a MemfileLeaseStatsQuery4 and then
|
||||
/// invokes its start method in which the query constructs its
|
||||
/// statistical data result set. The query object is then returned.
|
||||
///
|
||||
/// @return The populated query as a pointer to an LeaseStatsQuery
|
||||
virtual LeaseStatsQueryPtr startLeaseStatsQuery4();
|
||||
|
||||
/// @brief Creates and runs the IPv6 lease stats query
|
||||
///
|
||||
/// It creates an instance of a MemfileLeaseStatsQuery6 and then
|
||||
/// invokes its start method in which the query constructs its
|
||||
/// statistical data result set. The query object is then returned.
|
||||
///
|
||||
/// @return The populated query as a pointer to an LeaseStatsQuery.
|
||||
virtual LeaseStatsQueryPtr startLeaseStatsQuery6();
|
||||
|
||||
/// @name Protected methods used for %Lease File Cleanup.
|
||||
/// The following methods are protected so as they can be accessed and
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
|
||||
// Copyright (C) 2015-2016 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
|
||||
|
@@ -71,6 +71,7 @@ using namespace std;
|
||||
/// lease object.
|
||||
|
||||
namespace {
|
||||
|
||||
/// @brief Maximum length of the hostname stored in DNS.
|
||||
///
|
||||
/// This length is restricted by the length of the domain-name carried
|
||||
@@ -206,7 +207,14 @@ tagged_statements = { {
|
||||
"prefix_len = ?, fqdn_fwd = ?, fqdn_rev = ?, "
|
||||
"hostname = ?, hwaddr = ?, hwtype = ?, hwaddr_source = ?, "
|
||||
"state = ? "
|
||||
"WHERE address = ?"}
|
||||
"WHERE address = ?"},
|
||||
{MySqlLeaseMgr::RECOUNT_LEASE4_STATS,
|
||||
"SELECT subnet_id, state, count(state) as state_count "
|
||||
" FROM lease4 GROUP BY subnet_id, state ORDER BY subnet_id"},
|
||||
{MySqlLeaseMgr::RECOUNT_LEASE6_STATS,
|
||||
"SELECT subnet_id, lease_type, state, count(state) as state_count"
|
||||
" FROM lease6 GROUP BY subnet_id, lease_type, state "
|
||||
" ORDER BY subnet_id" }
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1215,8 +1223,145 @@ private:
|
||||
uint32_t state_; ///< Lease state.
|
||||
};
|
||||
|
||||
/// @brief MySql derivation of the statistical lease data query
|
||||
///
|
||||
/// This class is used to recalculate lease statistics for MySQL
|
||||
/// lease storage. It does so by executing a query which returns a result
|
||||
/// containining contain one row per monitored state per lease type per
|
||||
/// subnet, ordered by subnet id in ascending order.
|
||||
///
|
||||
class MySqlLeaseStatsQuery : public LeaseStatsQuery {
|
||||
public:
|
||||
/// @brief Constructor
|
||||
///
|
||||
/// @param conn A open connection to the database housing the lease data
|
||||
/// @brief statement_index Index of the query's prepared statement
|
||||
/// @brief fetch_type Indicates if query supplies lease type
|
||||
MySqlLeaseStatsQuery(MySqlConnection& conn, const size_t statement_index,
|
||||
const bool fetch_type)
|
||||
: conn_(conn), statement_index_(statement_index), statement_(NULL),
|
||||
fetch_type_(fetch_type),
|
||||
// Set the number of columns in the bind array based on fetch_type
|
||||
// This is the number of columns expected in the result set
|
||||
bind_(fetch_type_ ? 4 : 3) {
|
||||
if (statement_index_ >= MySqlLeaseMgr::NUM_STATEMENTS) {
|
||||
isc_throw(BadValue, "MySqlLeaseStatsQuery"
|
||||
" - invalid statement index" << statement_index_);
|
||||
}
|
||||
|
||||
statement_ = conn.statements_[statement_index_];
|
||||
}
|
||||
|
||||
/// @brief Destructor
|
||||
virtual ~MySqlLeaseStatsQuery() {
|
||||
(void) mysql_stmt_free_result(statement_);
|
||||
}
|
||||
|
||||
/// @brief Creates the IPv4 lease statistical data result set
|
||||
///
|
||||
/// The result set is populated by executing a SQL query against the
|
||||
/// lease(4/6) table which sums the leases per lease state per lease
|
||||
/// type (v6 only) per subnet id. This method binds the statement to
|
||||
/// the output bind array and then executes the statement, and fetches
|
||||
/// entire result set.
|
||||
void start() {
|
||||
int col = 0;
|
||||
// subnet_id: unsigned int
|
||||
bind_[col].buffer_type = MYSQL_TYPE_LONG;
|
||||
bind_[col].buffer = reinterpret_cast<char*>(&subnet_id_);
|
||||
bind_[col].is_unsigned = MLM_TRUE;
|
||||
++col;
|
||||
|
||||
// Fetch the lease type if we were told to do so.
|
||||
if (fetch_type_) {
|
||||
// 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;
|
||||
++col;
|
||||
} else {
|
||||
fetch_type_ = Lease::TYPE_NA;
|
||||
}
|
||||
|
||||
// state: uint32_t
|
||||
bind_[col].buffer_type = MYSQL_TYPE_LONG;
|
||||
bind_[col].buffer = reinterpret_cast<char*>(&lease_state_);
|
||||
bind_[col].is_unsigned = MLM_TRUE;
|
||||
++col;
|
||||
|
||||
// state_count_: uint32_t
|
||||
bind_[col].buffer_type = MYSQL_TYPE_LONG;
|
||||
bind_[col].buffer = reinterpret_cast<char*>(&state_count_);
|
||||
bind_[col].is_unsigned = MLM_TRUE;
|
||||
|
||||
// Set up the MYSQL_BIND array for the data being returned
|
||||
// and bind it to the statement.
|
||||
int status = mysql_stmt_bind_result(statement_, &bind_[0]);
|
||||
conn_.checkError(status, statement_index_, "outbound binding failed");
|
||||
|
||||
// Execute the statement
|
||||
status = mysql_stmt_execute(statement_);
|
||||
conn_.checkError(status, statement_index_, "unable to execute");
|
||||
|
||||
// Ensure that all the lease information is retrieved in one go to avoid
|
||||
// overhead of going back and forth between client and server.
|
||||
status = mysql_stmt_store_result(statement_);
|
||||
conn_.checkError(status, statement_index_, "results storage failed");
|
||||
}
|
||||
|
||||
|
||||
/// @brief Fetches the next row in the result set
|
||||
///
|
||||
/// Once the internal result set has been populated by invoking the
|
||||
/// the start() method, this method is used to iterate over the
|
||||
/// result set rows. Once the last row has been fetched, subsequent
|
||||
/// calls will return false.
|
||||
///
|
||||
/// @param row Storage for the fetched row
|
||||
///
|
||||
/// @return True if the fetch succeeded, false if there are no more
|
||||
/// rows to fetch.
|
||||
bool getNextRow(LeaseStatsRow& row) {
|
||||
bool have_row = false;
|
||||
int status = mysql_stmt_fetch(statement_);
|
||||
if (status == MLM_MYSQL_FETCH_SUCCESS) {
|
||||
row.subnet_id_ = static_cast<SubnetID>(subnet_id_);
|
||||
row.lease_type_ = static_cast<Lease::Type>(lease_type_);
|
||||
row.lease_state_ = lease_state_;
|
||||
row.state_count_ = state_count_;
|
||||
have_row = true;
|
||||
} else if (status != MYSQL_NO_DATA) {
|
||||
conn_.checkError(status, statement_index_, "getNextRow failed");
|
||||
}
|
||||
|
||||
return (have_row);
|
||||
}
|
||||
|
||||
private:
|
||||
/// @brief Database connection to use to execute the query
|
||||
MySqlConnection& conn_;
|
||||
|
||||
/// @brief Index of the query's prepared statement
|
||||
size_t statement_index_;
|
||||
|
||||
/// @brief The query's prepared statement
|
||||
MYSQL_STMT *statement_;
|
||||
|
||||
/// @brief Indicates if query supplies lease type
|
||||
bool fetch_type_;
|
||||
|
||||
/// @brief Bind array used to store the query result set;
|
||||
std::vector<MYSQL_BIND> bind_;
|
||||
|
||||
/// @brief Receives subnet ID when fetching a row
|
||||
uint32_t subnet_id_;
|
||||
/// @brief Receives the lease type when fetching a row
|
||||
uint32_t lease_type_;
|
||||
/// @brief Receives the lease state when fetching a row
|
||||
uint32_t lease_state_;
|
||||
/// @brief Receives the state count when fetching a row
|
||||
uint32_t state_count_;
|
||||
};
|
||||
|
||||
// MySqlLeaseMgr Constructor and Destructor
|
||||
|
||||
@@ -2026,6 +2171,23 @@ MySqlLeaseMgr::getVersion() const {
|
||||
return (std::make_pair(major, minor));
|
||||
}
|
||||
|
||||
LeaseStatsQueryPtr
|
||||
MySqlLeaseMgr::startLeaseStatsQuery4() {
|
||||
LeaseStatsQueryPtr query(new MySqlLeaseStatsQuery(conn_,
|
||||
RECOUNT_LEASE4_STATS,
|
||||
false));
|
||||
query->start();
|
||||
return(query);
|
||||
}
|
||||
|
||||
LeaseStatsQueryPtr
|
||||
MySqlLeaseMgr::startLeaseStatsQuery6() {
|
||||
LeaseStatsQueryPtr query(new MySqlLeaseStatsQuery(conn_,
|
||||
RECOUNT_LEASE6_STATS,
|
||||
true));
|
||||
query->start();
|
||||
return(query);
|
||||
}
|
||||
|
||||
void
|
||||
MySqlLeaseMgr::commit() {
|
||||
|
@@ -25,7 +25,6 @@ namespace dhcp {
|
||||
class MySqlLease4Exchange;
|
||||
class MySqlLease6Exchange;
|
||||
|
||||
|
||||
/// @brief MySQL Lease Manager
|
||||
///
|
||||
/// This class provides the \ref isc::dhcp::LeaseMgr interface to the MySQL
|
||||
@@ -410,6 +409,8 @@ public:
|
||||
INSERT_LEASE6, // Add entry to lease6 table
|
||||
UPDATE_LEASE4, // Update a Lease4 entry
|
||||
UPDATE_LEASE6, // Update a Lease6 entry
|
||||
RECOUNT_LEASE4_STATS, // Fetches IPv4 address statisics
|
||||
RECOUNT_LEASE6_STATS, // Fetches IPv6 address statisics
|
||||
NUM_STATEMENTS // Number of statements
|
||||
};
|
||||
|
||||
@@ -590,6 +591,25 @@ private:
|
||||
uint64_t deleteExpiredReclaimedLeasesCommon(const uint32_t secs,
|
||||
StatementIndex statement_index);
|
||||
|
||||
/// @brief Creates and runs the IPv4 lease stats query
|
||||
///
|
||||
/// It creates an instance of a MySqlLeaseStatsQuery4 and then
|
||||
/// invokes its start method, which fetches its statistical data
|
||||
/// result set by executing the RECOUNT_LEASE_STATS4 query.
|
||||
/// The query object is then returned.
|
||||
///
|
||||
/// @return The populated query as a pointer to an LeaseStatsQuery
|
||||
virtual LeaseStatsQueryPtr startLeaseStatsQuery4();
|
||||
|
||||
/// @brief Creates and runs the IPv6 lease stats query
|
||||
///
|
||||
/// It creates an instance of a MySqlLeaseStatsQuery6 and then
|
||||
/// invokes its start method, which fetches its statistical data
|
||||
/// result set by executing the RECOUNT_LEASE_STATS6 query.
|
||||
/// The query object is then returned.
|
||||
///
|
||||
/// @return The populated query as a pointer to an LeaseStatsQuery
|
||||
virtual LeaseStatsQueryPtr startLeaseStatsQuery6();
|
||||
|
||||
/// @brief Check Error and Throw Exception
|
||||
///
|
||||
|
@@ -201,6 +201,19 @@ PgSqlTaggedStatement tagged_statements[] = {
|
||||
"state = $13 "
|
||||
"WHERE address = $14"},
|
||||
|
||||
// RECOUNT_LEASE4_STATS,
|
||||
{ 0, { OID_NONE },
|
||||
"recount_lease4_stats",
|
||||
"SELECT subnet_id, state, count(state) as state_count "
|
||||
"FROM lease4 GROUP BY subnet_id, state ORDER BY subnet_id"},
|
||||
|
||||
// RECOUNT_LEASE6_STATS,
|
||||
{ 0, { OID_NONE },
|
||||
"recount_lease6_stats",
|
||||
"SELECT subnet_id, lease_type, state, count(state) as state_count "
|
||||
"FROM lease6 GROUP BY subnet_id, lease_type, state "
|
||||
"ORDER BY subnet_id"},
|
||||
|
||||
// End of list sentinel
|
||||
{ 0, { 0 }, NULL, NULL}
|
||||
};
|
||||
@@ -681,6 +694,107 @@ private:
|
||||
//@}
|
||||
};
|
||||
|
||||
/// @brief Base PgSql derivation of the statistical lease data query
|
||||
///
|
||||
/// This class provides the functionality such as results storgae and row
|
||||
/// fetching common to fulfilling the statistical lease data query.
|
||||
///
|
||||
class PgSqlLeaseStatsQuery : public LeaseStatsQuery {
|
||||
public:
|
||||
/// @brief Constructor
|
||||
///
|
||||
/// @param conn A open connection to the database housing the lease data
|
||||
/// @param statement The lease data SQL prepared statement to execute
|
||||
/// @param fetch_statement Indicates whether or not lease_type should be
|
||||
/// fetched from the result set
|
||||
PgSqlLeaseStatsQuery(PgSqlConnection& conn, PgSqlTaggedStatement& statement,
|
||||
const bool fetch_type)
|
||||
: conn_(conn), statement_(statement), result_set_(), next_row_(0),
|
||||
fetch_type_(fetch_type) {
|
||||
}
|
||||
|
||||
/// @brief Destructor
|
||||
virtual ~PgSqlLeaseStatsQuery() {};
|
||||
|
||||
/// @brief Creates the lease statistical data result set
|
||||
///
|
||||
/// The result set is populated by executing a prepared SQL query
|
||||
/// against the database which sums the leases per lease state per
|
||||
/// subnet id.
|
||||
void start() {
|
||||
// The query has no parameters, so we only need it's name.
|
||||
result_set_.reset(new PgSqlResult(PQexecPrepared(conn_, statement_.name,
|
||||
0, NULL, NULL, NULL, 0)));
|
||||
|
||||
conn_.checkStatementError(*result_set_, statement_);
|
||||
}
|
||||
|
||||
/// @brief Fetches the next row in the result set
|
||||
///
|
||||
/// Once the internal result set has been populated by invoking the
|
||||
/// the start() method, this method is used to iterate over the
|
||||
/// result set rows. Once the last row has been fetched, subsequent
|
||||
/// calls will return false.
|
||||
///
|
||||
/// @param row Storage for the fetched row
|
||||
///
|
||||
/// @return True if the fetch succeeded, false if there are no more
|
||||
/// rows to fetch.
|
||||
bool getNextRow(LeaseStatsRow& row) {
|
||||
// If we're past the end, punt.
|
||||
if (next_row_ >= result_set_->getRows()) {
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Fetch the subnet id.
|
||||
uint32_t col = 0;
|
||||
uint32_t subnet_id;
|
||||
PgSqlExchange::getColumnValue(*result_set_, next_row_, col, subnet_id);
|
||||
row.subnet_id_ = static_cast<SubnetID>(subnet_id);
|
||||
++col;
|
||||
|
||||
// Fetch the lease type if we were told to do so.
|
||||
if (fetch_type_) {
|
||||
uint32_t lease_type;
|
||||
PgSqlExchange::getColumnValue(*result_set_, next_row_ , col,
|
||||
lease_type);
|
||||
row.lease_type_ = static_cast<Lease::Type>(lease_type);
|
||||
++col;
|
||||
} else {
|
||||
row.lease_type_ = Lease::TYPE_NA;
|
||||
}
|
||||
|
||||
// Fetch the lease state.
|
||||
PgSqlExchange::getColumnValue(*result_set_, next_row_ , col,
|
||||
row.lease_state_);
|
||||
++col;
|
||||
|
||||
// Fetch the state count.
|
||||
PgSqlExchange::getColumnValue(*result_set_, next_row_, col,
|
||||
row.state_count_);
|
||||
|
||||
// Point to the next row.
|
||||
++next_row_;
|
||||
return (true);
|
||||
}
|
||||
|
||||
protected:
|
||||
/// @brief Database connection to use to execute the query
|
||||
PgSqlConnection& conn_;
|
||||
|
||||
/// @brief The query's prepared statement
|
||||
PgSqlTaggedStatement& statement_;
|
||||
|
||||
/// @brief The result set returned by Postgres.
|
||||
boost::shared_ptr<PgSqlResult> result_set_;
|
||||
|
||||
/// @brief Index of the next row to fetch
|
||||
uint32_t next_row_;
|
||||
|
||||
/// @brief Indicates if query supplies lease type
|
||||
bool fetch_type_;
|
||||
};
|
||||
|
||||
PgSqlLeaseMgr::PgSqlLeaseMgr(const DatabaseConnection::ParameterMap& parameters)
|
||||
: LeaseMgr(), exchange4_(new PgSqlLease4Exchange()),
|
||||
exchange6_(new PgSqlLease6Exchange()), conn_(parameters) {
|
||||
@@ -1222,6 +1336,26 @@ PgSqlLeaseMgr::deleteExpiredReclaimedLeasesCommon(const uint32_t secs,
|
||||
return (deleteLeaseCommon(statement_index, bind_array));
|
||||
}
|
||||
|
||||
LeaseStatsQueryPtr
|
||||
PgSqlLeaseMgr::startLeaseStatsQuery4() {
|
||||
LeaseStatsQueryPtr query(
|
||||
new PgSqlLeaseStatsQuery(conn_,
|
||||
tagged_statements[RECOUNT_LEASE4_STATS],
|
||||
false));
|
||||
query->start();
|
||||
return(query);
|
||||
}
|
||||
|
||||
LeaseStatsQueryPtr
|
||||
PgSqlLeaseMgr::startLeaseStatsQuery6() {
|
||||
LeaseStatsQueryPtr query(
|
||||
new PgSqlLeaseStatsQuery(conn_,
|
||||
tagged_statements[RECOUNT_LEASE6_STATS],
|
||||
true));
|
||||
query->start();
|
||||
return(query);
|
||||
}
|
||||
|
||||
string
|
||||
PgSqlLeaseMgr::getName() const {
|
||||
string name = "";
|
||||
|
@@ -317,6 +317,26 @@ public:
|
||||
/// @return Number of leases deleted.
|
||||
virtual uint64_t deleteExpiredReclaimedLeases6(const uint32_t secs);
|
||||
|
||||
/// @brief Creates and runs the IPv4 lease stats query
|
||||
///
|
||||
/// It creates an instance of a PgSqlLeaseStatsQuery4 and then
|
||||
/// invokes its start method, which fetches its statistical data
|
||||
/// result set by executing the RECOUNT_LEASE_STATS4 query.
|
||||
/// The query object is then returned.
|
||||
///
|
||||
/// @return The populated query as a pointer to an LeaseStatsQuery
|
||||
virtual LeaseStatsQueryPtr startLeaseStatsQuery4();
|
||||
|
||||
/// @brief Creates and runs the IPv6 lease stats query
|
||||
///
|
||||
/// It creates an instance of a PgSqlLeaseStatsQuery and then
|
||||
/// invokes its start method, which fetches its statistical data
|
||||
/// result set by executing the RECOUNT_LEASE_STATS6 query.
|
||||
/// The query object is then returned.
|
||||
///
|
||||
/// @return The populated query as a pointer to an LeaseStatsQuery
|
||||
virtual LeaseStatsQueryPtr startLeaseStatsQuery6();
|
||||
|
||||
/// @brief Return backend type
|
||||
///
|
||||
/// Returns the type of the backend (e.g. "mysql", "memfile" etc.)
|
||||
@@ -385,6 +405,8 @@ public:
|
||||
INSERT_LEASE6, // Add entry to lease6 table
|
||||
UPDATE_LEASE4, // Update a Lease4 entry
|
||||
UPDATE_LEASE6, // Update a Lease6 entry
|
||||
RECOUNT_LEASE4_STATS, // Fetch IPv4 lease statistical data
|
||||
RECOUNT_LEASE6_STATS, // Fetch IPv4 lease statistical data
|
||||
NUM_STATEMENTS // Number of statements
|
||||
};
|
||||
|
||||
|
@@ -7,6 +7,7 @@
|
||||
#include <config.h>
|
||||
#include <dhcpsrv/cfgmgr.h>
|
||||
#include <dhcpsrv/srv_config.h>
|
||||
#include <dhcpsrv/lease_mgr_factory.h>
|
||||
#include <log/logger_manager.h>
|
||||
#include <log/logger_specification.h>
|
||||
#include <dhcp/pkt.h> // Needed for HWADDR_SOURCE_*
|
||||
@@ -164,12 +165,18 @@ SrvConfig::removeStatistics() {
|
||||
|
||||
void
|
||||
SrvConfig::updateStatistics() {
|
||||
|
||||
// Updating subnet statistics involves updating lease statistics, which
|
||||
// is done by the LeaseMgr. Since servers with subnets, must have a
|
||||
// LeaseMgr, we do not bother updating subnet stats for servers without
|
||||
// a lease manager, such as D2. @todo We should probably examine why
|
||||
// "SrvConfig" is being used by D2.
|
||||
if (LeaseMgrFactory::haveInstance()) {
|
||||
// Updates statistics for v4 and v6 subnets
|
||||
getCfgSubnets4()->updateStatistics();
|
||||
|
||||
getCfgSubnets6()->updateStatistics();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -123,6 +123,9 @@ AllocEngine4Test::generateDeclinedLease(const std::string& addr,
|
||||
AllocEngine6Test::AllocEngine6Test() {
|
||||
CfgMgr::instance().clear();
|
||||
|
||||
// This lease mgr needs to exist to before configuration commits.
|
||||
factory_.create("type=memfile universe=6 persist=false");
|
||||
|
||||
duid_ = DuidPtr(new DUID(std::vector<uint8_t>(8, 0x42)));
|
||||
iaid_ = 42;
|
||||
|
||||
@@ -141,7 +144,6 @@ AllocEngine6Test::AllocEngine6Test() {
|
||||
|
||||
initFqdn("", false, false);
|
||||
|
||||
factory_.create("type=memfile universe=6 persist=false");
|
||||
}
|
||||
|
||||
void
|
||||
@@ -525,6 +527,10 @@ AllocEngine4Test::initSubnet(const asiolink::IOAddress& pool_start,
|
||||
}
|
||||
|
||||
AllocEngine4Test::AllocEngine4Test() {
|
||||
|
||||
// This lease mgr needs to exist to before configuration commits.
|
||||
factory_.create("type=memfile universe=4 persist=false");
|
||||
|
||||
// Create fresh instance of the HostMgr, and drop any previous HostMgr state.
|
||||
HostMgr::instance().create();
|
||||
|
||||
@@ -548,7 +554,6 @@ AllocEngine4Test::AllocEngine4Test() {
|
||||
initSubnet(IOAddress("192.0.2.100"), IOAddress("192.0.2.109"));
|
||||
cfg_mgr.commit();
|
||||
|
||||
factory_.create("type=memfile universe=4 persist=false");
|
||||
|
||||
// Create a default context. Note that remaining parameters must be
|
||||
// assigned when needed.
|
||||
|
@@ -89,6 +89,7 @@ public:
|
||||
/// @brief Destructor.
|
||||
virtual ~CfgMySQLDbAccessTest() {
|
||||
destroyMySQLSchema();
|
||||
LeaseMgrFactory::destroy();
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include <dhcp/dhcp6.h>
|
||||
#include <dhcp/tests/iface_mgr_test_config.h>
|
||||
#include <dhcpsrv/cfgmgr.h>
|
||||
#include <dhcpsrv/lease_mgr_factory.h>
|
||||
#include <dhcpsrv/subnet_id.h>
|
||||
#include <dhcpsrv/parsers/dhcp_parsers.h>
|
||||
#include <stats/stats_mgr.h>
|
||||
@@ -280,6 +281,23 @@ public:
|
||||
void clear() {
|
||||
CfgMgr::instance().setVerbose(false);
|
||||
CfgMgr::instance().clear();
|
||||
LeaseMgrFactory::destroy();
|
||||
}
|
||||
|
||||
/// @brief Creates instance of the backend.
|
||||
///
|
||||
/// @param family AF_INET for v4, AF_INET6 for v6
|
||||
void startBackend(int family = AF_INET) {
|
||||
try {
|
||||
std::ostringstream s;
|
||||
s << "type=memfile persist=false " << (family == AF_INET6 ?
|
||||
"universe=6" : "universe=4");
|
||||
LeaseMgrFactory::create(s.str());
|
||||
} catch (const std::exception& ex) {
|
||||
std::cerr << "*** ERROR: unable to create instance of the Memfile\n"
|
||||
" lease database backend: " << ex.what() << std::endl;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// used in client classification (or just empty container for other tests)
|
||||
@@ -575,6 +593,7 @@ TEST_F(CfgMgrTest, verbosity) {
|
||||
TEST_F(CfgMgrTest, commitStats4) {
|
||||
CfgMgr& cfg_mgr = CfgMgr::instance();
|
||||
StatsMgr& stats_mgr = StatsMgr::instance();
|
||||
startBackend(AF_INET);
|
||||
|
||||
// Let's prepare the "old" configuration: a subnet with id 123
|
||||
// and pretend there were addresses assigned, so statistics are non-zero.
|
||||
@@ -641,6 +660,7 @@ TEST_F(CfgMgrTest, clearStats4) {
|
||||
TEST_F(CfgMgrTest, commitStats6) {
|
||||
CfgMgr& cfg_mgr = CfgMgr::instance();
|
||||
StatsMgr& stats_mgr = StatsMgr::instance();
|
||||
startBackend(AF_INET6);
|
||||
|
||||
// Let's prepare the "old" configuration: a subnet with id 123
|
||||
// and pretend there were addresses assigned, so statistics are non-zero.
|
||||
|
@@ -5,11 +5,18 @@
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <asiolink/io_address.h>
|
||||
#include <dhcpsrv/cfgmgr.h>
|
||||
#include <dhcpsrv/database_connection.h>
|
||||
#include <dhcpsrv/tests/generic_lease_mgr_unittest.h>
|
||||
#include <dhcpsrv/tests/test_utils.h>
|
||||
#include <dhcpsrv/database_connection.h>
|
||||
#include <asiolink/io_address.h>
|
||||
#include <stats/stats_mgr.h>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
using namespace std;
|
||||
@@ -57,6 +64,7 @@ GenericLeaseMgrTest::GenericLeaseMgrTest()
|
||||
/// a template
|
||||
leasetype6_.push_back(LEASETYPE6[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
GenericLeaseMgrTest::~GenericLeaseMgrTest() {
|
||||
@@ -2381,6 +2389,300 @@ GenericLeaseMgrTest::testGetDeclinedLeases6() {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GenericLeaseMgrTest::checkStat(const std::string& name,
|
||||
const int64_t expected_value) {
|
||||
stats::ObservationPtr obs =
|
||||
stats::StatsMgr::instance().getObservation(name);
|
||||
|
||||
ASSERT_TRUE(obs) << " stat: " << name << " not found ";
|
||||
ASSERT_EQ(expected_value, obs->getInteger().first)
|
||||
<< " stat: " << name << " value wrong";
|
||||
}
|
||||
|
||||
void
|
||||
GenericLeaseMgrTest::checkLeaseStats(const StatValMapList& expectedStats) {
|
||||
// Global accumulators
|
||||
int64_t declined_addresses = 0;
|
||||
int64_t declined_reclaimed_addresses = 0;
|
||||
|
||||
// Iterate over all stats for each subnet
|
||||
for (int subnet_idx = 0; subnet_idx < expectedStats.size(); ++subnet_idx) {
|
||||
BOOST_FOREACH(StatValPair expectedStat, expectedStats[subnet_idx]) {
|
||||
// Verify the per subnet value.
|
||||
checkStat(stats::StatsMgr::generateName("subnet", subnet_idx+1,
|
||||
expectedStat.first),
|
||||
expectedStat.second);
|
||||
|
||||
// Add the value to globals as needed.
|
||||
if (expectedStat.first == "declined-addresses") {
|
||||
declined_addresses += expectedStat.second;
|
||||
} else if (expectedStat.first == "declined-reclaimed-addresses") {
|
||||
declined_reclaimed_addresses += expectedStat.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verify the globals.
|
||||
checkStat("declined-addresses", declined_addresses);
|
||||
checkStat("declined-reclaimed-addresses", declined_reclaimed_addresses);
|
||||
}
|
||||
|
||||
void
|
||||
GenericLeaseMgrTest::makeLease4(const std::string& address,
|
||||
const SubnetID& subnet_id,
|
||||
const uint32_t state) {
|
||||
Lease4Ptr lease(new Lease4());
|
||||
|
||||
// set the address
|
||||
lease->addr_ = IOAddress(address);
|
||||
|
||||
// make a MAC from the address
|
||||
std::vector<uint8_t> hwaddr = lease->addr_.toBytes();
|
||||
hwaddr.push_back(0);
|
||||
hwaddr.push_back(0);
|
||||
|
||||
lease->hwaddr_.reset(new HWAddr(hwaddr, HTYPE_ETHER));
|
||||
lease->valid_lft_ = 86400;
|
||||
lease->cltt_ = 168256;
|
||||
lease->subnet_id_ = subnet_id;
|
||||
lease->state_ = state;
|
||||
ASSERT_TRUE(lmptr_->addLease(lease));
|
||||
}
|
||||
|
||||
void
|
||||
GenericLeaseMgrTest::makeLease6(const Lease::Type& type,
|
||||
const std::string& address,
|
||||
uint8_t prefix_len,
|
||||
const SubnetID& subnet_id,
|
||||
const uint32_t state) {
|
||||
IOAddress addr(address);
|
||||
|
||||
// make a DUID from the address
|
||||
std::vector<uint8_t> bytes = addr.toBytes();
|
||||
bytes.push_back(prefix_len);
|
||||
|
||||
Lease6Ptr lease(new Lease6(type, addr, DuidPtr(new DUID(bytes)), 77,
|
||||
16000, 24000, 0, 0, subnet_id, HWAddrPtr(),
|
||||
prefix_len));
|
||||
lease->state_ = state;
|
||||
ASSERT_TRUE(lmptr_->addLease(lease));
|
||||
}
|
||||
|
||||
void
|
||||
GenericLeaseMgrTest::testRecountLeaseStats4() {
|
||||
using namespace stats;
|
||||
|
||||
StatsMgr::instance().removeAll();
|
||||
|
||||
// Create two subnets.
|
||||
int num_subnets = 2;
|
||||
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);
|
||||
|
||||
|
||||
ASSERT_NO_THROW(CfgMgr::instance().commit());
|
||||
|
||||
// Create the expected stats list. At this point, the only stat
|
||||
// that should be non-zero is total-addresses.
|
||||
StatValMapList expectedStats(num_subnets);
|
||||
for (int i = 0; i < num_subnets; ++i) {
|
||||
expectedStats[i]["total-addresses"] = 256;
|
||||
expectedStats[i]["assigned-addresses"] = 0;
|
||||
expectedStats[i]["declined-addresses"] = 0;
|
||||
expectedStats[i]["declined-reclaimed-addresses"] = 0;
|
||||
}
|
||||
|
||||
// Make sure stats are as expected.
|
||||
ASSERT_NO_FATAL_FAILURE(checkLeaseStats(expectedStats));
|
||||
|
||||
// Recount stats. We should have the same results.
|
||||
ASSERT_NO_THROW(lmptr_->recountLeaseStats4());
|
||||
|
||||
// Make sure stats are as expected.
|
||||
ASSERT_NO_FATAL_FAILURE(checkLeaseStats(expectedStats));
|
||||
|
||||
// Now let's insert some leases into subnet 1.
|
||||
int subnet_id = 1;
|
||||
|
||||
// Insert one lease in default state, i.e. assigned.
|
||||
makeLease4("192.0.1.1", subnet_id);
|
||||
|
||||
// Insert one lease in declined state.
|
||||
makeLease4("192.0.1.2", subnet_id, Lease::STATE_DECLINED);
|
||||
|
||||
// Insert one lease in the expired state.
|
||||
makeLease4("192.0.1.3", subnet_id, Lease::STATE_EXPIRED_RECLAIMED);
|
||||
|
||||
// Insert another lease in default state, i.e. assigned.
|
||||
makeLease4("192.0.1.4", subnet_id);
|
||||
|
||||
// Update the expected stats list for subnet 1.
|
||||
expectedStats[subnet_id - 1]["assigned-addresses"] = 2;
|
||||
expectedStats[subnet_id - 1]["declined-addresses"] = 1;
|
||||
|
||||
// Now let's add leases to subnet 2.
|
||||
subnet_id = 2;
|
||||
|
||||
// Insert one delined lease.
|
||||
makeLease4("192.0.2.2", subnet_id, Lease::STATE_DECLINED);
|
||||
|
||||
// Update the expected stats.
|
||||
expectedStats[subnet_id - 1]["declined-addresses"] = 1;
|
||||
|
||||
// Now Recount the stats.
|
||||
ASSERT_NO_THROW(lmptr_->recountLeaseStats4());
|
||||
|
||||
// Make sure stats are as expected.
|
||||
ASSERT_NO_FATAL_FAILURE(checkLeaseStats(expectedStats));
|
||||
|
||||
// Delete some leases from subnet, and update the expected stats.
|
||||
EXPECT_TRUE(lmptr_->deleteLease(IOAddress("192.0.1.1")));
|
||||
expectedStats[0]["assigned-addresses"] = 1;
|
||||
|
||||
EXPECT_TRUE(lmptr_->deleteLease(IOAddress("192.0.1.2")));
|
||||
expectedStats[0]["declined-addresses"] = 0;
|
||||
|
||||
// Recount the stats.
|
||||
ASSERT_NO_THROW(lmptr_->recountLeaseStats4());
|
||||
|
||||
// Make sure stats are as expected.
|
||||
ASSERT_NO_FATAL_FAILURE(checkLeaseStats(expectedStats));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GenericLeaseMgrTest::testRecountLeaseStats6() {
|
||||
using namespace stats;
|
||||
|
||||
StatsMgr::instance().removeAll();
|
||||
|
||||
// Create two subnets.
|
||||
int num_subnets = 2;
|
||||
CfgSubnets6Ptr cfg = CfgMgr::instance().getStagingCfg()->getCfgSubnets6();
|
||||
Subnet6Ptr subnet;
|
||||
Pool6Ptr pool;
|
||||
StatValMapList expectedStats(num_subnets);
|
||||
|
||||
int subnet_id = 1;
|
||||
subnet.reset(new Subnet6(IOAddress("3001:1::"), 64, 1, 2, 3, 4, subnet_id));
|
||||
pool.reset(new Pool6(Lease::TYPE_NA, IOAddress("3001:1::"),
|
||||
IOAddress("3001:1::FF")));
|
||||
subnet->addPool(pool);
|
||||
expectedStats[subnet_id - 1]["total-nas"] = 256;
|
||||
|
||||
pool.reset(new Pool6(Lease::TYPE_PD, IOAddress("3001:1:2::"),96,112));
|
||||
subnet->addPool(pool);
|
||||
expectedStats[subnet_id - 1]["total-pds"] = 65536;
|
||||
cfg->add(subnet);
|
||||
|
||||
++subnet_id;
|
||||
subnet.reset(new Subnet6(IOAddress("2001:db8:1::"), 64, 1, 2, 3, 4,
|
||||
subnet_id));
|
||||
pool.reset(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1::"), 120));
|
||||
subnet->addPool(pool);
|
||||
expectedStats[subnet_id - 1]["total-nas"] = 256;
|
||||
expectedStats[subnet_id - 1]["total-pds"] = 0;
|
||||
cfg->add(subnet);
|
||||
|
||||
ASSERT_NO_THROW(CfgMgr::instance().commit());
|
||||
|
||||
|
||||
// Create the expected stats list. At this point, the only stat
|
||||
// that should be non-zero is total-nas/total-pds.
|
||||
for (int i = 0; i < num_subnets; ++i) {
|
||||
expectedStats[i]["assigned-nas"] = 0;
|
||||
expectedStats[i]["declined-addresses"] = 0;
|
||||
expectedStats[i]["declined-reclaimed-addresses"] = 0;
|
||||
expectedStats[i]["assigned-pds"] = 0;
|
||||
}
|
||||
|
||||
// Make sure stats are as expected.
|
||||
ASSERT_NO_FATAL_FAILURE(checkLeaseStats(expectedStats));
|
||||
|
||||
|
||||
// Recount stats. We should have the same results.
|
||||
ASSERT_NO_THROW(lmptr_->recountLeaseStats4());
|
||||
|
||||
// Make sure stats are as expected.
|
||||
ASSERT_NO_FATAL_FAILURE(checkLeaseStats(expectedStats));
|
||||
|
||||
// Now let's insert some leases into subnet 1.
|
||||
subnet_id = 1;
|
||||
|
||||
// Insert three assigned NAs.
|
||||
makeLease6(Lease::TYPE_NA, "3001:1::1", 0, subnet_id);
|
||||
makeLease6(Lease::TYPE_NA, "3001:1::2", 0, subnet_id);
|
||||
makeLease6(Lease::TYPE_NA, "3001:1::3", 0, subnet_id);
|
||||
expectedStats[subnet_id - 1]["assigned-nas"] = 3;
|
||||
|
||||
// Insert two declined NAs.
|
||||
makeLease6(Lease::TYPE_NA, "3001:1::4", 0, subnet_id,
|
||||
Lease::STATE_DECLINED);
|
||||
makeLease6(Lease::TYPE_NA, "3001:1::5", 0, subnet_id,
|
||||
Lease::STATE_DECLINED);
|
||||
expectedStats[subnet_id - 1]["declined-addresses"] = 2;
|
||||
|
||||
// Insert one expired NA.
|
||||
makeLease6(Lease::TYPE_NA, "3001:1::6", 0, subnet_id,
|
||||
Lease::STATE_EXPIRED_RECLAIMED);
|
||||
|
||||
// Insert two assigned PDs.
|
||||
makeLease6(Lease::TYPE_PD, "3001:1:2:0100::", 112, subnet_id);
|
||||
makeLease6(Lease::TYPE_PD, "3001:1:2:0200::", 112, subnet_id);
|
||||
expectedStats[subnet_id - 1]["assigned-pds"] = 2;
|
||||
|
||||
// Insert two expired PDs.
|
||||
makeLease6(Lease::TYPE_PD, "3001:1:2:0300::", 112, subnet_id,
|
||||
Lease::STATE_EXPIRED_RECLAIMED);
|
||||
makeLease6(Lease::TYPE_PD, "3001:1:2:0400::", 112, subnet_id,
|
||||
Lease::STATE_EXPIRED_RECLAIMED);
|
||||
|
||||
// Now let's add leases to subnet 2.
|
||||
subnet_id = 2;
|
||||
|
||||
// Insert two assigned NAs.
|
||||
makeLease6(Lease::TYPE_NA, "2001:db81::1", 0, subnet_id);
|
||||
makeLease6(Lease::TYPE_NA, "2001:db81::2", 0, subnet_id);
|
||||
expectedStats[subnet_id - 1]["assigned-nas"] = 2;
|
||||
|
||||
// Insert one declined NA.
|
||||
makeLease6(Lease::TYPE_NA, "2001:db81::3", 0, subnet_id,
|
||||
Lease::STATE_DECLINED);
|
||||
expectedStats[subnet_id - 1]["declined-addresses"] = 1;
|
||||
|
||||
// Now Recount the stats.
|
||||
ASSERT_NO_THROW(lmptr_->recountLeaseStats6());
|
||||
|
||||
// Make sure stats are as expected.
|
||||
ASSERT_NO_FATAL_FAILURE(checkLeaseStats(expectedStats));
|
||||
|
||||
// Delete some leases and update the expected stats.
|
||||
EXPECT_TRUE(lmptr_->deleteLease(IOAddress("3001:1::2")));
|
||||
expectedStats[0]["assigned-nas"] = 2;
|
||||
|
||||
EXPECT_TRUE(lmptr_->deleteLease(IOAddress("2001:db81::3")));
|
||||
expectedStats[1]["declined-addresses"] = 0;
|
||||
|
||||
// Recount the stats.
|
||||
ASSERT_NO_THROW(lmptr_->recountLeaseStats6());
|
||||
|
||||
// Make sure stats are as expected.
|
||||
ASSERT_NO_FATAL_FAILURE(checkLeaseStats(expectedStats));
|
||||
}
|
||||
|
||||
|
||||
}; // namespace test
|
||||
}; // namespace dhcp
|
||||
}; // namespace isc
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
|
||||
// Copyright (C) 2014-2016 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
|
||||
@@ -15,6 +15,12 @@ namespace isc {
|
||||
namespace dhcp {
|
||||
namespace test {
|
||||
|
||||
|
||||
/// @brief typedefs to simplify lease statistic testing
|
||||
typedef std::map<std::string, int64_t> StatValMap;
|
||||
typedef std::pair<std::string, int64_t> StatValPair;
|
||||
typedef std::vector<StatValMap> StatValMapList;
|
||||
|
||||
/// @brief Test Fixture class with utility functions for LeaseMgr backends
|
||||
///
|
||||
/// It contains utility functions, like dummy lease creation.
|
||||
@@ -94,6 +100,47 @@ public:
|
||||
/// @return vector<Lease6Ptr> Vector of pointers to leases
|
||||
std::vector<Lease6Ptr> createLeases6();
|
||||
|
||||
/// @brief Compares a StatsMgr statistic to an expected value
|
||||
///
|
||||
/// Attempt to fetch the named statistic from the StatsMg and if
|
||||
/// found, compare its observed value to the given value.
|
||||
/// Fails if the stat is not found or if the values do not match.
|
||||
///
|
||||
/// @param name StatsMgr name for the statistic to check
|
||||
/// @param expected_value expected value of the statistic
|
||||
void checkStat(const std::string& name, const int64_t expected_value);
|
||||
|
||||
/// @brief Compares StatsMgr statistics against an expected list of values
|
||||
///
|
||||
/// Iterates over a list of statistic names and expected values, attempting
|
||||
/// to fetch each from the StatsMgr and if found, compare its observed value
|
||||
/// to the expected value. Fails if any of the expected stats are not
|
||||
/// found or if the values do not match.
|
||||
///
|
||||
/// @param expected_stats Map of expected static names and values.
|
||||
void checkLeaseStats(const StatValMapList& expected_stats);
|
||||
|
||||
/// @brief Constructs a minimal IPv4 lease and adds it to the lease storage
|
||||
///
|
||||
/// @param address - IPv4 address for the lease
|
||||
/// @param subnet_id - subnet ID to which the lease belongs
|
||||
/// @param state - the state of the lease
|
||||
void makeLease4(const std::string& address, const SubnetID& subnet_id,
|
||||
const uint32_t state = Lease::STATE_DEFAULT);
|
||||
|
||||
/// @brief Constructs a minimal IPv6 lease and adds it to the lease storage
|
||||
///
|
||||
/// The DUID is constructed from the address and prefix length.
|
||||
///
|
||||
/// @param type - type of lease to create (TYPE_NA, TYPE_PD...)
|
||||
/// @param address - IPv6 address/prefix for the lease
|
||||
/// @param prefix_len = length of the prefix (should be 0 for TYPE_NA)
|
||||
/// @param subnet_id - subnet ID to which the lease belongs
|
||||
/// @param state - the state of the lease
|
||||
void makeLease6(const Lease::Type& type, const std::string& address,
|
||||
uint8_t prefix_len, const SubnetID& subnet_id,
|
||||
const uint32_t state = Lease::STATE_DEFAULT);
|
||||
|
||||
/// @brief checks that addLease, getLease4(addr) and deleteLease() works
|
||||
void testBasicLease4();
|
||||
|
||||
@@ -313,6 +360,20 @@ public:
|
||||
/// leases can be removed.
|
||||
void testDeleteExpiredReclaimedLeases4();
|
||||
|
||||
/// @brief Check that the IPv4 lease statistics can be recounted
|
||||
///
|
||||
/// This test creates two subnets and several leases associated with
|
||||
/// them, then verifies that lease statistics are recalculated correctly
|
||||
/// after altering the lease states in various ways.
|
||||
void testRecountLeaseStats4();
|
||||
|
||||
/// @brief Check that the IPv6 lease statistics can be recounted
|
||||
///
|
||||
/// This test creates two subnets and several leases associated with
|
||||
/// them, then verifies that lease statistics are recalculated correctly
|
||||
/// after altering the lease states in various ways.
|
||||
void testRecountLeaseStats6();
|
||||
|
||||
/// @brief String forms of IPv4 addresses
|
||||
std::vector<std::string> straddress4_;
|
||||
|
||||
|
@@ -1883,6 +1883,16 @@ TEST_F(MemfileLeaseMgrTest, lease6ContainerIndexUpdate) {
|
||||
}
|
||||
}
|
||||
|
||||
// Verifies that IPv4 lease statistics can be recalculated.
|
||||
TEST_F(MemfileLeaseMgrTest, recountLeaseStats4) {
|
||||
startBackend(V4);
|
||||
testRecountLeaseStats4();
|
||||
}
|
||||
|
||||
// Verifies that IPv6 lease statistics can be recalculated.
|
||||
TEST_F(MemfileLeaseMgrTest, recountLeaseStats6) {
|
||||
startBackend(V6);
|
||||
testRecountLeaseStats6();
|
||||
}
|
||||
|
||||
}; // end of anonymous namespace
|
||||
|
@@ -477,4 +477,14 @@ TEST_F(MySqlLeaseMgrTest, deleteExpiredReclaimedLeases4) {
|
||||
testDeleteExpiredReclaimedLeases4();
|
||||
}
|
||||
|
||||
// Verifies that IPv4 lease statistics can be recalculated.
|
||||
TEST_F(MySqlLeaseMgrTest, recountLeaseStats4) {
|
||||
testRecountLeaseStats4();
|
||||
}
|
||||
|
||||
// Verifies that IPv6 lease statistics can be recalculated.
|
||||
TEST_F(MySqlLeaseMgrTest, recountLeaseStats6) {
|
||||
testRecountLeaseStats6();
|
||||
}
|
||||
|
||||
}; // Of anonymous namespace
|
||||
|
@@ -402,4 +402,14 @@ TEST_F(PgSqlLeaseMgrTest, getExpiredLeases6) {
|
||||
testGetExpiredLeases6();
|
||||
}
|
||||
|
||||
// Verifies that IPv4 lease statistics can be recalculated.
|
||||
TEST_F(PgSqlLeaseMgrTest, recountLeaseStats4) {
|
||||
testRecountLeaseStats4();
|
||||
}
|
||||
|
||||
// Verifies that IPv6 lease statistics can be recalculated.
|
||||
TEST_F(PgSqlLeaseMgrTest, recountLeaseStats6) {
|
||||
testRecountLeaseStats6();
|
||||
}
|
||||
|
||||
}; // namespace
|
||||
|
Reference in New Issue
Block a user