#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace zkutil { class ZooKeeperNodeCache; } using ConfigurationPtr = Poco::AutoPtr; using XMLDocumentPtr = Poco::AutoPtr; class ConfigProcessor { public: using Substitutions = std::vector >; /// Set log_to_console to true if the logging subsystem is not initialized yet. ConfigProcessor(bool throw_on_bad_incl = false, bool log_to_console = false, const Substitutions & substitutions = Substitutions()); ~ConfigProcessor(); /// Perform config includes and substitutions and return the resulting XML-document. /// /// Suppose path is "/path/file.xml" /// 1) Merge XML trees of /path/file.xml with XML trees of all files from /path/{conf,file}.d/*.{conf,xml} /// * If an element has a "replace" attribute, replace the matching element with it. /// * If an element has a "remove" attribute, remove the matching element. /// * Else, recursively merge child elements. /// 2) Determine the includes file from the config: /path2/metrika.xml /// If this path is not configured, use /etc/metrika.xml /// 3) Replace elements matching the "" pattern with /// "contents of the yandex/bar element in metrika.xml" /// 4) If zk_node_cache is non-NULL, replace elements matching the "" pattern with /// "contents of the /bar ZooKeeper node". /// If has_zk_includes is non-NULL and there are such elements, set has_zk_includes to true. /// 5) (Yandex.Metrika-specific) Substitute "" with "layer number from the hostname". XMLDocumentPtr processConfig( const std::string & path, bool * has_zk_includes = nullptr, zkutil::ZooKeeperNodeCache * zk_node_cache = nullptr); /// loadConfig* functions apply processConfig and create Poco::Util::XMLConfiguration. /// The resulting XML document is saved into a file with the name /// resulting from adding "-preprocessed" suffix to the path file name. /// E.g., config.xml -> config-preprocessed.xml struct LoadedConfig { ConfigurationPtr configuration; bool has_zk_includes; bool loaded_from_preprocessed; bool preprocessed_written; }; /// If allow_zk_includes is true, expect that the configuration XML can contain from_zk nodes. /// If it is the case, set has_zk_includes to true and don't write config-preprocessed.xml, /// expecting that config would be reloaded with zookeeper later. LoadedConfig loadConfig(const std::string & path, bool allow_zk_includes = false); /// If fallback_to_preprocessed is true, then if KeeperException is thrown during config /// processing, load the configuration from the preprocessed file. LoadedConfig loadConfigWithZooKeeperIncludes( const std::string & path, zkutil::ZooKeeperNodeCache & zk_node_cache, bool fallback_to_preprocessed = false); public: using Files = std::list; static Files getConfigMergeFiles(const std::string & config_path); private: bool throw_on_bad_incl; Logger * log; Poco::AutoPtr channel_ptr; Substitutions substitutions; Poco::AutoPtr name_pool; Poco::XML::DOMParser dom_parser; private: using NodePtr = Poco::AutoPtr; void mergeRecursive(XMLDocumentPtr config, Poco::XML::Node * config_node, Poco::XML::Node * with_node); void merge(XMLDocumentPtr config, XMLDocumentPtr with); std::string layerFromHost(); void doIncludesRecursive( XMLDocumentPtr config, XMLDocumentPtr include_from, Poco::XML::Node * node, zkutil::ZooKeeperNodeCache * zk_node_cache, std::unordered_set & contributing_zk_paths); void savePreprocessedConfig(const XMLDocumentPtr & config, const std::string & preprocessed_path); };