2 Copyright (c) 2018-2019 Nokia.
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
8 http://www.apache.org/licenses/LICENSE-2.0
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
17 #include "private/abort.hpp"
18 #include "private/configurationreader.hpp"
19 #include <boost/property_tree/json_parser.hpp>
20 #include <sdl/exception.hpp>
21 #include "private/createlogger.hpp"
22 #include "private/databaseconfiguration.hpp"
23 #include "private/logger.hpp"
24 #include "private/namespaceconfigurations.hpp"
25 #include "private/namespacevalidator.hpp"
26 #include "private/system.hpp"
28 using namespace shareddatalayer;
33 T get(const boost::property_tree::ptree& ptree, const std::string& param, const std::string& sourceName)
37 return ptree.get<T>(param);
39 catch (const boost::property_tree::ptree_bad_path&)
41 std::ostringstream os;
42 os << "Configuration error in " << sourceName << ": "
43 << "missing \"" << param << '\"';
44 throw Exception(os.str());
46 catch (const boost::property_tree::ptree_bad_data& e)
48 std::ostringstream os;
49 os << "Configuration error in " << sourceName << ": "
50 << "invalid \"" << param << "\": \"" << e.data<boost::property_tree::ptree::data_type>() << '\"';
51 throw Exception(os.str());
55 void validateAndSetDbType(const std::string& type, DatabaseConfiguration& databaseConfiguration,
56 const std::string& sourceName)
60 databaseConfiguration.checkAndApplyDbType(type);
62 catch (const std::exception& e)
64 std::ostringstream os;
65 os << "Configuration error in " << sourceName << ": "
67 throw Exception(os.str());
71 void validateAndSetDbServerAddress(const std::string& address, DatabaseConfiguration& databaseConfiguration,
72 const std::string& sourceName)
76 databaseConfiguration.checkAndApplyServerAddress(address);
78 catch (const std::exception& e)
80 std::ostringstream os;
81 os << "Configuration error in " << sourceName << ": "
82 << "invalid \"address\": \"" << address << "\" " << e.what();
83 throw Exception(os.str());
87 void parseDatabaseServerConfiguration(DatabaseConfiguration& databaseConfiguration,
88 const boost::property_tree::ptree& ptree,
89 const std::string& sourceName)
91 const auto address(get<std::string>(ptree, "address", sourceName));
92 validateAndSetDbServerAddress(address, databaseConfiguration, sourceName);
95 void parseDatabaseServersConfiguration(DatabaseConfiguration& databaseConfiguration,
96 const boost::property_tree::ptree& ptree,
97 const std::string& sourceName)
99 const auto servers(ptree.get_child_optional("servers"));
101 for(const auto& server : *servers)
102 parseDatabaseServerConfiguration(databaseConfiguration, server.second, sourceName);
105 std::ostringstream os;
106 os << "Configuration error in " << sourceName << ": "
107 << "missing \"servers\"";
108 throw Exception(os.str());
112 void parseDatabaseConfiguration(DatabaseConfiguration& databaseConfiguration,
113 const boost::property_tree::ptree& ptree,
114 const std::string& sourceName)
116 const auto type(get<std::string>(ptree, "type", sourceName));
117 validateAndSetDbType(type, databaseConfiguration, sourceName);
119 parseDatabaseServersConfiguration(databaseConfiguration, ptree, sourceName);
122 void parseDatabaseConfigurationTree(DatabaseConfiguration& databaseConfiguration,
123 const boost::optional<boost::property_tree::ptree>& databaseConfigurationPtree,
124 const std::string& sourceName)
126 if (databaseConfigurationPtree)
127 parseDatabaseConfiguration(databaseConfiguration, *databaseConfigurationPtree, sourceName);
130 void parseDatabaseServersConfigurationFromString(DatabaseConfiguration& databaseConfiguration,
131 const std::string& serverConfiguration,
132 const std::string& sourceName)
138 auto split = serverConfiguration.find(',', base);
139 done = std::string::npos == split;
140 validateAndSetDbServerAddress(serverConfiguration.substr(base, done ? std::string::npos : split-base),
141 databaseConfiguration,
147 void validateNamespacePrefix(const std::string& prefix,
148 const std::string& sourceName)
150 if (!isValidNamespaceSyntax(prefix))
152 std::ostringstream os;
153 os << "Configuration error in " << sourceName << ": "
154 << "\"namespacePrefix\": \"" << prefix << "\""
155 << " contains some of these disallowed characters: "
156 << getDisallowedCharactersInNamespace();
157 throw Exception(os.str());
161 void validateEnableNotifications(bool enableNotifications, bool useDbBackend,
162 const std::string& sourceName)
164 if (enableNotifications && !useDbBackend)
166 std::ostringstream os;
167 os << "Configuration error in " << sourceName << ": "
168 << "\"enableNotifications\" cannot be true, when \"useDbBackend\" is false";
169 throw Exception(os.str());
173 void parseNsConfiguration(NamespaceConfigurations& namespaceConfigurations,
174 const std::string& namespacePrefix,
175 const boost::property_tree::ptree& ptree,
176 const std::string& sourceName)
178 const auto useDbBackend(get<bool>(ptree, "useDbBackend", sourceName));
179 const auto enableNotifications(get<bool>(ptree, "enableNotifications", sourceName));
181 validateNamespacePrefix(namespacePrefix, sourceName);
182 validateEnableNotifications(enableNotifications, useDbBackend, sourceName);
184 namespaceConfigurations.addNamespaceConfiguration({namespacePrefix, useDbBackend, enableNotifications, sourceName});
187 void parseNsConfigurationMap(NamespaceConfigurations& namespaceConfigurations,
188 std::unordered_map<std::string, std::pair<boost::property_tree::ptree, std::string>>& namespaceConfigurationMap)
190 for (const auto &namespaceConfigurationMapItem : namespaceConfigurationMap )
191 parseNsConfiguration(namespaceConfigurations, namespaceConfigurationMapItem.first, namespaceConfigurationMapItem.second.first, namespaceConfigurationMapItem.second.second);
195 ConfigurationReader::ConfigurationReader(std::shared_ptr<Logger> logger):
196 ConfigurationReader(getDefaultConfDirectories(), System::getSystem(), logger)
200 ConfigurationReader::ConfigurationReader(const Directories& directories,
202 std::shared_ptr<Logger> logger):
203 dbHostEnvVariableName(DB_HOST_ENV_VAR_NAME),
204 dbHostEnvVariableValue({}),
205 dbPortEnvVariableName(DB_PORT_ENV_VAR_NAME),
206 dbPortEnvVariableValue({}),
207 jsonDatabaseConfiguration(boost::none),
210 auto envStr = system.getenv(dbHostEnvVariableName.c_str());
213 dbHostEnvVariableValue = envStr;
214 sourceForDatabaseConfiguration = dbHostEnvVariableName;
215 auto envStr = system.getenv(dbPortEnvVariableName.c_str());
217 dbPortEnvVariableValue = envStr;
220 readConfigurationFromDirectories(directories);
223 ConfigurationReader::~ConfigurationReader()
227 void ConfigurationReader::readConfigurationFromDirectories(const Directories& directories)
229 for (const auto& i : findConfigurationFiles(directories))
230 readConfiguration(i, i);
233 void ConfigurationReader::readConfigurationFromInputStream(const std::istream& input)
235 jsonNamespaceConfigurations.clear();
236 readConfiguration(const_cast<std::istream&>(input), "<istream>");
240 void ConfigurationReader::readConfiguration(T& input, const std::string& currentSourceName)
242 boost::property_tree::ptree propertyTree;
246 boost::property_tree::read_json(input, propertyTree);
248 catch (const boost::property_tree::json_parser::json_parser_error& e)
250 std::ostringstream os;
251 os << "error in SDL configuration " << currentSourceName << " at line " << e.line() << ": ";
253 logger->error() << os.str();
254 throw Exception(os.str());
257 // Environment variable configuration overrides json configuration
258 if (sourceForDatabaseConfiguration != dbHostEnvVariableName)
260 const auto databaseConfiguration(propertyTree.get_child_optional("database"));
261 if (databaseConfiguration)
263 jsonDatabaseConfiguration = databaseConfiguration;
264 sourceForDatabaseConfiguration = currentSourceName;
268 const auto namespaceConfigurations(propertyTree.get_child_optional("sharedDataLayer"));
269 if (namespaceConfigurations)
271 for(const auto& namespaceConfiguration : *namespaceConfigurations)
273 const auto namespacePrefix = get<std::string>(namespaceConfiguration.second, "namespacePrefix", currentSourceName);
274 jsonNamespaceConfigurations[namespacePrefix] = std::make_pair(namespaceConfiguration.second, currentSourceName);
279 void ConfigurationReader::readDatabaseConfiguration(DatabaseConfiguration& databaseConfiguration)
281 if (!databaseConfiguration.isEmpty())
282 SHAREDDATALAYER_ABORT("Database configuration can be read only to empty container");
286 if (sourceForDatabaseConfiguration == dbHostEnvVariableName)
288 // Currently hard coded to redis-standalone, because RIC dbaas does not support Redis cluster configuration.
289 validateAndSetDbType("redis-standalone", databaseConfiguration, sourceForDatabaseConfiguration);
290 if (dbPortEnvVariableValue.empty())
291 parseDatabaseServersConfigurationFromString(databaseConfiguration, dbHostEnvVariableValue, sourceForDatabaseConfiguration);
293 parseDatabaseServersConfigurationFromString(databaseConfiguration, dbHostEnvVariableValue + ":" + dbPortEnvVariableValue, sourceForDatabaseConfiguration);
296 parseDatabaseConfigurationTree(databaseConfiguration, jsonDatabaseConfiguration, sourceForDatabaseConfiguration);
298 catch (const std::exception& e)
300 logger->error() << e.what();
305 void ConfigurationReader::readNamespaceConfigurations(NamespaceConfigurations& namespaceConfigurations)
307 if (!namespaceConfigurations.isEmpty())
308 SHAREDDATALAYER_ABORT("Namespace configurations can be read only to empty container");
312 parseNsConfigurationMap(namespaceConfigurations, jsonNamespaceConfigurations);
314 catch(const std::exception& e)
316 logger->error() << e.what();
322 template void ConfigurationReader::readConfiguration(const std::string&, const std::string&);
323 template void ConfigurationReader::readConfiguration(std::istream&, const std::string&);