-// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
#include <exceptions/exceptions.h>
#include <boost/shared_ptr.hpp>
+#include <vector>
+
namespace isc {
namespace dhcp {
/// is identified by HW address, another one by DUID.
///
/// @param host Pointer to the new @c Host object being added.
- virtual void add(const HostPtr& host) = 0;
+ /// @return true if addition was successful.
+ virtual bool add(const HostPtr& host) = 0;
/// @brief Attempts to delete a host by (subnet-id, address)
///
/// @brief HostDataSource pointer
typedef boost::shared_ptr<BaseHostDataSource> HostDataSourcePtr;
+/// @brief HostDataSource list
+typedef std::vector<HostDataSourcePtr> HostDataSourceList;
+
}
}
-// Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2016-2018 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
LeaseMgrFactory::create(getLeaseDbAccessString());
// Recreate host data source.
- HostDataSourceFactory::destroy();
+ HostMgr::create();
if (!host_db_access_.empty()) {
- HostMgr::create(getHostDbAccessString());
+ HostMgr::addSource(getHostDbAccessString());
}
}
-// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
return (host);
}
-void
+bool
CfgHosts::add(const HostPtr& host) {
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE, HOSTS_CFG_ADD_HOST)
.arg(host ? host->toText() : "(no-host)");
add4(host);
add6(host);
+
+ return (true);
}
void
-// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
///
/// @param host Pointer to the new @c Host object being added.
///
+ /// @return always return true as additions are successful or throw.
/// @throw DuplicateHost If a host for a particular HW address or DUID
/// has already been added to the IPv4 or IPv6 subnet.
- virtual void add(const HostPtr& host);
+ virtual bool add(const HostPtr& host);
/// @brief Attempts to delete a host by address.
///
-// Copyright (C) 2016-2017 Deutsche Telekom AG.
+// Copyright (C) 2016-2018 Deutsche Telekom AG.
//
// Author: Andrei Pavel <andrei.pavel@qualitance.com>
//
delete impl_;
}
-void
+bool
CqlHostDataSource::add(const HostPtr& host) {
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_ADD);
impl_->add(host);
+
+ return (true);
}
ConstHostCollection
-// Copyright (C) 2016-2017 Deutsche Telekom AG.
+// Copyright (C) 2016-2018 Deutsche Telekom AG.
//
// Author: Andrei Pavel <andrei.pavel@qualitance.com>
//
/// Host, where one instance is identified by different identifier types.
///
/// @param host pointer to the new @ref Host being added.
- virtual void add(const HostPtr& host) override;
+ /// @return true as addition is successful or throws.
+ virtual bool add(const HostPtr& host) override;
/// @brief Retrieves a single @ref Host connected to an IPv4 subnet.
///
map<string, HostDataSourceFactory::Factory> HostDataSourceFactory::map_;
-HostDataSourcePtr&
-HostDataSourceFactory::getHostDataSourcePtr() {
- static HostDataSourcePtr hostDataSourcePtr;
- return (hostDataSourcePtr);
-}
-
void
-HostDataSourceFactory::create(const string& dbaccess) {
+HostDataSourceFactory::add(HostDataSourceList& sources,
+ const string& dbaccess) {
// Parse the access string and create a redacted string for logging.
DatabaseConnection::ParameterMap parameters =
DatabaseConnection::parse(dbaccess);
db_type << " is invalid");
}
- // Call the factory
- getHostDataSourcePtr().reset(index->second(parameters));
+ // Call the factory and push the pointer on sources.
+ sources.push_back(boost::shared_ptr<BaseHostDataSource>(index->second(parameters)));
// Check the factory did not return NULL.
- if (!getHostDataSourcePtr()) {
+ if (!sources.back()) {
+ sources.pop_back();
isc_throw(Unexpected, "Hosts database " << db_type <<
" factory returned NULL");
}
}
-void
-HostDataSourceFactory::destroy() {
- // Destroy current host data source instance. This is a no-op if no host
- // data source is available.
- if (getHostDataSourcePtr()) {
+bool
+HostDataSourceFactory::del(HostDataSourceList& sources,
+ const string& db_type) {
+ for (auto it = sources.begin(); it != sources.end(); ++it) {
+ if ((*it)->getType() != db_type) {
+ continue;
+ }
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE, HOSTS_CFG_CLOSE_HOST_DATA_SOURCE)
- .arg(getHostDataSourcePtr()->getType());
+ .arg(db_type);
+ sources.erase(it);
+ return (true);
}
- getHostDataSourcePtr().reset();
+ return (false);
}
bool
class HostDataSourceFactory {
public:
- /// @brief Create an instance of a host data source.
+ /// @brief Create and add an instance of a host data source.
///
/// Each database backend has its own host data source type. This static
- /// method sets the "current" host data source to be an object of the
- /// appropriate type. The actual host data source is returned by the
- /// "instance" method.
- ///
- /// @note When called, the current host data source is <b>always</b> destroyed
- /// and a new one created - even if the parameters are the same.
+ /// method adds an object of the appropriate type to a list of
+ /// host data sources.
///
/// dbaccess is a generic way of passing parameters. Parameters are passed
/// in the "name=value" format, separated by spaces. The data MUST include
/// a keyword/value pair of the form "type=dbtype" giving the database
/// type, e.q. "mysql" or "sqlite3".
///
+ /// @param sources host data source list.
/// @param dbaccess Database access parameters. These are in the form of
/// "keyword=value" pairs, separated by spaces. They are backend-
/// -end specific, although must include the "type" keyword which
/// keyword.
/// @throw isc::dhcp::InvalidType The "type" keyword in dbaccess does not
/// identify a supported backend.
- static void create(const std::string& dbaccess);
+ static void add(HostDataSourceList& sources, const std::string& dbaccess);
- /// @brief Destroy host data source
+ /// @brief Delete a host data source.
///
- /// Destroys the current host data source object. This should have the effect
- /// of closing the database connection. The method is a no-op if no
- /// host data source is available.
- static void destroy();
-
- /// @brief Hold pointer to host data source instance
+ /// Delete the first instance of a host data source of the given type.
+ /// This should have the effect of closing the database connection.
///
- /// Holds a pointer to the singleton host data source. The singleton
- /// is encapsulated in this method to avoid a "static initialization
- /// fiasco" if defined in an external static variable.
- static HostDataSourcePtr& getHostDataSourcePtr();
+ /// @param sources host data source list.
+ /// @param db_type database backend type.
+ /// @return true when found and removed, false when not found.
+ static bool del(HostDataSourceList& sources, const std::string& db_type);
/// @brief Type of host data source factory
///
-// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
}
void
-HostMgr::create(const std::string& access) {
+HostMgr::create() {
getHostMgrPtr().reset(new HostMgr());
+}
- if (!access.empty()) {
- // If the user specified parameters, let's pass them to the create
- // method. It will destroy any prior instances and will create
- // the new one.
- HostDataSourceFactory::create(access);
- } else {
- // Ok, no parameters were specified. We should destroy the existing
- // instance.
- HostDataSourceFactory::destroy();
- }
+void
+HostMgr::addSource(const std::string& access) {
+ HostDataSourceFactory::add(getHostMgrPtr()->alternate_sources_, access);
+}
+
+bool
+HostMgr::delSource(const std::string& db_type) {
+ return (HostDataSourceFactory::del(getHostMgrPtr()->alternate_sources_, db_type));
+}
- // Now store the host data source pointer. It may be NULL. That's ok as
- // NULL value indicates that there's no host data source configured.
- getHostMgrPtr()->alternate_source_ =
- HostDataSourceFactory::getHostDataSourcePtr();
+void
+HostMgr::delAllSources() {
+ getHostMgrPtr()->alternate_sources_.clear();
+}
+
+HostDataSourcePtr
+HostMgr::getHostDataSource() const {
+ if (alternate_sources_.empty()) {
+ return (HostDataSourcePtr());
+ }
+ return (alternate_sources_[0]);
}
HostMgr&
ConstHostCollection
HostMgr::getAll(const HWAddrPtr& hwaddr, const DuidPtr& duid) const {
ConstHostCollection hosts = getCfgHosts()->getAll(hwaddr, duid);
- if (alternate_source_) {
- ConstHostCollection hosts_plus = alternate_source_->getAll(hwaddr, duid);
+ for (auto it = alternate_sources_.begin();
+ it != alternate_sources_.end(); ++it) {
+ ConstHostCollection hosts_plus = (*it)->getAll(hwaddr, duid);
hosts.insert(hosts.end(), hosts_plus.begin(), hosts_plus.end());
}
return (hosts);
ConstHostCollection hosts = getCfgHosts()->getAll(identifier_type,
identifier_begin,
identifier_len);
- if (alternate_source_) {
+ for (auto it = alternate_sources_.begin();
+ it != alternate_sources_.end(); ++it) {
ConstHostCollection hosts_plus =
- alternate_source_->getAll(identifier_type, identifier_begin,
- identifier_len);
+ (*it)->getAll(identifier_type, identifier_begin, identifier_len);
hosts.insert(hosts.end(), hosts_plus.begin(), hosts_plus.end());
}
return (hosts);
ConstHostCollection
HostMgr::getAll4(const IOAddress& address) const {
ConstHostCollection hosts = getCfgHosts()->getAll4(address);
- if (alternate_source_) {
- ConstHostCollection hosts_plus = alternate_source_->getAll4(address);
+ for (auto it = alternate_sources_.begin();
+ it != alternate_sources_.end(); ++it) {
+ ConstHostCollection hosts_plus = (*it)->getAll4(address);
hosts.insert(hosts.end(), hosts_plus.begin(), hosts_plus.end());
}
return (hosts);
HostMgr::get4(const SubnetID& subnet_id, const HWAddrPtr& hwaddr,
const DuidPtr& duid) const {
ConstHostPtr host = getCfgHosts()->get4(subnet_id, hwaddr, duid);
- if (!host && alternate_source_) {
+ for (auto it = alternate_sources_.begin();
+ it != alternate_sources_.end(); ++it) {
+ if (host) {
+ break;
+ }
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_HWADDR_DUID)
.arg(subnet_id)
.arg(hwaddr ? hwaddr->toText() : "(no-hwaddr)")
.arg(duid ? duid->toText() : "(duid)");
if (duid) {
- host = alternate_source_->get4(subnet_id, HWAddrPtr(), duid);
+ host = (*it)->get4(subnet_id, HWAddrPtr(), duid);
}
if (!host && hwaddr) {
- host = alternate_source_->get4(subnet_id, hwaddr, DuidPtr());
+ host = (*it)->get4(subnet_id, hwaddr, DuidPtr());
}
}
return (host);
const size_t identifier_len) const {
ConstHostPtr host = getCfgHosts()->get4(subnet_id, identifier_type,
identifier_begin, identifier_len);
- if (!host && alternate_source_) {
-
+ for (auto it = alternate_sources_.begin();
+ it != alternate_sources_.end(); ++it) {
+ if (host) {
+ break;
+ }
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_IDENTIFIER)
.arg(subnet_id)
- .arg(Host::getIdentifierAsText(identifier_type, identifier_begin,
+ .arg(Host::getIdentifierAsText(identifier_type,
+ identifier_begin,
identifier_len));
- host = alternate_source_->get4(subnet_id, identifier_type,
- identifier_begin, identifier_len);
+ host = (*it)->get4(subnet_id, identifier_type,
+ identifier_begin, identifier_len);
if (host) {
LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS,
HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_IDENTIFIER_HOST)
.arg(subnet_id)
- .arg(Host::getIdentifierAsText(identifier_type, identifier_begin,
+ .arg(Host::getIdentifierAsText(identifier_type,
+ identifier_begin,
identifier_len))
.arg(host->toText());
-
- } else {
- LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS,
- HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_IDENTIFIER_NULL)
- .arg(subnet_id)
- .arg(Host::getIdentifierAsText(identifier_type, identifier_begin,
- identifier_len));
+ break;
}
+ LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS,
+ HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_IDENTIFIER_NULL)
+ .arg(subnet_id)
+ .arg(Host::getIdentifierAsText(identifier_type,
+ identifier_begin,
+ identifier_len));
}
return (host);
HostMgr::get4(const SubnetID& subnet_id,
const asiolink::IOAddress& address) const {
ConstHostPtr host = getCfgHosts()->get4(subnet_id, address);
- if (!host && alternate_source_) {
+ for (auto it = alternate_sources_.begin();
+ it != alternate_sources_.end(); ++it) {
+ if (host) {
+ break;
+ }
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
HOSTS_MGR_ALTERNATE_GET4_SUBNET_ID_ADDRESS4)
.arg(subnet_id)
.arg(address.toText());
- host = alternate_source_->get4(subnet_id, address);
+ host = (*it)->get4(subnet_id, address);
}
return (host);
}
HostMgr::get6(const SubnetID& subnet_id, const DuidPtr& duid,
const HWAddrPtr& hwaddr) const {
ConstHostPtr host = getCfgHosts()->get6(subnet_id, duid, hwaddr);
- if (!host && alternate_source_) {
+ for (auto it = alternate_sources_.begin();
+ it != alternate_sources_.end(); ++it) {
+ if (host) {
+ break;
+ }
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_DUID_HWADDR)
.arg(subnet_id)
.arg(duid ? duid->toText() : "(duid)")
.arg(hwaddr ? hwaddr->toText() : "(no-hwaddr)");
if (duid) {
- host = alternate_source_->get6(subnet_id, duid, HWAddrPtr());
+ host = (*it)->get6(subnet_id, duid, HWAddrPtr());
}
if (!host && hwaddr) {
- host = alternate_source_->get6(subnet_id, DuidPtr(), hwaddr);
+ host = (*it)->get6(subnet_id, DuidPtr(), hwaddr);
}
}
return (host);
ConstHostPtr
HostMgr::get6(const IOAddress& prefix, const uint8_t prefix_len) const {
ConstHostPtr host = getCfgHosts()->get6(prefix, prefix_len);
- if (!host && alternate_source_) {
+ for (auto it = alternate_sources_.begin();
+ it != alternate_sources_.end(); ++it) {
+ if (host) {
+ break;
+ }
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
HOSTS_MGR_ALTERNATE_GET6_PREFIX)
.arg(prefix.toText())
.arg(static_cast<int>(prefix_len));
- host = alternate_source_->get6(prefix, prefix_len);
+ host = (*it)->get6(prefix, prefix_len);
}
return (host);
}
const size_t identifier_len) const {
ConstHostPtr host = getCfgHosts()->get6(subnet_id, identifier_type,
identifier_begin, identifier_len);
- if (!host && alternate_source_) {
-
+ for (auto it = alternate_sources_.begin();
+ it != alternate_sources_.end(); ++it) {
+ if (host) {
+ break;
+ }
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_IDENTIFIER)
.arg(subnet_id)
- .arg(Host::getIdentifierAsText(identifier_type, identifier_begin,
+ .arg(Host::getIdentifierAsText(identifier_type,
+ identifier_begin,
identifier_len));
-
- host = alternate_source_->get6(subnet_id, identifier_type,
- identifier_begin, identifier_len);
+ host = (*it)->get6(subnet_id, identifier_type,
+ identifier_begin, identifier_len);
if (host) {
- LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS,
- HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_IDENTIFIER_HOST)
- .arg(subnet_id)
- .arg(Host::getIdentifierAsText(identifier_type, identifier_begin,
- identifier_len))
- .arg(host->toText());
-
- } else {
- LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS,
- HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_IDENTIFIER_NULL)
- .arg(subnet_id)
- .arg(Host::getIdentifierAsText(identifier_type, identifier_begin,
- identifier_len));
+ LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS,
+ HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_IDENTIFIER_HOST)
+ .arg(subnet_id)
+ .arg(Host::getIdentifierAsText(identifier_type,
+ identifier_begin,
+ identifier_len))
+ .arg(host->toText());
+ break;
}
-
+ LOG_DEBUG(hosts_logger, HOSTS_DBG_RESULTS,
+ HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_IDENTIFIER_NULL)
+ .arg(subnet_id)
+ .arg(Host::getIdentifierAsText(identifier_type,
+ identifier_begin,
+ identifier_len));
}
return (host);
}
HostMgr::get6(const SubnetID& subnet_id,
const asiolink::IOAddress& addr) const {
ConstHostPtr host = getCfgHosts()->get6(subnet_id, addr);
- if (!host && alternate_source_) {
+ for (auto it = alternate_sources_.begin();
+ it != alternate_sources_.end(); ++it) {
+ if (host) {
+ break;
+ }
LOG_DEBUG(hosts_logger, HOSTS_DBG_TRACE,
HOSTS_MGR_ALTERNATE_GET6_SUBNET_ID_ADDRESS6)
.arg(subnet_id)
.arg(addr.toText());
- host = alternate_source_->get6(subnet_id, addr);
+ host = (*it)->get6(subnet_id, addr);
}
return (host);
}
-void
+bool
HostMgr::add(const HostPtr& host) {
- if (!alternate_source_) {
+ if (alternate_sources_.empty()) {
isc_throw(NoHostDataSourceManager, "Unable to add new host because there is "
"no hosts-database configured.");
}
- alternate_source_->add(host);
+ for (auto it = alternate_sources_.begin();
+ it != alternate_sources_.end(); ++it) {
+ if ((*it)->add(host)) {
+ return (true);
+ }
+ }
+ // This should never happen as at least one backend implements addition.
+ return (false);
}
bool
HostMgr::del(const SubnetID& subnet_id, const asiolink::IOAddress& addr) {
- if (!alternate_source_) {
+ if (alternate_sources_.empty()) {
isc_throw(NoHostDataSourceManager, "Unable to delete a host because there is "
"no hosts-database configured.");
}
- return (alternate_source_->del(subnet_id, addr));
+ for (auto it = alternate_sources_.begin();
+ it != alternate_sources_.end(); ++it) {
+ if ((*it)->del(subnet_id, addr)) {
+ return (true);
+ }
+ }
+ return (false);
}
bool
HostMgr::del4(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin, const size_t identifier_len) {
- if (!alternate_source_) {
+ if (alternate_sources_.empty()) {
isc_throw(NoHostDataSourceManager, "Unable to delete a host because there is "
"no hosts-database configured.");
}
- return (alternate_source_->del4(subnet_id, identifier_type,
- identifier_begin, identifier_len));
+ for (auto it = alternate_sources_.begin();
+ it != alternate_sources_.end(); ++it) {
+ if ((*it)->del4(subnet_id, identifier_type,
+ identifier_begin, identifier_len)) {
+ return (true);
+ }
+ }
+ return (false);
}
bool
HostMgr::del6(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin, const size_t identifier_len) {
- if (!alternate_source_) {
+ if (alternate_sources_.empty()) {
isc_throw(NoHostDataSourceManager, "unable to delete a host because there is "
"no alternate host data source present");
}
- return (alternate_source_->del6(subnet_id, identifier_type,
- identifier_begin, identifier_len));
+ for (auto it = alternate_sources_.begin();
+ it != alternate_sources_.end(); ++it) {
+ if ((*it)->del6(subnet_id, identifier_type,
+ identifier_begin, identifier_len)) {
+ return (true);
+ }
+ }
+ return (false);
}
} // end of isc::dhcp namespace
-// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
/// configuration, accessible through the @c CfgHosts object in the @c CfgMgr.
/// The @c CfgHosts object holds all reservations specified in the DHCP server
/// configuration file. If a particular reservation is not found in the
-/// @c CfgHosts object, the @c HostMgr will try to find it using the alternate
-/// host data storage. The alternate host data storage is usually a database
+/// @c CfgHosts object, the @c HostMgr will try to find it using alternate
+/// host data storages. An alternate host data storage is usually a database
/// (e.g. SQL database), accessible through a dedicated host data source
/// object (a.k.a. database backend). This datasource is responsible for
/// managing the connection with the database and forming appropriate queries
/// to retrieve (or update) the information about the reservations.
///
-/// The use of the alternate host data source is optional and usually requires
+/// The use of alternate host data sources is optional and usually requires
/// additional configuration to be specified by the server administrator.
/// For example, for the SQL database the user's credentials, database address,
/// and database name are required. The @c HostMgr passes these parameters
/// to an appropriate datasource which is responsible for opening a connection
/// and maintaining it.
///
-/// It is possible to switch to a different alternate data source or disable
-/// the use of the alternate datasource, e.g. as a result of server's
+/// It is possible to switch to different alternate data sources or disable
+/// the use of alternate datasources, e.g. as a result of server's
/// reconfiguration. However, the use of the primary host data source (i.e.
/// reservations specified in the configuration file) can't be disabled.
-///
-/// @todo Implement alternate host data sources: MySQL, PostgreSQL, etc.
class HostMgr : public boost::noncopyable, public BaseHostDataSource {
public:
/// @brief Creates new instance of the @c HostMgr.
///
/// If an instance of the @c HostMgr already exists, it will be replaced
- /// by the new instance. Thus, any instances of the alternate host data
+ /// by the new instance. Thus, any instances of alternate host data
/// sources will be dropped.
///
+ static void create();
+
+ /// @brief Add an alternate host data source.
+ ///
/// @param access Host data source access parameters for the alternate
/// host data source. It holds "keyword=value" pairs, separated by spaces.
/// The supported values are specific to the alternate data source in use.
/// However, the "type" parameter will be common and it will specify which
/// data source is to be used. Currently, no parameters are supported
/// and the parameter is ignored.
- static void create(const std::string& access = "");
+ static void addSource(const std::string& access);
+
+ /// @brief Delete an alternate host data source.
+ ///
+ /// @param db_type_type database backend type.
+ /// @return true when found and removed, false when not found.
+ static bool delSource(const std::string& db_type);
+
+ /// @brief Delete all alternate host data source.
+ static void delAllSources();
/// @brief Returns a sole instance of the @c HostMgr.
///
/// in use.
///
/// @param host Pointer to the new @c Host object being added.
- virtual void add(const HostPtr& host);
+ /// @return true if addition was successful.
+ virtual bool add(const HostPtr& host);
/// @brief Return backend type
///
return (std::string("host_mgr"));
}
- /// @brief Returns pointer to the host data source
+ /// @brief Returns the host data source list.
///
- /// May return NULL
- /// @return pointer to the host data source (or NULL)
- HostDataSourcePtr getHostDataSource() const {
- return (alternate_source_);
+ /// @return reference to the host data source list.
+ HostDataSourceList& getHostDataSourceList() {
+ return (alternate_sources_);
}
- /// @brief Sets the alternate host data source.
+ /// @brief Returns the fist host data source.
+ ///
+ /// May return NULL if the host data source list is empty.
+ /// @return pointer to the first host data source (or NULL)
+ HostDataSourcePtr getHostDataSource() const;
+
+ /// @brief Sets alternate host data source list.
///
/// Note: This should be used only for testing. Do not use
/// in production. Normal control flow assumes that
- /// HostMgr::create(...) is called and it instantiates
- /// appropriate host data source. However, some tests
+ /// HostMgr::create() and HostMgr::add() is called and it instantiates
+ /// appropriate host data sources. However, some tests
/// (e.g. host_cmds) implement their own very simple
/// data source. It's not production ready by any means,
/// so it does not belong in host_data_source_factory.cc.
/// The testing nature of this method is reflected in its name.
///
- /// @param source new source to be set (may be NULL)
- void setTestHostDataSource(const HostDataSourcePtr& source) {
- alternate_source_ = source;
+ /// @param sources new source list to be set
+ void setTestHostDataSourceList(const HostDataSourceList& sources) {
+ alternate_sources_ = sources;
}
/// @brief Attempts to delete a host by address.
/// @brief Private default constructor.
HostMgr() { }
- /// @brief Pointer to an alternate host data source.
- ///
- /// If this pointer is NULL, the source is not in use.
- HostDataSourcePtr alternate_source_;
+ /// @brief List of alternate host data sources.
+ HostDataSourceList alternate_sources_;
/// @brief Returns a pointer to the currently used instance of the
/// @c HostMgr.
-// Copyright (C) 2015-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2018 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
delete impl_;
}
-void
+bool
MySqlHostDataSource::add(const HostPtr& host) {
// If operating in read-only mode, throw exception.
impl_->checkReadOnly();
// Everything went fine, so explicitly commit the transaction.
transaction.commit();
+
+ return (true);
}
bool
-// Copyright (C) 2015-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2018 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
/// one instance is identified by HW address, another one by DUID.
///
/// @param host Pointer to the new @c Host object being added.
- virtual void add(const HostPtr& host);
+ /// @return true as addition is successful or throws.
+ virtual bool add(const HostPtr& host);
/// @brief Attempts to delete a host by (subnet-id, address)
///
delete impl_;
}
-void
+bool
PgSqlHostDataSource::add(const HostPtr& host) {
// If operating in read-only mode, throw exception.
impl_->checkReadOnly();
// Everything went fine, so explicitly commit the transaction.
transaction.commit();
+
+ return (true);
}
bool
-// Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2016-2018 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
/// -# Address and Prefix Length must be unique (DuplicateEntry)
///
/// @param host Pointer to the new @c Host object being added.
+ /// @return true as addition is successful or throws.
/// @throw DuplicateEntry or DbOperationError dependent on the constraint
/// violation
- virtual void add(const HostPtr& host);
+ virtual bool add(const HostPtr& host);
/// @brief Attempts to delete a host by (subnet-id, address)
///
#include <dhcpsrv/cql_host_data_source.h>
#include <dhcpsrv/cql_lease_mgr.h>
#include <dhcpsrv/host.h>
+#include <dhcpsrv/host_mgr.h>
#include <dhcpsrv/host_data_source_factory.h>
#include <dhcpsrv/tests/generic_host_data_source_unittest.h>
#include <dhcpsrv/tests/test_utils.h>
// Connect to the database
try {
- HostDataSourceFactory::create(validCqlConnectionString());
+ HostMgr::create();
+ HostMgr::addSource(validCqlConnectionString());
} catch (...) {
std::cerr << "*** ERROR: unable to open database. The test"
"*** environment is broken and must be fixed before"
throw;
}
- hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr();
+ hdsptr_ = HostMgr::instance().getHostDataSource();
}
/// @brief Destroys the HDS and the schema.
// Rollback should never fail, as Cassandra doesn't support transactions
// (commit and rollback are both no-op).
}
- HostDataSourceFactory::destroy();
+ HostMgr::delAllSources();
+ hdsptr_.reset();
destroyCqlSchema(false, true);
}
/// Parameter is ignored for CQL backend as the v4 and v6 leases share
/// the same database.
void reopen(Universe) {
- HostDataSourceFactory::destroy();
- HostDataSourceFactory::create(validCqlConnectionString());
- hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr();
+ HostMgr::create();
+ HostMgr::addSource(validCqlConnectionString());
+ hdsptr_ = HostMgr::instance().getHostDataSource();
}
};
// Check that lease manager open the database opens correctly and tidy up.
// If it fails, print the error message.
try {
- HostDataSourceFactory::create(validCqlConnectionString());
- EXPECT_NO_THROW((void)HostDataSourceFactory::getHostDataSourcePtr());
- HostDataSourceFactory::destroy();
+ HostMgr::create();
+ EXPECT_NO_THROW(HostMgr::addSource(validCqlConnectionString()));
+ HostMgr::delSource("cql");
} catch (const isc::Exception& ex) {
FAIL() << "*** ERROR: unable to open database, reason:\n"
<< " " << ex.what() << "\n"
try {
std::string connection_string = validCqlConnectionString() + std::string(" ") +
std::string(VALID_TIMEOUT);
- HostDataSourceFactory::create(connection_string);
- EXPECT_NO_THROW((void)HostDataSourceFactory::getHostDataSourcePtr());
- HostDataSourceFactory::destroy();
+ HostMgr::create();
+ EXPECT_NO_THROW(HostMgr::addSource(connection_string));
+ HostMgr::delSource("cql");
} catch (const isc::Exception& ex) {
FAIL() << "*** ERROR: unable to open database, reason:\n"
<< " " << ex.what() << "\n"
// Check that attempting to get an instance of the host data source when
// none is set throws an exception.
- EXPECT_FALSE(HostDataSourceFactory::getHostDataSourcePtr());
+ EXPECT_FALSE(HostMgr::instance().getHostDataSource());
// Check that wrong specification of backend throws an exception.
// (This is really a check on HostDataSourceFactory, but is convenient to
// perform here.)
- EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ EXPECT_THROW(HostMgr::addSource(connectionString(
NULL, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
InvalidParameter);
- EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ EXPECT_THROW(HostMgr::addSource(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(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
+ EXPECT_NO_THROW(HostMgr::addSource(connectionString(CQL_VALID_TYPE,
INVALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)));
- EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
+ EXPECT_NO_THROW(HostMgr::addSource(connectionString(CQL_VALID_TYPE,
VALID_NAME, INVALID_HOST, VALID_USER, VALID_PASSWORD)));
- EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
+ EXPECT_NO_THROW(HostMgr::addSource(connectionString(CQL_VALID_TYPE,
VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)));
- EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
+ EXPECT_NO_THROW(HostMgr::addSource(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,
+ EXPECT_THROW(HostMgr::addSource(connectionString(CQL_VALID_TYPE,
VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_1)),
DbOperationError);
- EXPECT_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
+ EXPECT_THROW(HostMgr::addSource(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,
+ EXPECT_NO_THROW(HostMgr::addSource(connectionString(CQL_VALID_TYPE,
NULL, VALID_HOST, INVALID_USER, VALID_PASSWORD)));
// Tidy up after the test
#include <dhcp/option_string.h>
#include <dhcp/option_vendor.h>
#include <dhcpsrv/database_connection.h>
+#include <dhcpsrv/host_mgr.h>
#include <dhcpsrv/host_data_source_factory.h>
#include <dhcpsrv/tests/generic_host_data_source_unittest.h>
#include <dhcpsrv/tests/test_utils.h>
// Close the database connection and reopen in "read-only" mode as
// specified by the "VALID_READONLY_DB" parameter.
- HostDataSourceFactory::destroy();
- HostDataSourceFactory::create(connectionString(
+ HostMgr::create();
+ HostMgr::addSource(connectionString(
valid_db_type, VALID_NAME, VALID_HOST, VALID_READONLY_USER,
VALID_PASSWORD, VALID_READONLY_DB));
- hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr();
+ hdsptr_ = HostMgr::instance().getHostDataSource();
// Check that an attempt to insert new host would result in
// exception.
--- /dev/null
+// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <dhcpsrv/host_data_source_factory.h>
+#include <exceptions/exceptions.h>
+
+#include <gtest/gtest.h>
+
+#include <iostream>
+#include <sstream>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+
+namespace {
+
+// @brief Names of test backends
+enum Names { FOOBAR, FOO, BAR };
+
+// @brief Convert a name to a string
+string toString(Names name) {
+ switch (name) {
+ case FOOBAR:
+ return ("foobar");
+ case FOO:
+ return ("foo");
+ default:
+ return ("bar");
+ }
+}
+
+// A host data source
+template <Names NAME>
+class FakeHostDataSource : public BaseHostDataSource {
+public:
+ // @brief Constructor
+ FakeHostDataSource(const DatabaseConnection::ParameterMap&) { }
+
+ virtual ~FakeHostDataSource() { }
+
+ // The base class is abstract so we need to define methods
+
+ virtual ConstHostCollection
+ getAll(const HWAddrPtr&, const DuidPtr&) const {
+ return (ConstHostCollection());
+ }
+
+ virtual ConstHostCollection
+ getAll(const Host::IdentifierType&, const uint8_t*, const size_t) const {
+ return (ConstHostCollection());
+ }
+
+ virtual ConstHostCollection
+ getAll4(const asiolink::IOAddress&) const {
+ return (ConstHostCollection());
+ }
+
+ virtual ConstHostPtr
+ get4(const SubnetID&, const HWAddrPtr&, const DuidPtr&) const {
+ return (ConstHostPtr());
+ }
+
+ virtual ConstHostPtr
+ get4(const SubnetID&, const Host::IdentifierType&,
+ const uint8_t*, const size_t) const {
+ return (ConstHostPtr());
+ }
+
+ virtual ConstHostPtr
+ get4(const SubnetID&, const asiolink::IOAddress&) const {
+ return (ConstHostPtr());
+ }
+
+ virtual ConstHostPtr
+ get6(const SubnetID&, const DuidPtr&, const HWAddrPtr&) const {
+ return (ConstHostPtr());
+ }
+
+ virtual ConstHostPtr
+ get6(const SubnetID&, const Host::IdentifierType&,
+ const uint8_t*, const size_t) const {
+ return (ConstHostPtr());
+ }
+
+ virtual ConstHostPtr
+ get6(const asiolink::IOAddress&, const uint8_t) const {
+ return (ConstHostPtr());
+ }
+
+ virtual ConstHostPtr
+ get6(const SubnetID&, const asiolink::IOAddress&) const {
+ return (ConstHostPtr());
+ }
+
+ virtual bool add(const HostPtr&) {
+ return (false);
+ }
+
+ virtual bool del(const SubnetID&, const asiolink::IOAddress&) {
+ return (false);
+ }
+
+ virtual bool del4(const SubnetID&, const Host::IdentifierType&,
+ const uint8_t*, const size_t) {
+ return (false);
+ }
+
+ virtual bool del6(const SubnetID&, const Host::IdentifierType&,
+ const uint8_t*, const size_t) {
+ return (false);
+ }
+
+ virtual string getType() const {
+ return (toString(NAME));
+ }
+};
+
+// @brief Factory function template
+template <Names NAME>
+BaseHostDataSource*
+factory(const DatabaseConnection::ParameterMap& parameters) {
+ return (new FakeHostDataSource<NAME>(parameters));
+}
+
+// @brief Register factory template
+template <Names NAME>
+bool registerFactory() {
+ return (HostDataSourceFactory::registerFactory(toString(NAME),
+ factory<NAME>));
+}
+
+// @brief Factory function returning 0
+BaseHostDataSource* factory0(const DatabaseConnection::ParameterMap&) {
+ return (0);
+}
+
+// @brief Test fixture class
+class HostDataSourceFactoryTest : public ::testing::Test {
+private:
+ // @brief Prepares the class for a test.
+ virtual void SetUp() {
+ }
+
+ // @brief Cleans up after the test.
+ virtual void TearDown() {
+ sources_.clear();
+ HostDataSourceFactory::deregisterFactory("foobar");
+ HostDataSourceFactory::deregisterFactory("foo");
+ HostDataSourceFactory::deregisterFactory("bar");
+ }
+public:
+ HostDataSourceList sources_;
+};
+
+// Verify a factory can be registered and only once.
+TEST_F(HostDataSourceFactoryTest, registerFactory) {
+ EXPECT_TRUE(registerFactory<Names::FOOBAR>());
+
+ // Only once
+ EXPECT_FALSE(registerFactory<Names::FOOBAR>());
+}
+
+// Verify a factory can be registered and deregistered
+TEST_F(HostDataSourceFactoryTest, deregisterFactory) {
+ // Does not exist at the beginning
+ EXPECT_FALSE(HostDataSourceFactory::deregisterFactory("foobar"));
+
+ // Register and deregister
+ EXPECT_TRUE(registerFactory<Names::FOOBAR>());
+ EXPECT_TRUE(HostDataSourceFactory::deregisterFactory("foobar"));
+
+ // No longer exists
+ EXPECT_FALSE(HostDataSourceFactory::deregisterFactory("foobar"));
+}
+
+// Verify a registered factory can be called
+TEST_F(HostDataSourceFactoryTest, add) {
+ EXPECT_TRUE(registerFactory<Names::FOOBAR>());
+ EXPECT_NO_THROW(HostDataSourceFactory::add(sources_, "type=foobar"));
+ ASSERT_EQ(1, sources_.size());
+ EXPECT_EQ("foobar", sources_[0]->getType());
+}
+
+// Verify that type is required
+TEST_F(HostDataSourceFactoryTest, notype) {
+ EXPECT_THROW(HostDataSourceFactory::add(sources_, "tp=foobar"),
+ InvalidParameter);
+ EXPECT_THROW(HostDataSourceFactory::add(sources_, "type=foobar"),
+ InvalidType);
+}
+
+// Verify that factory must not return NULL
+TEST_F(HostDataSourceFactoryTest, null) {
+ EXPECT_TRUE(HostDataSourceFactory::registerFactory("foobar", factory0));
+ EXPECT_THROW(HostDataSourceFactory::add(sources_, "type=foobar"),
+ Unexpected);
+}
+
+// Verify del class method
+TEST_F(HostDataSourceFactoryTest, del) {
+ // No sources at the beginning
+ EXPECT_FALSE(HostDataSourceFactory::del(sources_, "foobar"));
+
+ // Add foobar
+ EXPECT_TRUE(registerFactory<Names::FOOBAR>());
+ EXPECT_NO_THROW(HostDataSourceFactory::add(sources_, "type=foobar"));
+ ASSERT_EQ(1, sources_.size());
+
+ // Delete another
+ EXPECT_FALSE(HostDataSourceFactory::del(sources_, "another"));
+
+ // Delete foobar
+ EXPECT_TRUE(HostDataSourceFactory::del(sources_, "foobar"));
+
+ // No longer foobar in sources
+ EXPECT_FALSE(HostDataSourceFactory::del(sources_, "foobar"));
+}
+
+// Verify add and del class method on multiple backends
+TEST_F(HostDataSourceFactoryTest, multiple) {
+ // Add foo twice
+ EXPECT_TRUE(registerFactory<Names::FOO>());
+ EXPECT_NO_THROW(HostDataSourceFactory::add(sources_, "type=foo"));
+ EXPECT_NO_THROW(HostDataSourceFactory::add(sources_, "type=foo"));
+
+ // Add bar once
+ EXPECT_TRUE(registerFactory<Names::BAR>());
+ EXPECT_NO_THROW(HostDataSourceFactory::add(sources_, "type=bar"));
+
+ // Delete them
+ EXPECT_TRUE(HostDataSourceFactory::del(sources_, "foo"));
+ EXPECT_TRUE(HostDataSourceFactory::del(sources_, "bar"));
+ // Second instance of foo
+ EXPECT_TRUE(HostDataSourceFactory::del(sources_, "foo"));
+
+ // No more sources
+ EXPECT_EQ(0, sources_.size());
+ EXPECT_FALSE(HostDataSourceFactory::del(sources_, "foo"));
+ EXPECT_FALSE(HostDataSourceFactory::del(sources_, "bar"));
+}
+
+}; // end of anonymous namespace
-// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// If there non-matching HW address is specified, nothing should be
// returned.
hosts = HostMgr::instance().getAll(Host::IDENT_HWADDR,
- &hwaddrs_[1]->hwaddr_[0],
- hwaddrs_[1]->hwaddr_.size());
+ &hwaddrs_[1]->hwaddr_[0],
+ hwaddrs_[1]->hwaddr_.size());
ASSERT_TRUE(hosts.empty());
// For the correct HW address, there should be two reservations.
// Look for the first reservation.
bool found = false;
- for (int i = 0; i < 2; ++i) {
+ for (unsigned i = 0; i < 2; ++i) {
if (hosts[0]->getIPv4Reservation() == IOAddress("192.0.2.5")) {
ASSERT_EQ(1, hosts[0]->getIPv4SubnetID());
found = true;
// Look for the second reservation.
found = false;
- for (int i = 0; i < 2; ++i) {
+ for (unsigned i = 0; i < 2; ++i) {
if (hosts[1]->getIPv4Reservation() == IOAddress("192.0.3.10")) {
ASSERT_EQ(10, hosts[1]->getIPv4SubnetID());
found = true;
// Connect to the database
try {
- HostMgr::create(test::validMySQLConnectionString());
+ HostMgr::addSource(test::validMySQLConnectionString());
} catch (...) {
std::cerr << "*** ERROR: unable to open database. The test\n"
"*** environment is broken and must be fixed before\n"
void
MySQLHostMgrTest::TearDown() {
- HostDataSourceFactory::getHostDataSourcePtr()->rollback();
- HostDataSourceFactory::destroy();
+ HostMgr::instance().getHostDataSource()->rollback();
+ HostMgr::delSource("mysql");
test::destroyMySQLSchema();
}
// Connect to the database
try {
- HostMgr::create(test::validPgSQLConnectionString());
+ HostMgr::addSource(test::validPgSQLConnectionString());
} catch (...) {
std::cerr << "*** ERROR: unable to open database. The test\n"
"*** environment is broken and must be fixed before\n"
void
PostgreSQLHostMgrTest::TearDown() {
- HostDataSourceFactory::getHostDataSourcePtr()->rollback();
- HostDataSourceFactory::destroy();
+ HostMgr::instance().getHostDataSource()->rollback();
+ HostMgr::delSource("postgresql");
test::destroyPgSQLSchema();
}
-// Copyright (C) 2015-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2018 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
#include <dhcpsrv/mysql_host_data_source.h>
#include <dhcpsrv/tests/generic_host_data_source_unittest.h>
#include <dhcpsrv/testutils/mysql_schema.h>
+#include <dhcpsrv/host_mgr.h>
#include <dhcpsrv/host_data_source_factory.h>
#include <gtest/gtest.h>
// Connect to the database
try {
- HostDataSourceFactory::create(validMySQLConnectionString());
+ HostMgr::create();
+ HostMgr::addSource(validMySQLConnectionString());
} catch (...) {
std::cerr << "*** ERROR: unable to open database. The test\n"
"*** environment is broken and must be fixed before\n"
throw;
}
- hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr();
+ hdsptr_ = HostMgr::instance().getHostDataSource();
}
/// @brief Destructor
} catch (...) {
// Rollback may fail if backend is in read only mode. That's ok.
}
- HostDataSourceFactory::destroy();
+ HostMgr::delAllSources();
hdsptr_.reset();
destroyMySQLSchema();
}
/// Parameter is ignored for MySQL backend as the v4 and v6 leases share
/// the same database.
void reopen(Universe) {
- HostDataSourceFactory::destroy();
- HostDataSourceFactory::create(validMySQLConnectionString());
- hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr();
+ HostMgr::create();
+ HostMgr::addSource(validMySQLConnectionString());
+ hdsptr_ = HostMgr::instance().getHostDataSource();
}
/// @brief returns number of rows in a table
// Check that lease manager open the database opens correctly and tidy up.
// If it fails, print the error message.
try {
- HostDataSourceFactory::create(validMySQLConnectionString());
- EXPECT_NO_THROW((void) HostDataSourceFactory::getHostDataSourcePtr());
- HostDataSourceFactory::destroy();
+ HostMgr::create();
+ EXPECT_NO_THROW(HostMgr::addSource(validMySQLConnectionString()));
+ HostMgr::delSource("mysql");
} catch (const isc::Exception& ex) {
FAIL() << "*** ERROR: unable to open database, reason:\n"
<< " " << ex.what() << "\n"
try {
string connection_string = validMySQLConnectionString() + string(" ") +
string(VALID_TIMEOUT);
- HostDataSourceFactory::create(connection_string);
- EXPECT_NO_THROW((void) HostDataSourceFactory::getHostDataSourcePtr());
- HostDataSourceFactory::destroy();
+ HostMgr::create();
+ EXPECT_NO_THROW(HostMgr::addSource(connection_string));
+ HostMgr::delSource("mysql");
} catch (const isc::Exception& ex) {
FAIL() << "*** ERROR: unable to open database, reason:\n"
<< " " << ex.what() << "\n"
// Check that attempting to get an instance of the lease manager when
// none is set throws an exception.
- EXPECT_FALSE(HostDataSourceFactory::getHostDataSourcePtr());
+ EXPECT_FALSE(HostMgr::instance().getHostDataSource());
// Check that wrong specification of backend throws an exception.
// (This is really a check on LeaseMgrFactory, but is convenient to
// perform here.)
- EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ EXPECT_THROW(HostMgr::addSource(connectionString(
NULL, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
InvalidParameter);
- EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ EXPECT_THROW(HostMgr::addSource(connectionString(
INVALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
InvalidType);
// Check that invalid login data causes an exception.
- EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ EXPECT_THROW(HostMgr::addSource(connectionString(
MYSQL_VALID_TYPE, INVALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
DbOpenError);
- EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ EXPECT_THROW(HostMgr::addSource(connectionString(
MYSQL_VALID_TYPE, VALID_NAME, INVALID_HOST, VALID_USER, VALID_PASSWORD)),
DbOpenError);
- EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ EXPECT_THROW(HostMgr::addSource(connectionString(
MYSQL_VALID_TYPE, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
DbOpenError);
- EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ EXPECT_THROW(HostMgr::addSource(connectionString(
MYSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, INVALID_PASSWORD)),
DbOpenError);
- EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ EXPECT_THROW(HostMgr::addSource(connectionString(
MYSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_1)),
DbInvalidTimeout);
- EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ EXPECT_THROW(HostMgr::addSource(connectionString(
MYSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_2)),
DbInvalidTimeout);
- EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ EXPECT_THROW(HostMgr::addSource(connectionString(
MYSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD,
VALID_TIMEOUT, INVALID_READONLY_DB)), DbInvalidReadOnly);
// Check for missing parameters
- EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ EXPECT_THROW(HostMgr::addSource(connectionString(
MYSQL_VALID_TYPE, NULL, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
NoDatabaseName);
-// Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2016-2018 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
#include <dhcpsrv/pgsql_host_data_source.h>
#include <dhcpsrv/tests/generic_host_data_source_unittest.h>
#include <dhcpsrv/testutils/pgsql_schema.h>
+#include <dhcpsrv/host_mgr.h>
#include <dhcpsrv/host_data_source_factory.h>
#include <gtest/gtest.h>
// Connect to the database
try {
- HostDataSourceFactory::create(validPgSQLConnectionString());
+ HostMgr::create();
+ HostMgr::addSource(validPgSQLConnectionString());
} catch (...) {
std::cerr << "*** ERROR: unable to open database. The test\n"
"*** environment is broken and must be fixed before\n"
throw;
}
- hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr();
+ hdsptr_ = HostMgr::instance().getHostDataSource();
}
/// @brief Destructor
} catch (...) {
// Rollback may fail if backend is in read only mode. That's ok.
}
- HostDataSourceFactory::destroy();
+ HostMgr::delAllSources();
hdsptr_.reset();
destroyPgSQLSchema();
}
/// Parameter is ignored for PostgreSQL backend as the v4 and v6 leases
/// share the same database.
void reopen(Universe) {
- HostDataSourceFactory::destroy();
- HostDataSourceFactory::create(validPgSQLConnectionString());
- hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr();
+ HostMgr::create();
+ HostMgr::addSource(validPgSQLConnectionString());
+ hdsptr_ = HostMgr::instance().getHostDataSource();
}
/// @brief returns number of rows in a table
// Check that lease manager open the database opens correctly and tidy up.
// If it fails, print the error message.
try {
- HostDataSourceFactory::create(validPgSQLConnectionString());
- EXPECT_NO_THROW((void) HostDataSourceFactory::getHostDataSourcePtr());
- HostDataSourceFactory::destroy();
+ HostMgr::create();
+ EXPECT_NO_THROW(HostMgr::addSource(validPgSQLConnectionString()));
+ HostMgr::delSource("postgresql");
} catch (const isc::Exception& ex) {
FAIL() << "*** ERROR: unable to open database, reason:\n"
<< " " << ex.what() << "\n"
try {
string connection_string = validPgSQLConnectionString() + string(" ") +
string(VALID_TIMEOUT);
- HostDataSourceFactory::create(connection_string);
- EXPECT_NO_THROW((void) HostDataSourceFactory::getHostDataSourcePtr());
- HostDataSourceFactory::destroy();
+ EXPECT_NO_THROW(HostMgr::addSource(connection_string));
+ HostMgr::delSource("postgresql");
} catch (const isc::Exception& ex) {
FAIL() << "*** ERROR: unable to open database, reason:\n"
<< " " << ex.what() << "\n"
// Check that attempting to get an instance of the lease manager when
// none is set throws an exception.
- EXPECT_FALSE(HostDataSourceFactory::getHostDataSourcePtr());
+ EXPECT_FALSE(HostMgr::instance().getHostDataSource());
// Check that wrong specification of backend throws an exception.
// (This is really a check on LeaseMgrFactory, but is convenient to
// perform here.)
- EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ EXPECT_THROW(HostMgr::addSource(connectionString(
NULL, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
InvalidParameter);
- EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ EXPECT_THROW(HostMgr::addSource(connectionString(
INVALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
InvalidType);
// Check that invalid login data causes an exception.
- EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ EXPECT_THROW(HostMgr::addSource(connectionString(
PGSQL_VALID_TYPE, INVALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
DbOpenError);
- EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ EXPECT_THROW(HostMgr::addSource(connectionString(
PGSQL_VALID_TYPE, VALID_NAME, INVALID_HOST, VALID_USER, VALID_PASSWORD)),
DbOpenError);
- EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ EXPECT_THROW(HostMgr::addSource(connectionString(
PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
DbOpenError);
- EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ EXPECT_THROW(HostMgr::addSource(connectionString(
PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, INVALID_PASSWORD)),
DbOpenError);
- EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ EXPECT_THROW(HostMgr::addSource(connectionString(
PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_1)),
DbInvalidTimeout);
- EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ EXPECT_THROW(HostMgr::addSource(connectionString(
PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_2)),
DbInvalidTimeout);
// Check for missing parameters
- EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ EXPECT_THROW(HostMgr::addSource(connectionString(
PGSQL_VALID_TYPE, NULL, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
NoDatabaseName);