namespace isc {
namespace cb {
-/// @brief Server selector for associating objects in a database with
-/// specific servers.
-///
-/// Configuration information stored in the configuration backends can be
-/// associated with selected servers, all servers or no particular server.
-/// For example: a particular subnet definition in the database may be
-/// associated with one server or can be shared by multiple servers.
-/// In the latter case, a subnet may be associated with a subset of
-/// servers or all servers. An administrator may also add the
-/// configuration data into the database and do not associate this data
-/// with any patrticular server.
-///
-/// When fetching the configuration data from a databse or when storing
-/// data in the database there is a need to specify which servers this
-/// data is associated with. The @c ServerSelector class represents
-/// such associations.
-///
-/// It includes three modes of selection: UNASSIGNED, ALL and SUBSET and
-/// several factory functions making associations described above.
-///
-/// The @c ServerSelector class should be used in objects derived from
-/// @c BaseConfigBackendPool and in objects derived from
-/// @c BaseConfigBackend to indicate which servers the specific calls
-/// exposed by these objects refer to.
-class ServerSelector {
-public:
-
- /// @brief Type of the server selection.
- enum class Type {
- UNASSIGNED,
- ALL,
- SUBSET
- };
-
- /// @brief Factory returning "unassigned" server selector.
- static ServerSelector& UNASSIGNED() {
- static ServerSelector selector(Type::UNASSIGNED);
- return (selector);
- }
-
- /// @brief Factory returning "all servers" selector.
- static ServerSelector& ALL() {
- static ServerSelector selector(Type::ALL);
- return (selector);
- }
-
- /// @brief Factory returning selector of one server.
- ///
- /// @param server_tag tag of the single server to be selected.
- static ServerSelector& ONE(const std::string& server_tag) {
- static ServerSelector selector(server_tag);
- return (selector);
- }
-
- /// @brief Factory returning "multiple servers" selector.
- ///
- /// @param server_tags set of server tags to be selected.
- static ServerSelector& MULTIPLE(const std::set<std::string>& server_tags) {
- static ServerSelector selector(server_tags);
- return (selector);
- }
-
- /// @brief Returns type of the selector.
- Type getType() const {
- return (type_);
- }
-
- /// @brief Returns tags associated with the selector.
- ///
- /// @return server tags for mutliple selections and for one server,
- /// empty set for all servers and and unassigned.
- std::set<std::string> getTags() const {
- return (tags_);
- }
-
-private:
-
- /// @brief Constructor used for "unassigned" and "all" slection types.
- ///
- /// @param type selector type.
- explicit ServerSelector(const Type& type)
- : type_(type), tags_() {
- }
-
- /// @brief Constructor used for selecting a single server.
- ///
- /// @param server_tag tag of the server to be selected.
- explicit ServerSelector(const std::string& server_tag)
- : type_(Type::SUBSET), tags_() {
- tags_.insert(server_tag);
- }
-
- /// @brief Constructor used for selecting multiple servers.
- ///
- /// @param server_tags set of server tags.
- explicit ServerSelector(const std::set<std::string>& server_tags)
- : type_(Type::SUBSET), tags_(server_tags) {
- }
-
- /// @brief Selection type used.
- Type type_;
-
- /// @brief Holds tags of explicitly selected servers.
- std::set<std::string> tags_;
-};
-
/// @brief Base class for server specific configuration backends.
class BaseConfigBackend {
public:
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <config_backend/base_config_backend_pool.h>
-#include <exceptions/exceptions.h>
-#include <climits>
-#include <sstream>
-
-using namespace isc::data;
namespace isc {
namespace cb {
-BackendSelector::BackendSelector()
- : backend_type_(BackendSelector::Type::UNSPEC),
- host_(), port_(0) {
-}
-
-BackendSelector::BackendSelector(const Type& backend_type)
- : backend_type_(backend_type),
- host_(), port_(0) {
-}
-
-BackendSelector::BackendSelector(const std::string& host,
- const uint16_t port)
- : backend_type_(BackendSelector::Type::UNSPEC),
- host_(host), port_(port) {
- validate();
-}
-
-BackendSelector::BackendSelector(const data::ConstElementPtr& access_map)
- : backend_type_(BackendSelector::Type::UNSPEC),
- host_(), port_(0) {
- if (access_map->getType() != Element::map) {
- isc_throw(BadValue, "database access information must be a map");
- }
-
- ConstElementPtr t = access_map->get("type");
- if (t) {
- if (t->getType() != Element::string) {
- isc_throw(BadValue, "'type' parameter must be a string");
- }
- backend_type_ = stringToBackendType(t->stringValue());
- }
-
- ConstElementPtr h = access_map->get("host");
- if (h) {
- if (h->getType() != Element::string) {
- isc_throw(BadValue, "'host' parameter must be a string");
- }
- host_ = h->stringValue();
- }
-
- ConstElementPtr p = access_map->get("port");
- if (p) {
- if ((p->getType() != Element::integer) ||
- (p->intValue() < 0) ||
- (p->intValue() > std::numeric_limits<uint16_t>::max())) {
- isc_throw(BadValue, "'port' parameter must be a number in range from 0 "
- "to " << std::numeric_limits<uint16_t>::max());
- }
- port_ = static_cast<uint16_t>(p->intValue());
- }
-
- validate();
-}
-
-const BackendSelector&
-BackendSelector::BackendSelector::UNSPEC() {
- static BackendSelector selector;
- return (selector);
-}
-
-bool
-BackendSelector::amUnspecified() const {
- return ((backend_type_ == BackendSelector::Type::UNSPEC) &&
- (host_.empty()) &&
- (port_ == 0));
-}
-
-std::string
-BackendSelector::toText() const {
- std::ostringstream s;
- if (amUnspecified()) {
- s << "unspecified";
-
- } else {
- if (backend_type_ != BackendSelector::Type::UNSPEC) {
- s << "type=" << backendTypeToString(backend_type_) << ",";
- }
-
- if (!host_.empty()) {
- s << "host=" << host_ << ",";
-
- if (port_ > 0) {
- s << "port=" << port_ << ",";
- }
- }
- }
-
- std::string text = s.str();
- if ((!text.empty() && (text.back() == ','))) {
- text.pop_back();
- }
-
- return (text);
-}
-
-BackendSelector::Type
-BackendSelector::stringToBackendType(const std::string& type) {
- if (type == "mysql") {
- return (BackendSelector::Type::MYSQL);
-
- } else if (type == "pgsql") {
- return (BackendSelector::Type::PGSQL);
-
- } else if (type == "cql") {
- return (BackendSelector::Type::CQL);
-
- } else {
- isc_throw(BadValue, "unsupported configuration backend type '" << type << "'");
- }
-}
-
-std::string
-BackendSelector::backendTypeToString(const BackendSelector::Type& type) {
- switch (type) {
- case BackendSelector::Type::MYSQL:
- return ("mysql");
- case BackendSelector::Type::PGSQL:
- return ("pgsql");
- case BackendSelector::Type::CQL:
- return ("cql");
- default:
- ;
- }
-
- return (std::string());
-}
-
-void
-BackendSelector::validate() const {
- if ((port_ != 0) && (host_.empty())) {
- isc_throw(BadValue, "'host' must be specified along with 'port' parameter");
- }
-}
} // end of namespace isc::cb
#include <cc/data.h>
#include <config_backend/base_config_backend.h>
+#include <database/backend_selector.h>
#include <database/db_exceptions.h>
-#include <cstdint>
+#include <database/server_selector.h>
#include <functional>
#include <list>
#include <string>
namespace isc {
namespace cb {
-/// @brief Config Backend selector.
-///
-/// Each Kea server using database as a configuration respository
-/// may use multiple configuration backends simultaneously. The most
-/// typical case is to use a single configuration backend per server,
-/// but there are use cases when configuration information is distributed
-/// accross multiple database instances. In the future, there may be
-/// also caching mechanisms implemented, which will allow for storing
-/// results of certain database queries in memory.
-///
-/// From the server perspective, the most common use of the configuration
-/// backend is to fetch entire configuration information from the
-/// databases (upon startup) or fetch the latest updates to the
-/// configuration, e.g. new subnet added, DHCP option modified etc.
-/// In those cases, it is not so important from the server which backend
-/// this data come from. Therefore, the server would fetch this information
-/// from all available backends.
-///
-/// When the server administrator wants to insert some new data into
-/// the database, modify existing data or simply wants to check the
-/// contents of one of the database instance, he would specify which
-/// database backend he wants to direct queries to.
-///
-/// The @c BackendSelector class provides means to specify whether
-/// the queries should be directed to any backend (see server case
-/// above) or to a specific backend (data insertion case above).
-/// In addition, the @c BackendSelector allows for using various
-/// criteria for selecting a backend to use. Currently those criteria
-/// are: database type (e.g. mysql), database host and database port.
-/// In order to use a specific port, the database host must also be
-/// specified. Note that in a general case multiple backends of the
-/// same type can be used simultaneously, e.g. multiple MySQL backends.
-/// In that case, it may be necessary to specify host (and port) to
-/// issue a query to the right one.
-///
-/// The @c BackendSelector class may be extended in the future to provide
-/// additional backend selection criteria.
-class BackendSelector {
-public:
-
- /// @brief Supported database types.
- ///
- /// The @c UNSPEC indicates that the database type is not specified
- /// as selection criteria.
- enum class Type {
- MYSQL,
- PGSQL,
- CQL,
- UNSPEC
- };
-
- /// @brief Default constructor.
- ///
- /// It sets the selector to "unspecified". When this selector is used
- /// the backend pool will use "any" backend. This has a different meaning
- /// for each type of query. See the @c BaseConfigBackendPool for details.
- explicit BackendSelector();
-
- /// @brief Constructor specifying backend type as a selection criteria.
- ///
- /// @param backend_type Type of the backend to be selected.
- explicit BackendSelector(const Type& backend_type);
-
- /// @brief Constructor for specifying host and optionally port as a
- /// selection criteria.
- ///
- /// @param host Hostname to be used for selecting a backend.
- /// @param port Port number to be used for selecting a backend. This value
- /// is optional and is ignored when set to 0. It must be used on conjuction
- /// with hostname.
- explicit BackendSelector(const std::string& host, const uint16_t port = 0);
-
- /// @brief Constructor for selecting a backend using JSON access map.
- ///
- /// The provided access map must have the same structure as an element
- /// of the "config-databases" configuration parameter. However, it merely
- /// takes into account: "type", "host" and "port" parameters. In addition,
- /// these parameters are optional. The following are valid combinations:
- ///
- /// @code
- /// {
- /// "type": "mysql"
- /// }
- /// @endcode
- ///
- /// @code
- /// {
- /// "host": "somehost.example.org"
- /// }
- /// @endcode
- ///
- /// @code
- /// {
- /// "host": "somehost.example.org",
- /// "port": 1234
- /// }
- /// @endcode
- ///
- /// @code
- /// {
- /// "type": "mysql"
- /// "host": "somehost.example.org",
- /// }
- /// @endcode
- ///
- /// @code
- /// {
- /// "type": "mysql"
- /// "host": "somehost.example.org",
- /// "port": 1234
- /// }
- /// @endcode
- ///
- /// where "type" can be any of the supported backend types.
- ///
- /// This constructor is useful for creating backend selectors from the
- /// received control commands.
- ///
- /// @param access_map Access map as provided above.
- explicit BackendSelector(const data::ConstElementPtr& access_map);
-
- /// @brief Returns instance of the "unspecified" backend selector.
- static const BackendSelector& UNSPEC();
-
- /// @brief Checks if selector is "unspecified".
- ///
- /// @return true if backend type is @c UNSPEC, hostname is empty and
- /// port number 0, false otherwise.
- bool amUnspecified() const;
-
- /// @brief Returns backend type selected.
- Type getBackendType() const {
- return (backend_type_);
- }
-
- /// @brief Returns host selected.
- ///
- /// @return host if specified or empty string if host is not
- /// specified.
- std::string getBackendHost() const {
- return (host_);
- }
-
- /// @brief Returns port selected.
- ///
- /// @return port number of the selected backend or 0 if port number
- /// is not specified.
- uint16_t getBackendPort() const {
- return (port_);
- }
-
- /// @brief Returns selections as text.
- ///
- /// @return Collection of comma separated selections, e.g.
- /// "type=mysql,host=somehost.example.org,port=1234".
- std::string toText() const;
-
- /// @brief Converts string to backend type.
- ///
- /// @param type Backend type as string.
- static Type stringToBackendType(const std::string& type);
-
- /// @brief Converts backend type to string.
- ///
- /// @param type Backend type to be converted.
- static std::string backendTypeToString(const Type& type);
-
-
-private:
-
- /// @brief Checks if the specified selector is valid.
- ///
- /// It checks if the port number is specified in conjuction with
- /// host.
- /// @throw BadValue if selector validation fails.
- void validate() const;
-
- /// @brief Backend type selected.
- Type backend_type_;
-
- /// @brief Host selected.
- std::string host_;
-
- /// @brief Port number selected.
- uint16_t port_;
-};
/// @brief Base class for configuration backend pools.
///
/// was found.
template<typename PropertyType, typename... InputType>
void getPropertyPtrConst(PropertyType (ConfigBackendType::*MethodPointer)
- (const ServerSelector&, InputType...) const,
- const BackendSelector& selector,
- const ServerSelector& server_selector,
+ (const db::ServerSelector&, InputType...) const,
+ const db::BackendSelector& selector,
+ const db::ServerSelector& server_selector,
PropertyType& property,
InputType... input) const {
/// was found.
template<typename PropertyCollectionType, typename... InputType>
void getMultiplePropertiesConst(PropertyCollectionType (ConfigBackendType::*MethodPointer)
- (const ServerSelector&, InputType...) const,
- const BackendSelector& selector,
- const ServerSelector& server_selector,
+ (const db::ServerSelector&, InputType...) const,
+ const db::BackendSelector& selector,
+ const db::ServerSelector& server_selector,
PropertyCollectionType& properties,
InputType... input) const {
if (selector.amUnspecified()) {
/// was found.
template<typename PropertyCollectionType>
void getAllPropertiesConst(PropertyCollectionType (ConfigBackendType::*MethodPointer)
- (const ServerSelector&) const,
- const BackendSelector& selector,
- const ServerSelector& server_selector,
+ (const db::ServerSelector&) const,
+ const db::BackendSelector& selector,
+ const db::ServerSelector& server_selector,
PropertyCollectionType& properties) const {
if (selector.amUnspecified()) {
for (auto backend : backends_) {
/// were found.
template<typename... InputType>
void createUpdateDeleteProperty(void (ConfigBackendType::*MethodPointer)
- (const ServerSelector&, InputType...),
- const BackendSelector& selector,
- const ServerSelector& server_selector,
+ (const db::ServerSelector&, InputType...),
+ const db::BackendSelector& selector,
+ const db::ServerSelector& server_selector,
InputType... input) {
auto backends = selectBackends(selector);
if (backends.empty()) {
/// "unspecified" or there is no backend in the pool, an empty list is returned.
///
/// @param selector Selector for which matching backends should be selected.
- std::list<ConfigBackendTypePtr> selectBackends(const BackendSelector& selector) const {
+ std::list<ConfigBackendTypePtr>
+ selectBackends(const db::BackendSelector& selector) const {
std::list<ConfigBackendTypePtr> selected;
for (auto backend : backends_) {
// If backend type is specified and it is not matching,
// do not select this backend.
- if ((selector.getBackendType() != BackendSelector::Type::UNSPEC) &&
+ if ((selector.getBackendType() != db::BackendSelector::Type::UNSPEC) &&
(selector.getBackendType() !=
- BackendSelector::stringToBackendType(backend->getType()))) {
+ db::BackendSelector::stringToBackendType(backend->getType()))) {
continue;
}
TESTS += libcb_unittests
libcb_unittests_SOURCES = config_backend_mgr_unittest.cc
-libcb_unittests_SOURCES += config_backend_selector_unittest.cc
libcb_unittests_SOURCES += run_unittests.cc
-libcb_unittests_SOURCES += server_selector_unittest.cc
libcb_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
libcb_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
CLEANFILES = *.gcno *.gcda db_messages.h db_messages.cc s-messages
lib_LTLIBRARIES = libkea-database.la
-libkea_database_la_SOURCES = database_connection.cc database_connection.h
+libkea_database_la_SOURCES = backend_selector.cc backend_selector.h
+libkea_database_la_SOURCES += database_connection.cc database_connection.h
libkea_database_la_SOURCES += dbaccess_parser.h dbaccess_parser.cc
libkea_database_la_SOURCES += db_exceptions.h
libkea_database_la_SOURCES += db_log.cc db_log.h
+libkea_database_la_SOURCES += server_selector.h
nodist_libkea_database_la_SOURCES = db_messages.cc db_messages.h
# Specify the headers for copying into the installation directory tree.
libkea_database_includedir = $(pkgincludedir)/database
libkea_database_include_HEADERS = \
+ backend_selector.h \
database_connection.h \
db_exceptions.h \
db_log.h
--- /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 <database/backend_selector.h>
+#include <exceptions/exceptions.h>
+#include <climits>
+#include <sstream>
+
+using namespace isc::data;
+
+namespace isc {
+namespace db {
+
+BackendSelector::BackendSelector()
+ : backend_type_(BackendSelector::Type::UNSPEC),
+ host_(), port_(0) {
+}
+
+BackendSelector::BackendSelector(const Type& backend_type)
+ : backend_type_(backend_type),
+ host_(), port_(0) {
+}
+
+BackendSelector::BackendSelector(const std::string& host,
+ const uint16_t port)
+ : backend_type_(BackendSelector::Type::UNSPEC),
+ host_(host), port_(port) {
+ validate();
+}
+
+BackendSelector::BackendSelector(const data::ConstElementPtr& access_map)
+ : backend_type_(BackendSelector::Type::UNSPEC),
+ host_(), port_(0) {
+ if (access_map->getType() != Element::map) {
+ isc_throw(BadValue, "database access information must be a map");
+ }
+
+ ConstElementPtr t = access_map->get("type");
+ if (t) {
+ if (t->getType() != Element::string) {
+ isc_throw(BadValue, "'type' parameter must be a string");
+ }
+ backend_type_ = stringToBackendType(t->stringValue());
+ }
+
+ ConstElementPtr h = access_map->get("host");
+ if (h) {
+ if (h->getType() != Element::string) {
+ isc_throw(BadValue, "'host' parameter must be a string");
+ }
+ host_ = h->stringValue();
+ }
+
+ ConstElementPtr p = access_map->get("port");
+ if (p) {
+ if ((p->getType() != Element::integer) ||
+ (p->intValue() < 0) ||
+ (p->intValue() > std::numeric_limits<uint16_t>::max())) {
+ isc_throw(BadValue, "'port' parameter must be a number in range from 0 "
+ "to " << std::numeric_limits<uint16_t>::max());
+ }
+ port_ = static_cast<uint16_t>(p->intValue());
+ }
+
+ validate();
+}
+
+const BackendSelector&
+BackendSelector::BackendSelector::UNSPEC() {
+ static BackendSelector selector;
+ return (selector);
+}
+
+bool
+BackendSelector::amUnspecified() const {
+ return ((backend_type_ == BackendSelector::Type::UNSPEC) &&
+ (host_.empty()) &&
+ (port_ == 0));
+}
+
+std::string
+BackendSelector::toText() const {
+ std::ostringstream s;
+ if (amUnspecified()) {
+ s << "unspecified";
+
+ } else {
+ if (backend_type_ != BackendSelector::Type::UNSPEC) {
+ s << "type=" << backendTypeToString(backend_type_) << ",";
+ }
+
+ if (!host_.empty()) {
+ s << "host=" << host_ << ",";
+
+ if (port_ > 0) {
+ s << "port=" << port_ << ",";
+ }
+ }
+ }
+
+ std::string text = s.str();
+ if ((!text.empty() && (text.back() == ','))) {
+ text.pop_back();
+ }
+
+ return (text);
+}
+
+BackendSelector::Type
+BackendSelector::stringToBackendType(const std::string& type) {
+ if (type == "mysql") {
+ return (BackendSelector::Type::MYSQL);
+
+ } else if (type == "pgsql") {
+ return (BackendSelector::Type::PGSQL);
+
+ } else if (type == "cql") {
+ return (BackendSelector::Type::CQL);
+
+ } else {
+ isc_throw(BadValue, "unsupported configuration backend type '" << type << "'");
+ }
+}
+
+std::string
+BackendSelector::backendTypeToString(const BackendSelector::Type& type) {
+ switch (type) {
+ case BackendSelector::Type::MYSQL:
+ return ("mysql");
+ case BackendSelector::Type::PGSQL:
+ return ("pgsql");
+ case BackendSelector::Type::CQL:
+ return ("cql");
+ default:
+ ;
+ }
+
+ return (std::string());
+}
+
+void
+BackendSelector::validate() const {
+ if ((port_ != 0) && (host_.empty())) {
+ isc_throw(BadValue, "'host' must be specified along with 'port' parameter");
+ }
+}
+
+} // end of namespace isc::db
+} // end of namespace isc
--- /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/.
+
+#ifndef BACKEND_SELECTOR_H
+#define BACKEND_SELECTOR_H
+
+#include <cc/data.h>
+#include <cstdint>
+#include <string>
+
+namespace isc {
+namespace db {
+
+/// @brief Config Backend selector.
+///
+/// Each Kea server using database as a configuration respository
+/// may use multiple configuration backends simultaneously. The most
+/// typical case is to use a single configuration backend per server,
+/// but there are use cases when configuration information is distributed
+/// accross multiple database instances. In the future, there may be
+/// also caching mechanisms implemented, which will allow for storing
+/// results of certain database queries in memory.
+///
+/// From the server perspective, the most common use of the configuration
+/// backend is to fetch entire configuration information from the
+/// databases (upon startup) or fetch the latest updates to the
+/// configuration, e.g. new subnet added, DHCP option modified etc.
+/// In those cases, it is not so important from the server which backend
+/// this data come from. Therefore, the server would fetch this information
+/// from all available backends.
+///
+/// When the server administrator wants to insert some new data into
+/// the database, modify existing data or simply wants to check the
+/// contents of one of the database instance, he would specify which
+/// database backend he wants to direct queries to.
+///
+/// The @c BackendSelector class provides means to specify whether
+/// the queries should be directed to any backend (see server case
+/// above) or to a specific backend (data insertion case above).
+/// In addition, the @c BackendSelector allows for using various
+/// criteria for selecting a backend to use. Currently those criteria
+/// are: database type (e.g. mysql), database host and database port.
+/// In order to use a specific port, the database host must also be
+/// specified. Note that in a general case multiple backends of the
+/// same type can be used simultaneously, e.g. multiple MySQL backends.
+/// In that case, it may be necessary to specify host (and port) to
+/// issue a query to the right one.
+///
+/// The @c BackendSelector class may be extended in the future to provide
+/// additional backend selection criteria.
+class BackendSelector {
+public:
+
+ /// @brief Supported database types.
+ ///
+ /// The @c UNSPEC indicates that the database type is not specified
+ /// as selection criteria.
+ enum class Type {
+ MYSQL,
+ PGSQL,
+ CQL,
+ UNSPEC
+ };
+
+ /// @brief Default constructor.
+ ///
+ /// It sets the selector to "unspecified". When this selector is used
+ /// the backend pool will use "any" backend. This has a different meaning
+ /// for each type of query. See the @c BaseConfigBackendPool for details.
+ explicit BackendSelector();
+
+ /// @brief Constructor specifying backend type as a selection criteria.
+ ///
+ /// @param backend_type Type of the backend to be selected.
+ explicit BackendSelector(const Type& backend_type);
+
+ /// @brief Constructor for specifying host and optionally port as a
+ /// selection criteria.
+ ///
+ /// @param host Hostname to be used for selecting a backend.
+ /// @param port Port number to be used for selecting a backend. This value
+ /// is optional and is ignored when set to 0. It must be used on conjuction
+ /// with hostname.
+ explicit BackendSelector(const std::string& host, const uint16_t port = 0);
+
+ /// @brief Constructor for selecting a backend using JSON access map.
+ ///
+ /// The provided access map must have the same structure as an element
+ /// of the "config-databases" configuration parameter. However, it merely
+ /// takes into account: "type", "host" and "port" parameters. In addition,
+ /// these parameters are optional. The following are valid combinations:
+ ///
+ /// @code
+ /// {
+ /// "type": "mysql"
+ /// }
+ /// @endcode
+ ///
+ /// @code
+ /// {
+ /// "host": "somehost.example.org"
+ /// }
+ /// @endcode
+ ///
+ /// @code
+ /// {
+ /// "host": "somehost.example.org",
+ /// "port": 1234
+ /// }
+ /// @endcode
+ ///
+ /// @code
+ /// {
+ /// "type": "mysql"
+ /// "host": "somehost.example.org",
+ /// }
+ /// @endcode
+ ///
+ /// @code
+ /// {
+ /// "type": "mysql"
+ /// "host": "somehost.example.org",
+ /// "port": 1234
+ /// }
+ /// @endcode
+ ///
+ /// where "type" can be any of the supported backend types.
+ ///
+ /// This constructor is useful for creating backend selectors from the
+ /// received control commands.
+ ///
+ /// @param access_map Access map as provided above.
+ explicit BackendSelector(const data::ConstElementPtr& access_map);
+
+ /// @brief Returns instance of the "unspecified" backend selector.
+ static const BackendSelector& UNSPEC();
+
+ /// @brief Checks if selector is "unspecified".
+ ///
+ /// @return true if backend type is @c UNSPEC, hostname is empty and
+ /// port number 0, false otherwise.
+ bool amUnspecified() const;
+
+ /// @brief Returns backend type selected.
+ Type getBackendType() const {
+ return (backend_type_);
+ }
+
+ /// @brief Returns host selected.
+ ///
+ /// @return host if specified or empty string if host is not
+ /// specified.
+ std::string getBackendHost() const {
+ return (host_);
+ }
+
+ /// @brief Returns port selected.
+ ///
+ /// @return port number of the selected backend or 0 if port number
+ /// is not specified.
+ uint16_t getBackendPort() const {
+ return (port_);
+ }
+
+ /// @brief Returns selections as text.
+ ///
+ /// @return Collection of comma separated selections, e.g.
+ /// "type=mysql,host=somehost.example.org,port=1234".
+ std::string toText() const;
+
+ /// @brief Converts string to backend type.
+ ///
+ /// @param type Backend type as string.
+ static Type stringToBackendType(const std::string& type);
+
+ /// @brief Converts backend type to string.
+ ///
+ /// @param type Backend type to be converted.
+ static std::string backendTypeToString(const Type& type);
+
+
+private:
+
+ /// @brief Checks if the specified selector is valid.
+ ///
+ /// It checks if the port number is specified in conjuction with
+ /// host.
+ /// @throw BadValue if selector validation fails.
+ void validate() const;
+
+ /// @brief Backend type selected.
+ Type backend_type_;
+
+ /// @brief Host selected.
+ std::string host_;
+
+ /// @brief Port number selected.
+ uint16_t port_;
+};
+
+
+} // end of namespace isc::db
+} // end of namespace isc
+
+#endif
--- /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/.
+
+#ifndef SERVER_SELECTOR_H
+#define SERVER_SELECTOR_H
+
+#include <set>
+#include <string>
+
+namespace isc {
+namespace db {
+
+/// @brief Server selector for associating objects in a database with
+/// specific servers.
+///
+/// Configuration information stored in the configuration backends can be
+/// associated with selected servers, all servers or no particular server.
+/// For example: a particular subnet definition in the database may be
+/// associated with one server or can be shared by multiple servers.
+/// In the latter case, a subnet may be associated with a subset of
+/// servers or all servers. An administrator may also add the
+/// configuration data into the database and do not associate this data
+/// with any patrticular server.
+///
+/// When fetching the configuration data from a databse or when storing
+/// data in the database there is a need to specify which servers this
+/// data is associated with. The @c ServerSelector class represents
+/// such associations.
+///
+/// It includes three modes of selection: UNASSIGNED, ALL and SUBSET and
+/// several factory functions making associations described above.
+///
+/// The @c ServerSelector class should be used in objects derived from
+/// @c BaseConfigBackendPool and in objects derived from
+/// @c BaseConfigBackend to indicate which servers the specific calls
+/// exposed by these objects refer to.
+class ServerSelector {
+public:
+
+ /// @brief Type of the server selection.
+ enum class Type {
+ UNASSIGNED,
+ ALL,
+ SUBSET
+ };
+
+ /// @brief Factory returning "unassigned" server selector.
+ static ServerSelector& UNASSIGNED() {
+ static ServerSelector selector(Type::UNASSIGNED);
+ return (selector);
+ }
+
+ /// @brief Factory returning "all servers" selector.
+ static ServerSelector& ALL() {
+ static ServerSelector selector(Type::ALL);
+ return (selector);
+ }
+
+ /// @brief Factory returning selector of one server.
+ ///
+ /// @param server_tag tag of the single server to be selected.
+ static ServerSelector& ONE(const std::string& server_tag) {
+ static ServerSelector selector(server_tag);
+ return (selector);
+ }
+
+ /// @brief Factory returning "multiple servers" selector.
+ ///
+ /// @param server_tags set of server tags to be selected.
+ static ServerSelector& MULTIPLE(const std::set<std::string>& server_tags) {
+ static ServerSelector selector(server_tags);
+ return (selector);
+ }
+
+ /// @brief Returns type of the selector.
+ Type getType() const {
+ return (type_);
+ }
+
+ /// @brief Returns tags associated with the selector.
+ ///
+ /// @return server tags for mutliple selections and for one server,
+ /// empty set for all servers and and unassigned.
+ std::set<std::string> getTags() const {
+ return (tags_);
+ }
+
+private:
+
+ /// @brief Constructor used for "unassigned" and "all" slection types.
+ ///
+ /// @param type selector type.
+ explicit ServerSelector(const Type& type)
+ : type_(type), tags_() {
+ }
+
+ /// @brief Constructor used for selecting a single server.
+ ///
+ /// @param server_tag tag of the server to be selected.
+ explicit ServerSelector(const std::string& server_tag)
+ : type_(Type::SUBSET), tags_() {
+ tags_.insert(server_tag);
+ }
+
+ /// @brief Constructor used for selecting multiple servers.
+ ///
+ /// @param server_tags set of server tags.
+ explicit ServerSelector(const std::set<std::string>& server_tags)
+ : type_(Type::SUBSET), tags_(server_tags) {
+ }
+
+ /// @brief Selection type used.
+ Type type_;
+
+ /// @brief Holds tags of explicitly selected servers.
+ std::set<std::string> tags_;
+};
+
+
+} // end of namespace isc::db
+} // end of namespace isc
+
+#endif
if HAVE_GTEST
TESTS += libdatabase_unittests
-libdatabase_unittests_SOURCES = database_connection_unittest.cc
+libdatabase_unittests_SOURCES = backend_selector_unittest.cc
+libdatabase_unittests_SOURCES += database_connection_unittest.cc
libdatabase_unittests_SOURCES += dbaccess_parser_unittest.cc
libdatabase_unittests_SOURCES += run_unittests.cc
+libdatabase_unittests_SOURCES += server_selector_unittest.cc
libdatabase_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
libdatabase_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
#include <config.h>
-#include <config_backend/base_config_backend_pool.h>
+#include <database/backend_selector.h>
#include <boost/scoped_ptr.hpp>
#include <gtest/gtest.h>
using namespace isc;
-using namespace isc::cb;
+using namespace isc::db;
using namespace isc::data;
namespace {
+// Verifies defaults of the backend selector.
TEST(BackendSelectorTest, defaults) {
BackendSelector sel;
EXPECT_EQ(BackendSelector::Type::UNSPEC, sel.getBackendType());
EXPECT_EQ("unspecified", sel.toText());
}
+// Verifies that the backend selector can be set to "unspecified".
TEST(BackendSelectorTest, unspec) {
BackendSelector sel = BackendSelector::UNSPEC();
EXPECT_EQ(BackendSelector::Type::UNSPEC, sel.getBackendType());
EXPECT_EQ("unspecified", sel.toText());
}
+// Verifies that it is possible to select backend by type.
TEST(BackendSelectorTest, backendTypeSpec) {
boost::scoped_ptr<BackendSelector> sel;
ASSERT_NO_THROW(
EXPECT_EQ("type=mysql", sel->toText());
}
+// Verifies that backend can be selected by host and port.
TEST(BackendSelectorTest, backendHostPortSpec) {
boost::scoped_ptr<BackendSelector> sel;
ASSERT_NO_THROW(
EXPECT_EQ("host=myhost,port=1234", sel->toText());
}
+// Verifies that backend can be selected by host.
TEST(BackendSelectorTest, backendHostSpec) {
boost::scoped_ptr<BackendSelector> sel;
ASSERT_NO_THROW(
EXPECT_EQ("host=otherhost", sel->toText());
}
+// Verifies that backend becomes unspecified if the access
+// map is empty.
TEST(BackendSelectorTest, accessMapTypeUnSpec) {
ElementPtr access_map = Element::createMap();
boost::scoped_ptr<BackendSelector> sel;
EXPECT_EQ("unspecified", sel->toText());
}
+// Verifies that backend can be selected by type using access map.
TEST(BackendSelectorTest, accessMapTypeSpec) {
ElementPtr access_map = Element::createMap();
access_map->set("type", Element::create("mysql"));
EXPECT_EQ("type=mysql", sel->toText());
}
+// Verifies that backend can be selected by host and port using
+// access map.
TEST(BackendSelectorTest, accessMapHostPortSpec) {
ElementPtr access_map = Element::createMap();
access_map->set("host", Element::create("myhost"));
EXPECT_EQ("host=myhost,port=1234", sel->toText());
}
+// Verifies that the backend can be selected by host using access
+// map.
TEST(BackendSelectorTest, accessMapHostSpec) {
ElementPtr access_map = Element::createMap();
access_map->set("host", Element::create("myhost"));
EXPECT_EQ("host=myhost", sel->toText());
}
+// Verifies that selecting backend by port only is not possible.
TEST(BackendSelectorTest, accessMapPortSpec) {
ElementPtr access_map = Element::createMap();
access_map->set("port", Element::create(int64_t(1234)));
BadValue);
}
+// Tests conversions of strings to backend types.
TEST(BackendSelectorTest, stringToBackendType) {
EXPECT_EQ(BackendSelector::Type::MYSQL,
BackendSelector::stringToBackendType("mysql"));
BadValue);
}
+// Tests conversions of backend types to strings.
TEST(BackendSelectorTest, backendTypeToString) {
EXPECT_EQ("mysql",
BackendSelector::backendTypeToString(BackendSelector::Type::MYSQL));
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <config.h>
-#include <config_backend/base_config_backend.h>
+#include <database/server_selector.h>
#include <gtest/gtest.h>
-using namespace isc::cb;
+using namespace isc::db;
namespace {