base_config_backend_mgr.h 6.96 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// 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 BASE_CONFIG_BACKEND_MGR_H
#define BASE_CONFIG_BACKEND_MGR_H

#include <config_backend/base_config_backend.h>
11
#include <database/database_connection.h>
12 13 14 15 16 17 18 19 20
#include <exceptions/exceptions.h>
#include <boost/shared_ptr.hpp>
#include <functional>
#include <map>
#include <string>

namespace isc {
namespace cb {

21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
/// @brief Base class for Configuration Backend Managers (CBM).
///
/// Each Kea server supporting Configuration Backend feature implements
/// a "manager" class which holds information about supported and
/// configured backends and provides access to the backends. This is
/// similar to @c HostMgr and @c LeaseMgr singletons being used by the
/// DHCP servers.
///
/// The Config Backend Managers are typically implemented as singletons
/// which can be accessed from any place within the server code. This
/// includes server configuration, data fetching during normal server
/// operation and data management, including processing of control
/// commands implemented within hooks libraries.
///
/// The @c BaseConfigBackendMgr is a base class for all CBMs implemented
/// for respective Kea servers. It includes mechanisms to register config
/// backend factory functions and to create instances of the backends using
/// those factory functions as a result of server configuration. The mechanism
/// of factory functions registration is useful in cases when the config
/// backend is implemented within the hook library. Such hook library
/// registers factory function in its @c load function and the server
/// simply calls this function to create the instance of this backend when
/// instructed to do so via configuration. Similar mechanism exists in
/// DHCP @c HostMgr.
///
/// Unlike @c HostMgr, the CBMs do not directly expose API to fetch and
/// manipulate the data in the database. This is done via, so called,
/// Configuration Backends Pools. See @c BaseConfigBackendPool for
/// details. The @c BaseConfigBackendMgr is provided with the pool type
/// via class template parameter. Respective CBM implementations
/// use their own pools, which provide APIs appropriate for those
/// implementation.
///
/// @tparam ConfgBackendPoolType Type of the configuration backend pool
/// to be used by the manager. It must derive from @c BaseConfigBackendPool
/// template class.
57 58 59 60
template<typename ConfigBackendPoolType>
class BaseConfigBackendMgr {
public:

61
    /// @brief Pointer to the configuration backend pool.
62 63
    typedef boost::shared_ptr<ConfigBackendPoolType> ConfigBackendPoolPtr;

64 65 66 67
    /// @brief Type of the backend factory function.
    ///
    /// Factory function returns a pointer to the instance of the configuration
    /// backend created.
68 69 70
    typedef std::function<typename ConfigBackendPoolType::ConfigBackendTypePtr
                          (const db::DatabaseConnection::ParameterMap&)> Factory;

71
    /// @brief Constructor.
72
    BaseConfigBackendMgr()
73
        : factories_(), pool_(new ConfigBackendPoolType()) {
74 75
    }

76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
    /// @brief Registers new backend factory function for a given backend type.
    ///
    /// The typical usage of this function is to make the CBM aware of a
    /// configuration backend implementation. This implementation may exist
    /// in a hooks library. In such case, this function should be called from
    /// the @c load function in this library. When the backend is registered,
    /// the server will use it when required by the configuration, i.e. a
    /// user includes configuration backend of that type in the
    /// "config-databases" list.
    ///
    /// If the backend of the given type has already been registered, perhaps
    /// by another hooks library, the CBM will refuse to register another
    /// backend of the same type.
    ///
    /// @param db_type Backend type, e.g. "mysql".
    /// @param factory Pointer to the backend factory function.
    ///
    /// @return true if the backend has been successfully registered, false
    /// if another backend of this type already exists.
95 96
    bool registerBackendFactory(const std::string& db_type,
                                const Factory& factory) {
97
        // Check if this backend has been already registered.
98 99 100 101
        if (factories_.count(db_type)) {
            return (false);
        }

102
        // Register the new backend.
103 104 105 106
        factories_.insert(std::make_pair(db_type, factory));
        return (true);
    }

107 108 109 110 111 112 113 114 115 116 117 118 119 120
    /// @brief Create an instance of a configuration backend.
    ///
    /// This method uses provided @c dbaccess string representing database
    /// connection information to create an instance of the database
    /// backend. If the specified backend type is not supported, i.e. there
    /// is no relevant factory function registered, an exception is thrown.
    ///
    /// @param dbaccess Database access string being a collection of
    /// key=value pairs.
    ///
    /// @throw InvalidParameter if access string lacks database type value.
    /// @throw db::InvalidType if the type of the database backend is not
    /// supported.
    /// @throw Unexpected if the backend factory function returned NULL.
121
    void addBackend(const std::string& dbaccess) {
122
        // Parse the access string into a map of parameters.
123 124 125
        db::DatabaseConnection::ParameterMap parameters =
            db::DatabaseConnection::parse(dbaccess);

126
        // Get the database type to locate a factory function.
127 128
        db::DatabaseConnection::ParameterMap::iterator it = parameters.find("type");
        if (it == parameters.end()) {
129 130
            isc_throw(InvalidParameter, "Config backend specification lacks the "
                      "'type' keyword");
131 132 133 134 135 136 137
        }

        std::string db_type = it->second;
        auto index = factories_.find(db_type);

        // No match?
        if (index == factories_.end()) {
138 139
            isc_throw(db::InvalidType, "The type of the configuration backend: '" <<
                      db_type << "' is not supported");
140 141 142 143 144 145 146 147 148
    }

        // Call the factory and push the pointer on sources.
        auto backend = index->second(parameters);
        if (!backend) {
            isc_throw(Unexpected, "Config database " << db_type <<
                      " factory returned NULL");
        }

149 150
        // Backend instance created successfully.
        pool_->addBackend(backend);
151 152
    }

153
    /// @brief Removes all backends from the pool.
154
    void delAllBackends() {
155
        pool_->delAllBackends();
156 157
    }

158
    /// @brief Returns underlying config backend pool.
159
    ConfigBackendPoolPtr getPool() const {
160
        return (pool_);
161 162 163 164
    }

protected:

165
    /// @brief A map holding registered backend factory functions.
166 167
    std::map<std::string, Factory> factories_;

168 169
    /// @brief Pointer to the configuration backends pool.
    ConfigBackendPoolPtr pool_;
170 171 172 173 174 175
};

} // end of namespace isc::cb
} // end of namespace isc

#endif // BASE_CONFIG_BACKEND_MGR_H