d_cfg_mgr.h 19.5 KB
Newer Older
Francis Dupont's avatar
Francis Dupont committed
1
// Copyright (C) 2013-2017 Internet Systems Consortium, Inc. ("ISC")
2
//
3
4
5
// 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/.
6

7
8
9
#ifndef D_CFG_MGR_H
#define D_CFG_MGR_H

10
#include <cc/data.h>
11
#include <cc/cfg_to_element.h>
12
#include <exceptions/exceptions.h>
13
#include <dhcpsrv/parsers/dhcp_parsers.h>
14
#include <functional>
15
16
17
18

#include <stdint.h>
#include <string>

19
20
21
22
23
24
25
// Undefine the macro OPTIONAL which is defined in some operating
// systems but conflicts with class constant is the context base class.

#ifdef OPTIONAL
#undef OPTIONAL
#endif

26
namespace isc {
27
namespace process {
28

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

32
33
34
35
36
37
38
/// @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) { };
};

39
40
41
42
class DCfgContextBase;
/// @brief Pointer to a configuration context.
typedef boost::shared_ptr<DCfgContextBase> DCfgContextBasePtr;

43
44
45
46
47
48
49
50
/// @brief Abstract class that implements a container for configuration context.
/// It provides a single enclosure for the storage of configuration parameters
/// and any other context specific information that needs to be accessible
/// during configuration parsing as well as to the application as a whole.
/// The base class supports storage for a small set of simple data types.
/// Derivations simply add additional storage as needed.  Note that this class
/// declares the pure virtual clone() method, its copy constructor is protected,
/// and its copy operator is inaccessible.  Derivations must supply an
51
52
53
/// implementation of clone that calls the base class copy constructor.
/// This allows the management class to perform context backup and restoration
/// without derivation specific knowledge using logic like
54
55
56
57
58
59
60
61
/// the following:
///
///    // Make a backup copy
///    DCfgContextBasePtr backup_copy(context_->clone());
///    :
///    // Restore from backup
///    context_ = backup_copy;
///
62
class DCfgContextBase : public isc::data::CfgToElement {
63
public:
64
    /// @brief Indicator that a configuration parameter is optional.
65
66
    static const bool OPTIONAL = true;
    static const bool REQUIRED = false;
67

68
69
70
71
72
73
74
75
76
77
78
79
    /// @brief Constructor
    DCfgContextBase();

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

    /// @brief Fetches the value for a given boolean configuration parameter
    /// from the context.
    ///
    /// @param name is the name of the parameter to retrieve.
    /// @param value is an output parameter in which to return the retrieved
    /// value.
80
81
82
83
    /// @param optional if true, the parameter is optional and the method
    /// will not throw if the parameter is not found in the context. The
    /// contents of the output parameter, value, will not be altered.
    /// It defaults to false if not specified.
84
85
86
87
    ///
    /// @return The parameter's element's position information if found,
    /// otherwise it returns isc::data::Element::ZERO_POSITION().
    ///
88
    /// @throw throws DhcpConfigError if the context does not contain the
89
    /// parameter and optional is false.
90
91
    const data::Element::Position&
    getParam(const std::string& name, bool& value, bool optional=false);
92
93
94
95
96
97
98

    /// @brief Fetches the value for a given uint32_t configuration parameter
    /// from the context.
    ///
    /// @param name is the name of the parameter to retrieve.
    /// @param value is an output parameter in which to return the retrieved
    /// value.
99
100
101
    /// @param optional if true, the parameter is optional and the method
    /// will not throw if the parameter is not found in the context. The
    /// contents of the output parameter, value, will not be altered.
102
103
104
105
    ///
    /// @return The parameter's element's position information if found,
    /// otherwise it returns isc::data::Element::ZERO_POSITION().
    ///
106
    /// @throw throws DhcpConfigError if the context does not contain the
107
    /// parameter and optional is false.
108
109
    const data::Element::Position&
    getParam(const std::string& name, uint32_t& value,
110
                 bool optional=false);
111
112
113
114
115
116
117

    /// @brief Fetches the value for a given string configuration parameter
    /// from the context.
    ///
    /// @param name is the name of the parameter to retrieve.
    /// @param value is an output parameter in which to return the retrieved
    /// value.
118
119
120
    /// @param optional if true, the parameter is optional and the method
    /// will not throw if the parameter is not found in the context. The
    /// contents of the output parameter, value, will not be altered.
121
122
123
124
    ///
    /// @return The parameter's element's position information if found,
    /// otherwise it returns isc::data::Element::ZERO_POSITION().
    ///
125
    /// @throw throws DhcpConfigError if the context does not contain the
126
    /// parameter and optional is false.
127
128
    const data::Element::Position&
    getParam(const std::string& name, std::string& value,
129
                  bool optional=false);
130
131
132
133
134

