softwarecontainer  0.18.0-739e8d7 2017-05-04
config.cpp
1 /*
2  * Copyright (C) 2016-2017 Pelagicore AB
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
9  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
10  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
11  * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
12  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
13  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
14  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
15  * SOFTWARE.
16  *
17  * For further information see LICENSE
18  */
19 
20 #include "softwarecontainer-common.h"
21 #include "config.h"
22 #include "configtypes.h"
23 #include "configerror.h"
24 
25 
26 namespace softwarecontainer {
27 
28 
29 Config::Config(std::vector<std::unique_ptr<ConfigSource>> sources,
30  MandatoryConfigs mandatory,
31  ConfigDependencies dependencies):
32  m_sources(std::move(sources)),
33  m_mandatory(mandatory),
34  m_dependencies(dependencies),
35  m_stringConfigs(std::vector<StringConfig>()),
36  m_intConfigs(std::vector<IntConfig>()),
37  m_boolConfigs(std::vector<BoolConfig>()),
38  m_allConfigs(std::vector<UniqueKey>())
39 {
40  /*
41  * The order of the calls below is important since some methods modifies members that are
42  * needed in subsequent method calls.
43  */
44 
45  // Read all ConfigItems from all sources and store them
46  readConfigsFromSources();
47 
48  // If any ConfigItem has one or more dependencies which are not present, it is a fatal error
49  assertDependencies();
50 
51  // If any group-key combo is mandatory and not present, it is a fatal error
52  assertAllMandatoryPresent();
53 }
54 
55 void Config::assertDependencies()
56 {
57  for (const auto &dep : m_dependencies) {
58  UniqueKey config = dep.first;
59  std::string group = std::get<0>(config);
60  std::string key = std::get<1>(config);
61 
62  // Check if the dependee exists in the configs we got from the sources
63  bool found = std::find(m_allConfigs.begin(), m_allConfigs.end(), config) != m_allConfigs.end();
64 
65  // If a dependee was present among the configs, all its dependencies needs to be present as well
66  if (found && !allDepsSatisfied(dep.second)) {
67  // It is a fatal error if one or more dependencies were not found
68  std::string message = "One or more dependencies were not met for config " + group + "::" + key;
69  log_error() << message;
70  throw ConfigDependencyError(message);
71  }
72  }
73 }
74 
75 bool Config::allDepsSatisfied(const std::vector<UniqueKey> &dependencies) const
76 {
77  for (const UniqueKey &dependency : dependencies) {
78  bool found = std::find(m_allConfigs.begin(), m_allConfigs.end(), dependency) != m_allConfigs.end();
79 
80  if (!found) {
81  return false;
82  }
83  }
84 
85  return true;
86 }
87 
88 void Config::assertAllMandatoryPresent()
89 {
90  for (const UniqueKey &mandatory : m_mandatory) {
91  // A mandatory config must be found among the configs we got from the sources
92  bool found = std::find(m_allConfigs.begin(), m_allConfigs.end(), mandatory) != m_allConfigs.end();
93 
94  if (!found) {
95  std::string message = "Mandatory config " + mandatory.first + "::" + mandatory.second + " not found";
96  log_error() << message;
97  throw ConfigMandatoryError(message);
98  }
99  }
100 }
101 
102 void Config::readConfigsFromSources()
103 {
104  for (auto &source : m_sources) {
105  auto stringConfigs = source->stringConfigs();
106  m_stringConfigs.insert(m_stringConfigs.end(), stringConfigs.begin(), stringConfigs.end());
107 
108  auto intConfigs = source->intConfigs();
109  m_intConfigs.insert(m_intConfigs.end(), intConfigs.begin(), intConfigs.end());
110 
111  auto boolConfigs = source->boolConfigs();
112  m_boolConfigs.insert(m_boolConfigs.end(), boolConfigs.begin(), boolConfigs.end());
113  }
114 
115  // Put all configs in the same place for later use
116  for (auto &config : m_stringConfigs) {
117  m_allConfigs.push_back(UniqueKey(config.group(), config.key()));
118  }
119 
120  for (auto &config : m_intConfigs) {
121  m_allConfigs.push_back(UniqueKey(config.group(), config.key()));
122  }
123 
124  for (auto &config : m_boolConfigs) {
125  m_allConfigs.push_back(UniqueKey(config.group(), config.key()));
126  }
127 }
128 
129 std::string Config::getStringValue(const std::string &group, const std::string &key) const
130 {
131  return getConfig(group, key, m_stringConfigs).value();
132 }
133 
134 int Config::getIntValue(const std::string &group, const std::string &key) const
135 {
136  return getConfig(group, key, m_intConfigs).value();
137 }
138 
139 bool Config::getBoolValue(const std::string &group, const std::string &key) const
140 {
141  return getConfig(group, key, m_boolConfigs).value();
142 }
143 
144 template<typename T>
145 T Config::getConfig(const std::string &group, const std::string &key, const std::vector<T> &configs) const
146 {
147  std::vector<T> foundConfigs;
148 
149  for (auto config : configs) {
150  if (config.group() == group && config.key() == key) {
151  log_debug() << "Found config "
152  << group << "::" << key
153  << " in "
154  << ConfigTypes::configSourceToString(config.source());
155  foundConfigs.push_back(config);
156  }
157  }
158 
159  if (foundConfigs.empty()) {
160  std::string message = "No config found for " + group + "::" + key;
161  log_error() << message;
162  throw ConfigNotFoundError(message);
163  }
164 
165  T config = prioritizedConfig(foundConfigs);
166 
167  log_debug() << "Using config "
168  << group << "::" << key
169  << " with value \""
170  << config.value() << "\""
171  << ", from " << ConfigTypes::configSourceToString(config.source());
172 
173  return config;
174 }
175 
176 template<typename T>
177 T Config::prioritizedConfig(const std::vector<T> &configs) const
178 {
179  for (auto config : configs) {
180  if (config.source() == ConfigSourceType::Commandline) {
181  return config;
182  }
183  }
184 
185  for (auto config : configs) {
186  if (config.source() == ConfigSourceType::Main) {
187  return config;
188  }
189  }
190 
191  for (auto config : configs) {
192  if (config.source() == ConfigSourceType::Default) {
193  return config;
194  }
195  }
196 
197  log_error() << "Config has an incorrect source";
198  throw ConfigInternalError("Config has an incorrect source");
199 }
200 
201 } // namespace softwarecontainer
bool getBoolValue(const std::string &group, const std::string &key) const
getBoolValue Get a config value of type bool
Definition: config.cpp:139
Represents a config item of type bool.
Definition: configitem.h:72
Represents a config item of type string.
Definition: configitem.h:46
std::string getStringValue(const std::string &group, const std::string &key) const
getStringValue Get a config value of type string
Definition: config.cpp:129
A requested config item could not be found in any of the config sources.
Definition: configerror.h:140
int getIntValue(const std::string &group, const std::string &key) const
getIntValue Get a config value of type int
Definition: config.cpp:134
Developers guide to adding a config item:
Represents a config item of type int.
Definition: configitem.h:59
Config(std::vector< std::unique_ptr< ConfigSource >> sources, MandatoryConfigs mandatory, ConfigDependencies dependencies)
Constructor - retrieves all configs from the available sources.
Definition: config.cpp:29
An error occured which is an internal error in the config code.
Definition: configerror.h:56