Aktualizr
C++ SOTA Client
config_utils.h
1 #ifndef CONFIG_UTILS_H_
2 #define CONFIG_UTILS_H_
3 
4 #include <string>
5 
6 #include <boost/property_tree/ini_parser.hpp>
7 
8 #include "logging/logging.h"
9 #include "types.h"
10 #include "utils.h"
11 
12 /*
13  The following uses a small amount of template hackery to provide a nice
14  interface to load the sota.toml config file. StripQuotesFromStrings is
15  templated, and passes everything that isn't a string straight through.
16  Strings in toml are always double-quoted, and we remove them by specializing
17  StripQuotesFromStrings for std::string.
18 
19  The end result is that the sequence of calls in Config::updateFromToml are
20  pretty much a direct expression of the required behaviour: load this variable
21  from this config entry, and print a warning at the
22 
23  Note that default values are defined by Config's default constructor.
24  */
25 
26 template <typename T>
27 inline T StripQuotesFromStrings(const T& value);
28 
29 template <>
30 inline std::string StripQuotesFromStrings<std::string>(const std::string& value) {
31  return Utils::stripQuotes(value);
32 }
33 
34 template <typename T>
35 inline T StripQuotesFromStrings(const T& value) {
36  return value;
37 }
38 
39 template <typename T>
40 inline T addQuotesToStrings(const T& value);
41 
42 template <>
43 inline std::string addQuotesToStrings<std::string>(const std::string& value) {
44  return Utils::addQuotes(value);
45 }
46 
47 template <typename T>
48 inline T addQuotesToStrings(const T& value) {
49  return value;
50 }
51 
52 template <typename T>
53 inline void writeOption(std::ostream& sink, const T& data, const std::string& option_name) {
54  sink << option_name << " = " << addQuotesToStrings(data) << "\n";
55 }
56 
57 template <typename T>
58 inline void CopyFromConfig(T& dest, const std::string& option_name, const boost::property_tree::ptree& pt) {
59  boost::optional<T> value = pt.get_optional<T>(option_name);
60  if (value.is_initialized()) {
61  dest = StripQuotesFromStrings(value.get());
62  }
63 }
64 
65 template <>
66 inline void CopyFromConfig(KeyType& dest, const std::string& option_name, const boost::property_tree::ptree& pt) {
67  boost::optional<std::string> value = pt.get_optional<std::string>(option_name);
68  if (value.is_initialized()) {
69  std::string key_type{StripQuotesFromStrings(value.get())};
70  if (key_type == "RSA2048") {
71  dest = KeyType::kRSA2048;
72  } else if (key_type == "RSA3072") {
73  dest = KeyType::kRSA3072;
74  } else if (key_type == "RSA4096") {
75  dest = KeyType::kRSA4096;
76  } else if (key_type == "ED25519") {
77  dest = KeyType::kED25519;
78  } else {
79  dest = KeyType::kUnknown;
80  }
81  }
82 }
83 
84 template <>
85 inline void CopyFromConfig(CryptoSource& dest, const std::string& option_name, const boost::property_tree::ptree& pt) {
86  boost::optional<std::string> value = pt.get_optional<std::string>(option_name);
87  if (value.is_initialized()) {
88  std::string crypto_source{StripQuotesFromStrings(value.get())};
89  if (crypto_source == "pkcs11") {
90  dest = CryptoSource::kPkcs11;
91  } else {
92  dest = CryptoSource::kFile;
93  }
94  }
95 }
96 
97 template <>
98 inline void CopyFromConfig(RunningMode& dest, const std::string& option_name, const boost::property_tree::ptree& pt) {
99  boost::optional<std::string> value = pt.get_optional<std::string>(option_name);
100  if (value.is_initialized()) {
101  dest = RunningModeFromString(StripQuotesFromStrings(value.get()));
102  }
103 }
104 
105 template <>
106 inline void CopyFromConfig(BasedPath& dest, const std::string& option_name, const boost::property_tree::ptree& pt) {
107  boost::optional<std::string> value = pt.get_optional<std::string>(option_name);
108  if (value.is_initialized()) {
109  BasedPath bp{StripQuotesFromStrings(value.get())};
110  dest = bp;
111  }
112 }
113 
114 template <typename T>
115 inline void CopySubtreeFromConfig(T& dest, const std::string& subtree_name, const boost::property_tree::ptree& pt) {
116  auto subtree = pt.get_child_optional(subtree_name);
117  if (subtree.is_initialized()) {
118  dest.updateFromPropertyTree(subtree.get());
119  } else {
120  // call with empty tree so that default value warnings are preserved
121  dest.updateFromPropertyTree(boost::property_tree::ptree());
122  }
123 }
124 
125 template <typename T>
126 inline void WriteSectionToStream(T& sec, const std::string& section_name, std::ostream& os) {
127  os << std::boolalpha;
128  os << "[" << section_name << "]\n";
129  sec.writeToStream(os);
130  os << "\n";
131 }
132 
133 class BaseConfig {
134  public:
135  virtual ~BaseConfig() = default;
136  void updateFromToml(const boost::filesystem::path& filename) {
137  LOG_INFO << "Reading config: " << filename;
138  if (!boost::filesystem::exists(filename)) {
139  throw std::runtime_error("Config file " + filename.string() + " does not exist.");
140  }
141  boost::property_tree::ptree pt;
142  boost::property_tree::ini_parser::read_ini(filename.string(), pt);
143  updateFromPropertyTree(pt);
144  }
145  virtual void updateFromPropertyTree(const boost::property_tree::ptree& pt) = 0;
146 
147  protected:
148  void updateFromDirs(const std::vector<boost::filesystem::path>& configs) {
149  std::map<std::string, boost::filesystem::path> configs_map;
150  for (const auto& config : configs) {
151  if (!boost::filesystem::exists(config)) {
152  continue;
153  }
154  if (boost::filesystem::is_directory(config)) {
155  for (const auto& config_file : Utils::glob((config / "*.toml").string())) {
156  configs_map[config_file.filename().string()] = config_file;
157  }
158  } else {
159  configs_map[config.filename().string()] = config;
160  }
161  }
162  for (const auto& config_file : configs_map) {
163  updateFromToml(config_file.second);
164  }
165  }
166 
167  void checkDirs(const std::vector<boost::filesystem::path>& configs) {
168  for (const auto& config : configs) {
169  if (!boost::filesystem::exists(config)) {
170  throw std::runtime_error("Config directory " + config.string() + " does not exist.");
171  }
172  }
173  }
174 
175  std::vector<boost::filesystem::path> config_dirs_ = {"/usr/lib/sota/conf.d", "/etc/sota/conf.d/"};
176 };
177 
178 #endif // CONFIG_UTILS_H_
General data structures.
Definition: types.cc:44
RunningMode
Execution mode to run aktualizr in.
Definition: types.h:63