    /// @brief Fetches the Boolean Storage. Typically used for passing
    /// into parsers.
    ///
    /// @return returns a pointer to the Boolean Storage.
135
    isc::dhcp::BooleanStoragePtr getBooleanStorage() {
136
137
138
139
140
141
142
        return (boolean_values_);
    }

    /// @brief Fetches the uint32 Storage. Typically used for passing
    /// into parsers.
    ///
    /// @return returns a pointer to the uint32 Storage.
143
    isc::dhcp::Uint32StoragePtr getUint32Storage() {
144
145
146
147
148
149
150
        return (uint32_values_);
    }

    /// @brief Fetches the string Storage. Typically used for passing
    /// into parsers.
    ///
    /// @return returns a pointer to the string Storage.
151
    isc::dhcp::StringStoragePtr getStringStorage() {
152
153
154
        return (string_values_);
    }

155
    /// @brief Creates a clone of this context object.
156
    ///
157
158
159
160
161
162
    /// As mentioned in the the class brief, derivation must supply an
    /// implementation that initializes the base class storage as well as its
    /// own.  Typically the derivation's clone method would return the result
    /// of passing  "*this" into its own copy constructor:
    ///
    /// @code
163
164
165
166
    /// class DStubContext : public DCfgContextBase {
    /// public:
    ///  :
    ///     // Clone calls its own copy constructor
167
168
    ///     virtual DCfgContextBasePtr clone() {
    ///         return (DCfgContextBasePtr(new DStubContext(*this)));
169
170
171
172
173
174
175
176
177
178
179
    ///     }
    ///
    ///     // Note that the copy constructor calls the base class copy ctor
    ///     // then initializes its additional storage.
    ///     DStubContext(const DStubContext& rhs) : DCfgContextBase(rhs),
    ///         extra_values_(new Uint32Storage(*(rhs.extra_values_))) {
    ///     }
    ///  :
    ///    // Here's the derivation's additional storage.
    ///    isc::dhcp::Uint32StoragePtr extra_values_;
    ///  :
180
    /// @endcode
181
    ///
182
183
    /// @return returns a pointer to the new clone.
    virtual DCfgContextBasePtr clone() = 0;
184

Tomek Mrugalski's avatar
Tomek Mrugalski committed
185
    /// @brief Unparse a configuration object
186
    ///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
187
    /// Returns an element which must parse into the same object, i.e.
188
189
190
191
192
193
194
195
    /// @code
    /// for all valid config C parse(parse(C)->toElement()) == parse(C)
    /// @endcode
    ///
    /// @return a pointer to a configuration which can be parsed into
    /// the initial configuration object
    virtual isc::data::ElementPtr toElement() const = 0;

196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
protected:
    /// @brief Copy constructor for use by derivations in clone().
    DCfgContextBase(const DCfgContextBase& rhs);

private:
    /// @brief Private assignment operator to avoid potential for slicing.
    DCfgContextBase& operator=(const DCfgContextBase& rhs);

    /// @brief Storage for boolean parameters.
    isc::dhcp::BooleanStoragePtr boolean_values_;

    /// @brief Storage for uint32 parameters.
    isc::dhcp::Uint32StoragePtr uint32_values_;

    /// @brief Storage for string parameters.
    isc::dhcp::StringStoragePtr string_values_;
};

214
/// @brief Defines a sequence of Element IDs used to specify a parsing order.
215
216
typedef std::vector<std::string> ElementIdList;

217
218
219
220
221
222
223
/// @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
224
/// application management layers.
225
///
226
227
228
229
/// This class allows two configuration methods:
///
/// 1. classic method
///
230
231
232
/// The class presents a public method for receiving new configurations,
/// parseConfig.  This method coordinates the parsing effort as follows:
///
233
/// @code
234
///    make backup copy of configuration context
235
236
237
238
239
240
241
242
243
244
///    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;
245
246
247
248
249
///        get derivation-specific parser for element
///        run parser
///        update context with parsed results
///        break on error
///
250
///    if an error occurred or this is only a check
251
///        restore configuration context from backup
252
/// @endcode
253
///
254
255
256
/// 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:
257
258
259
260
261
262
///
///    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.
263
///
264
265
266
267
/// 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.
268
269
270
///
/// In the event that an error occurs, parsing is halted and the
/// configuration context is restored from backup.
271
272
273
274
275
276
277
278
279
280
281
282
283
284
///
/// 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
285
/// 4. if the configuration was unsuccessful or this is only a check, the
286
287
288
289
///    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.
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
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(DCfgContextBasePtr context);

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

