// 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 #include #include #include #include #include #include #include #include namespace isc { namespace process { /// @brief Defines a map of ConstElementPtrs keyed by name typedef std::map 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& 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> jsonPathsToRedact() const; private: /// @brief Pointer to the configuration context instance. ConfigPtr context_; }; /// @brief Defines a shared pointer to DCfgMgrBase. typedef boost::shared_ptr DCfgMgrBasePtr; } // end of isc::process namespace } // end of isc namespace #endif // D_CFG_MGR_H