1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 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
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
// Copyright (C) 2013-2021 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 D_CFG_MGR_H
#define D_CFG_MGR_H

#include <cc/data.h>
#include <cc/cfg_to_element.h>
#include <cc/user_context.h>
#include <process/config_base.h>
#include <exceptions/exceptions.h>

#include <stdint.h><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include <functional><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <list><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <string><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.

namespace isc {
namespace process {

/// @brief Defines a map of ConstElementPtrs keyed by name
typedef std::map<std::string, isc::data::ConstElementPtr> ElementMap;

/// @brief Exception thrown if the configuration manager encounters an error.
class DCfgMgrBaseError : public isc::Exception {
public:
    DCfgMgrBaseError(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) { };
};

/// @brief Configuration Manager
///
/// DCfgMgrBase is an abstract class that provides the mechanisms for managing
/// an application's configuration.  This includes services for parsing sets of
/// configuration values, storing the parsed information in its converted form,
/// and retrieving the information on demand.  It is intended to be the worker
/// class which is handed a set of configuration values to process by upper
/// application management layers.
///
/// This class allows two configuration methods:
///
/// 1. classic method
///
/// The class presents a public method for receiving new configurations,
/// parseConfig.  This method coordinates the parsing effort as follows:
///
/// @code
///    make backup copy of configuration context
///    Split top-level configuration elements into to sets:
///      1. Set of scalar elements (strings, booleans, ints, etc..)
///      2. Set of object elements (maps, lists, etc...)
///    For each entry in the scalar set:
///        get derivation-specific parser for element
///        run parser
///        update context with parsed results
///        break on error
///
///    For each entry in the object set;
///        get derivation-specific parser for element
///        run parser
///        update context with parsed results
///        break on error
///
///    if an error occurred or this is only a check
///        restore configuration context from backup
/// @endcode
///
/// The above structuring ensures that global parameters are parsed first
/// making them available during subsequent object element parsing. The order
/// in which the object elements are processed is either:
///
///    1. Natural order presented by the configuration set
///    2. Specific order determined by a list of element ids
///
/// This allows a derivation to specify the order in which its elements are
/// parsed if there are dependencies between elements.
///
/// To parse a given element, its id along with the element itself,
/// is passed into the virtual method, @c parseElement. Derivations are
/// expected to converts the element into application specific object(s),
/// thereby isolating the CPL from application details.
///
/// In the event that an error occurs, parsing is halted and the
/// configuration context is restored from backup.
///
/// See @ref isc::d2::D2CfgMgr and @ref isc::d2::D2Process for example use of
/// this approach.
///
/// 2. simple configuration method
///
/// This approach assumes usage of @ref isc::data::SimpleParser paradigm. It
/// does not use any intermediate storage, does not use parser pointers, does
/// not enforce parsing order.
///
/// Here's the expected control flow order:
/// 1. implementation calls simpleParseConfig from its configure method.
/// 2. simpleParseConfig makes a configuration context
/// 3. parse method from the derived class is called
/// 4. if the configuration was unsuccessful or this is only a check, the
///    old context is reinstantiated. If not, the configuration is kept.
///
/// See @ref isc::agent::CtrlAgentCfgMgr and @ref isc::agent::CtrlAgentProcess
/// for example use of this approach.
class DCfgMgrBase {
public:
    /// @brief Constructor
    ///
    /// @param context is a pointer to the configuration context the manager
    /// will use for storing parsed results.
    ///
    /// @throw throws DCfgMgrBaseError if context is null
    DCfgMgrBase(ConfigPtr context);

    /// @brief Destructor
    virtual ~DCfgMgrBase();

    /// @brief Acts as the receiver of new configurations.
    ///
    /// This method is similar to what parseConfig did, execept it employs
    /// the simple parser paradigm: no intermediate storage, no parser pointers
    /// no distinction between params_map and objects_map, parse order (if needed)
    /// can be enforced in the actual implementation by calling specific
    /// parsers first. See @ref isc::agent::CtrlAgentCfgMgr::parse for example.
    ///
    /// If check_only is true, the actual parsing is done to check if the configuration
    /// is sane, but is then reverted.
    ///
    /// @param config set of configuration elements to be parsed
    /// @param check_only true if the config is to be checked only, but not applied
    /// @param post_config_cb Callback to be executed after the usual parsing stage.
    /// This can be specified as a C++ lambda which configures other parts of the
    /// system based on the parsed configuration information. The callback should
    /// throw an exception to signal an error. This method will catch this
    /// exception and place an exception string within the result returned.
    ///
    /// @return an Element that contains the results of configuration composed
    /// of an integer status value (0 means successful, non-zero means failure),
    /// and a string explanation of the outcome.
    isc::data::ConstElementPtr
    simpleParseConfig(isc::data::ConstElementPtr config,
                      bool check_only = false,
                      const std::function<void()>& post_config_cb = nullptr);