    /// @brief Acts as the receiver of new configurations and coordinates
    /// the parsing as described in the class brief.
    ///
306
    /// @param config_set is a set of configuration elements to be parsed.
307
    /// @param check_only true if the config is to be checked only, but not applied
308
309
310
311
    ///
    /// @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.
312
313
314
    isc::data::ConstElementPtr
    parseConfig(isc::data::ConstElementPtr config_set,
                bool check_only = false);
315

316
317
318
319
320
321
322
323
324
325
326
327
328
329

    /// @brief Acts as the receiver of new configurations.
    ///
    /// This method is similar to what @ref parseConfig does, 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
330
331
332
333
334
335
    /// @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.
    ///
336
337
338
339
340
    /// @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,
341
342
                      bool check_only = false,
                      const std::function<void()>& post_config_cb = nullptr);
343

344
    /// @brief Adds a given element id to the end of the parse order list.
345
    ///
346
347
348
349
    /// The order in which object elements are retrieved from this is the
    /// order in which they are added to the list. Derivations should use this
    /// method to populate the parse order as part of their constructor.
    /// Scalar parameters should NOT be included in this list.
350
    ///
351
352
    /// @param element_id is the string name of the element as it will appear
    /// in the configuration set.
353
    void addToParseOrder(const std::string& element_id){
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
        parse_order_.push_back(element_id);
    }

    /// @brief Fetches the parse order list.
    ///
    /// @return returns a const reference to the list.
    const ElementIdList& getParseOrder() const {
        return (parse_order_);
    }

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

371
372
373
374
375
376
377
378
379
380
    /// @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.
381
    virtual std::string getConfigSummary(const uint32_t selection) = 0;
382

383
protected:
384
385
    /// @brief Adds default values to the given config
    ///
Josh Soref's avatar
Josh Soref committed
386
    /// Provides derivations a means to add defaults to a configuration
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
    /// 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 Parses an individual element
    ///
    /// Each element to be parsed is passed into this method to be converted
    /// into the requisite application object(s).
    ///
    /// @param element_id name of the element as it is expected in the cfg
    /// @param element value of the element as ElementPtr
    ///
    virtual void parseElement(const std::string& element_id,
                              isc::data::ConstElementPtr element);

403
404
405
406
    /// @brief Parses a set of scalar configuration elements into global
    /// parameters
    ///
    /// For each scalar element in the set:
407
    /// - Invoke parseElement
Josh Soref's avatar
Josh Soref committed
408
    /// - If it returns true go to the next element otherwise:
409
410
411
    ///     - create a parser for the element
    ///     - invoke the parser's build method
    ///     - invoke the parser's commit method
412
413
414
415
416
417
418
419
420
    ///
    /// This will commit the values to context storage making them accessible
    /// during object parsing.
    ///
    /// @param params_config set of scalar configuration elements to parse
    virtual void buildParams(isc::data::ConstElementPtr params_config);

    /// @brief Abstract factory which creates a context instance.
    ///
421
422
423
424
425
426
    /// 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.
    ///
427
428
429
    /// @return Returns a DCfgContextBasePtr to the new context instance.
    virtual DCfgContextBasePtr createNewContext() = 0;

Francis Dupont's avatar
Francis Dupont committed
430
    /// @brief Replaces existing context with a new, empty context.
431
432
433
434
435
436
437
438
439
    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(DCfgContextBasePtr& context);

440
441
442
443
444
445
446
447
448
    /// @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.
    ///
Josh Soref's avatar
Josh Soref committed
449
    /// @param config the Element tree structure that describes the configuration.
450
451
452
453
454
455
456
457
    /// @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);

458
459
private:

460
461
    /// @brief Parse a configuration element.
    ///
462
463
464
465
    /// Given an element_id and data value, invoke parseElement. If
    /// it returns true the return, otherwise created the appropriate
    /// parser, parse the data value, and commit the results.
    ///
466
467
468
469
470
471
472
473
474
475
    ///
    /// @param element_id is the string name of the element as it will appear
    /// in the configuration set.
    /// @param value is the data value to be parsed and associated with
    /// element_id.
    ///
    /// @throw throws DCfgMgrBaseError if an error occurs.
    void buildAndCommit(std::string& element_id,
                        isc::data::ConstElementPtr value);

476
477
478
479
    /// @brief A list of element ids which specifies the element parsing order.
    ///
    /// If the list is empty, the natural order in the configuration set
    /// it used.
480
481
482
483
484
485
486
487
488
489
    ElementIdList parse_order_;

    /// @brief Pointer to the configuration context instance.
    DCfgContextBasePtr context_;
};

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


490
}; // end of isc::process namespace
491
492
493
}; // end of isc namespace

#endif // D_CFG_MGR_H