Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
config.cc
1 #include <fcntl.h>
2 #include <unistd.h>
3 #include <iomanip>
4 #include <sstream>
5 
6 #include "bootstrap/bootstrap.h"
7 #include "libaktualizr/config.h"
8 #include "utilities/config_utils.h"
9 #include "utilities/exceptions.h"
10 #include "utilities/utils.h"
11 
12 std::ostream& operator<<(std::ostream& os, ProvisionMode mode) {
13  std::string mode_s;
14  switch (mode) {
15  case ProvisionMode::kSharedCred:
16  mode_s = "SharedCred";
17  break;
18  case ProvisionMode::kDeviceCred:
19  mode_s = "DeviceCred";
20  break;
21  case ProvisionMode::kSharedCredReuse:
22  mode_s = "SharedCredReuse";
23  break;
24  default:
25  mode_s = "Default";
26  break;
27  }
28  os << '"' << mode_s << '"';
29  return os;
30 }
31 
32 template <>
33 inline void CopyFromConfig(ProvisionMode& dest, const std::string& option_name, const boost::property_tree::ptree& pt) {
34  boost::optional<std::string> value = pt.get_optional<std::string>(option_name);
35  if (value.is_initialized()) {
36  std::string provision_mode{StripQuotesFromStrings(value.get())};
37  if (provision_mode == "SharedCred") {
38  dest = ProvisionMode::kSharedCred;
39  } else if (provision_mode == "DeviceCred") {
40  dest = ProvisionMode::kDeviceCred;
41  } else if (provision_mode == "SharedCredReuse") {
42  dest = ProvisionMode::kSharedCredReuse;
43  } else {
44  dest = ProvisionMode::kDefault;
45  }
46  }
47 }
48 
49 void TlsConfig::updateFromPropertyTree(const boost::property_tree::ptree& pt) {
50  CopyFromConfig(server, "server", pt);
51  CopyFromConfig(server_url_path, "server_url_path", pt);
52  CopyFromConfig(ca_source, "ca_source", pt);
53  CopyFromConfig(cert_source, "cert_source", pt);
54  CopyFromConfig(pkey_source, "pkey_source", pt);
55 }
56 
57 void TlsConfig::writeToStream(std::ostream& out_stream) const {
58  writeOption(out_stream, server, "server");
59  writeOption(out_stream, server_url_path, "server_url_path");
60  writeOption(out_stream, ca_source, "ca_source");
61  writeOption(out_stream, pkey_source, "pkey_source");
62  writeOption(out_stream, cert_source, "cert_source");
63 }
64 
65 void ProvisionConfig::updateFromPropertyTree(const boost::property_tree::ptree& pt) {
66  CopyFromConfig(server, "server", pt);
67  CopyFromConfig(p12_password, "p12_password", pt);
68  CopyFromConfig(expiry_days, "expiry_days", pt);
69  CopyFromConfig(provision_path, "provision_path", pt);
70  CopyFromConfig(device_id, "device_id", pt);
71  CopyFromConfig(primary_ecu_serial, "primary_ecu_serial", pt);
72  CopyFromConfig(primary_ecu_hardware_id, "primary_ecu_hardware_id", pt);
73  CopyFromConfig(ecu_registration_endpoint, "ecu_registration_endpoint", pt);
74  CopyFromConfig(mode, "mode", pt);
75 }
76 
77 void ProvisionConfig::writeToStream(std::ostream& out_stream) const {
78  writeOption(out_stream, server, "server");
79  writeOption(out_stream, p12_password, "p12_password");
80  writeOption(out_stream, expiry_days, "expiry_days");
81  writeOption(out_stream, provision_path, "provision_path");
82  writeOption(out_stream, device_id, "device_id");
83  writeOption(out_stream, primary_ecu_serial, "primary_ecu_serial");
84  writeOption(out_stream, primary_ecu_hardware_id, "primary_ecu_hardware_id");
85  writeOption(out_stream, ecu_registration_endpoint, "ecu_registration_endpoint");
86  writeOption(out_stream, mode, "mode");
87 }
88 
89 void UptaneConfig::updateFromPropertyTree(const boost::property_tree::ptree& pt) {
90  CopyFromConfig(polling_sec, "polling_sec", pt);
91  CopyFromConfig(director_server, "director_server", pt);
92  CopyFromConfig(repo_server, "repo_server", pt);
93  CopyFromConfig(key_source, "key_source", pt);
94  CopyFromConfig(key_type, "key_type", pt);
95  CopyFromConfig(force_install_completion, "force_install_completion", pt);
96  CopyFromConfig(secondary_config_file, "secondary_config_file", pt);
97  CopyFromConfig(secondary_preinstall_wait_sec, "secondary_preinstall_wait_sec", pt);
98 }
99 
100 void UptaneConfig::writeToStream(std::ostream& out_stream) const {
101  writeOption(out_stream, polling_sec, "polling_sec");
102  writeOption(out_stream, director_server, "director_server");
103  writeOption(out_stream, repo_server, "repo_server");
104  writeOption(out_stream, key_source, "key_source");
105  writeOption(out_stream, key_type, "key_type");
106  writeOption(out_stream, force_install_completion, "force_install_completion");
107  writeOption(out_stream, secondary_config_file, "secondary_config_file");
108  writeOption(out_stream, secondary_preinstall_wait_sec, "secondary_preinstall_wait_sec");
109 }
110 
111 void P11Config::updateFromPropertyTree(const boost::property_tree::ptree& pt) {
112  CopyFromConfig(module, "module", pt);
113  CopyFromConfig(pass, "pass", pt);
114  CopyFromConfig(uptane_key_id, "uptane_key_id", pt);
115  CopyFromConfig(tls_cacert_id, "tls_cacert_id", pt);
116  CopyFromConfig(tls_pkey_id, "tls_pkey_id", pt);
117  CopyFromConfig(tls_clientcert_id, "tls_clientcert_id", pt);
118 }
119 
120 void P11Config::writeToStream(std::ostream& out_stream) const {
121  writeOption(out_stream, module, "module");
122  writeOption(out_stream, pass, "pass");
123  writeOption(out_stream, uptane_key_id, "uptane_key_id");
124  writeOption(out_stream, tls_cacert_id, "tls_ca_id");
125  writeOption(out_stream, tls_pkey_id, "tls_pkey_id");
126  writeOption(out_stream, tls_clientcert_id, "tls_clientcert_id");
127 }
128 
129 void BaseConfig::updateFromToml(const boost::filesystem::path& filename) {
130  LOG_INFO << "Reading config: " << filename;
131  if (!boost::filesystem::exists(filename)) {
132  throw std::runtime_error("Config file " + filename.string() + " does not exist.");
133  }
134  boost::property_tree::ptree pt;
135  boost::property_tree::ini_parser::read_ini(filename.string(), pt);
136  updateFromPropertyTree(pt);
137 }
138 
139 void BaseConfig::updateFromDirs(const std::vector<boost::filesystem::path>& configs) {
140  std::map<std::string, boost::filesystem::path> configs_map;
141  for (const auto& config : configs) {
142  if (!boost::filesystem::exists(config)) {
143  continue;
144  }
145  if (boost::filesystem::is_directory(config)) {
146  for (const auto& config_file : Utils::getDirEntriesByExt(config, ".toml")) {
147  configs_map[config_file.filename().string()] = config_file;
148  }
149  } else {
150  configs_map[config.filename().string()] = config;
151  }
152  }
153  for (const auto& config_file : configs_map) {
154  updateFromToml(config_file.second);
155  }
156 }
157 
158 /**
159  * \par Description:
160  * Overload the << operator for the configuration class allowing
161  * us to print its content, i.e. for logging purposes.
162  */
163 std::ostream& operator<<(std::ostream& os, const Config& cfg) {
164  cfg.writeToStream(os);
165  return os;
166 }
167 
168 Config::Config() { postUpdateValues(); }
169 
170 Config::Config(const boost::filesystem::path& filename) {
171  updateFromToml(filename);
172  postUpdateValues();
173 }
174 
175 Config::Config(const std::vector<boost::filesystem::path>& config_dirs) {
176  checkDirs(config_dirs);
177  updateFromDirs(config_dirs);
178  postUpdateValues();
179 }
180 
181 Config::Config(const boost::program_options::variables_map& cmd) {
182  // Redundantly check and set the loglevel from the commandline prematurely so
183  // that it is taken account while processing the config.
184  if (cmd.count("loglevel") != 0) {
185  logger.loglevel = cmd["loglevel"].as<int>();
186  logger_set_threshold(logger);
187  loglevel_from_cmdline = true;
188  }
189 
190  if (cmd.count("config") > 0) {
191  const auto configs = cmd["config"].as<std::vector<boost::filesystem::path>>();
192  checkDirs(configs);
193  updateFromDirs(configs);
194  } else {
195  updateFromDirs(config_dirs_);
196  }
197  updateFromCommandLine(cmd);
198  postUpdateValues();
199 }
200 
201 KeyManagerConfig Config::keymanagerConfig() const {
202  return KeyManagerConfig{p11, tls.ca_source, tls.pkey_source, tls.cert_source, uptane.key_type, uptane.key_source};
203 }
204 
205 void Config::postUpdateValues() {
206  logger_set_threshold(logger);
207 
208  if (provision.mode == ProvisionMode::kDefault) {
209  provision.mode = provision.provision_path.empty() ? ProvisionMode::kDeviceCred : ProvisionMode::kSharedCred;
210  } else if (provision.mode == ProvisionMode::kSharedCredReuse) {
211  LOG_INFO << "Provisioning mode is set to reuse shared credentials. This should only be used for testing!";
212  }
213 
214  if (tls.server.empty()) {
215  if (!tls.server_url_path.empty()) {
216  try {
217  tls.server = Utils::readFile(tls.server_url_path, true);
218  } catch (const std::exception& e) {
219  LOG_ERROR << "Couldn't read gateway URL: " << e.what();
220  tls.server = "";
221  }
222  } else if (!provision.provision_path.empty()) {
223  if (boost::filesystem::exists(provision.provision_path)) {
224  tls.server = Bootstrap::readServerUrl(provision.provision_path);
225  } else {
226  LOG_ERROR << "Provided provision archive " << provision.provision_path << " does not exist!";
227  }
228  }
229  }
230 
231  if (!tls.server.empty()) {
232  if (provision.server.empty()) {
233  provision.server = tls.server;
234  }
235 
236  if (uptane.repo_server.empty()) {
237  uptane.repo_server = tls.server + "/repo";
238  }
239 
240  if (uptane.director_server.empty()) {
241  uptane.director_server = tls.server + "/director";
242  }
243 
244  if (pacman.ostree_server.empty()) {
245  pacman.ostree_server = tls.server + "/treehub";
246  }
247  }
248 
249  if (!uptane.director_server.empty()) {
250  if (provision.ecu_registration_endpoint.empty()) {
251  provision.ecu_registration_endpoint = uptane.director_server + "/ecus";
252  }
253  }
254 
255  LOG_TRACE << "Final configuration that will be used: \n" << (*this);
256 }
257 
258 // For testing
259 void Config::updateFromTomlString(const std::string& contents) {
260  boost::property_tree::ptree pt;
261  std::stringstream stream(contents);
262  boost::property_tree::ini_parser::read_ini(stream, pt);
263  updateFromPropertyTree(pt);
264 }
265 
266 void Config::updateFromPropertyTree(const boost::property_tree::ptree& pt) {
267  // Keep this order the same as in config.h and Config::writeToStream().
268  if (!loglevel_from_cmdline) {
269  CopySubtreeFromConfig(logger, "logger", pt);
270  // If not already set from the commandline, set the loglevel now so that it
271  // affects the rest of the config processing.
272  logger_set_threshold(logger);
273  }
274  CopySubtreeFromConfig(p11, "p11", pt);
275  CopySubtreeFromConfig(tls, "tls", pt);
276  CopySubtreeFromConfig(provision, "provision", pt);
277  CopySubtreeFromConfig(uptane, "uptane", pt);
278  CopySubtreeFromConfig(pacman, "pacman", pt);
279  CopySubtreeFromConfig(storage, "storage", pt);
280  CopySubtreeFromConfig(import, "import", pt);
281  CopySubtreeFromConfig(telemetry, "telemetry", pt);
282  CopySubtreeFromConfig(bootloader, "bootloader", pt);
283 }
284 
285 void Config::updateFromCommandLine(const boost::program_options::variables_map& cmd) {
286  // Try to keep these options in the same order as parse_options() in main.cc.
287  if (cmd.count("loglevel") != 0) {
288  logger.loglevel = cmd["loglevel"].as<int>();
289  }
290  if (cmd.count("tls-server") != 0) {
291  tls.server = cmd["tls-server"].as<std::string>();
292  }
293  if (cmd.count("repo-server") != 0) {
294  uptane.repo_server = cmd["repo-server"].as<std::string>();
295  }
296  if (cmd.count("director-server") != 0) {
297  uptane.director_server = cmd["director-server"].as<std::string>();
298  }
299  if (cmd.count("primary-ecu-serial") != 0) {
300  provision.primary_ecu_serial = cmd["primary-ecu-serial"].as<std::string>();
301  }
302  if (cmd.count("primary-ecu-hardware-id") != 0) {
303  provision.primary_ecu_hardware_id = cmd["primary-ecu-hardware-id"].as<std::string>();
304  }
305  if (cmd.count("secondary-config-file") != 0) {
306  uptane.secondary_config_file = cmd["secondary_config_file"].as<boost::filesystem::path>();
307  }
308 }
309 
310 void Config::writeToStream(std::ostream& sink) const {
311  // Keep this order the same as in config.h and
312  // Config::updateFromPropertyTree().
313  WriteSectionToStream(logger, "logger", sink);
314  WriteSectionToStream(p11, "p11", sink);
315  WriteSectionToStream(tls, "tls", sink);
316  WriteSectionToStream(provision, "provision", sink);
317  WriteSectionToStream(uptane, "uptane", sink);
318  WriteSectionToStream(pacman, "pacman", sink);
319  WriteSectionToStream(storage, "storage", sink);
320  WriteSectionToStream(import, "import", sink);
321  WriteSectionToStream(telemetry, "telemetry", sink);
322  WriteSectionToStream(bootloader, "bootloader", sink);
323 }
Configuration object for an aktualizr instance running on a Primary ECU.
Definition: config.h:210