    /// @brief Fetches the configuration context.
    ///
    /// @return returns a pointer reference to the configuration context.
    ConfigPtr& getContext() {
        return (context_);
    }

    /// @brief Returns configuration summary in the textual format.
    ///
    /// This method returns the brief text describing the current configuration.
    /// It may be used for logging purposes, e.g. whn the new configuration is
    /// committed to notify a user about the changes in configuration.
    ///
    /// @param selection Bitfield which describes the parts of the configuration
    /// to be returned.
    ///
    /// @return Summary of the configuration in the textual format.
    virtual std::string getConfigSummary(const uint32_t selection) = 0;

    /// @brief Redact the configuration.
    ///
    /// This method replaces passwords and secrets by asterisks. By
    /// default it follows all subtrees at the exception of user
    /// contexts. Please derive the method to allow a reasonable
    /// performance by following only subtrees where the syntax allows
    /// the presence of passwords and secrets.
    ///
    /// @param config the Element tree structure that describes the configuration.
    /// @return unmodified config or a copy of the config where passwords were
    /// replaced by asterisks so can be safely logged to an unprivileged place.
    isc::data::ConstElementPtr
    redactConfig(isc::data::ConstElementPtr const& config) const;

protected:
    /// @brief Adds default values to the given config
    ///
    /// Provides derivations a means to add defaults to a configuration
    /// Element map prior to parsing it.
    ///
    /// @param mutable_config - configuration to which defaults should be added
    virtual void setCfgDefaults(isc::data::ElementPtr mutable_config);

    /// @brief Abstract factory which creates a context instance.
    ///
    /// This method is used at the beginning of configuration process to
    /// create a fresh, empty copy of the derivation-specific context. This
    /// new context will be populated during the configuration process
    /// and will replace the existing context provided the configuration
    /// process completes without error.
    ///
    /// @return Returns a ConfigPtr to the new context instance.
    virtual ConfigPtr createNewContext() = 0;

    /// @brief Replaces existing context with a new, empty context.
    void resetContext();

    /// @brief Update the current context.
    ///
    /// Replaces the existing context with the given context.
    /// @param context Pointer to the new context.
    /// @throw DCfgMgrBaseError if context is NULL.
    void setContext(ConfigPtr& context);

    /// @brief Parses actual configuration.
    ///
    /// This method is expected to be implemented in derived classes that employ
    /// SimpleParser paradigm (i.e. they call simpleParseConfig rather than
    /// parseConfig from their configure method).
    ///
    /// Implementations that do not employ this method may provide dummy
    /// implementation.
    ///
    /// @param config the Element tree structure that describes the configuration.
    /// @param check_only false for normal configuration, true when verifying only
    ///
    /// @return an Element that contains the results of configuration composed
    /// of an integer status value (0 means successful, non-zero means failure),
    /// and a string explanation of the outcome.
    virtual isc::data::ConstElementPtr parse(isc::data::ConstElementPtr config,
                                             bool check_only);

    /// @brief Return a list of all paths that contain passwords or secrets.
    ///
    /// Used in @ref isc::process::Daemon::redactConfig to only make copies and
    /// only redact configuration subtrees that contain passwords or secrets.
    ///
    /// This method needs to be overridden in each process that has a distinct
    /// configuration structure.
    ///
    /// @return the list of lists of sequential JSON map keys needed to reach
    /// the passwords and secrets.
    virtual std::list<std::list<std::string>> jsonPathsToRedact() const;

private:
    /// @brief Pointer to the configuration context instance.
    ConfigPtr context_;
};

/// @brief Defines a shared pointer to DCfgMgrBase.
typedef boost::shared_ptr<DCfgMgrBase> DCfgMgrBasePtr;

} // end of isc::process namespace
} // end of isc namespace

#endif // D_CFG_MGR_H