Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
main.cc
1 #include <curl/curl.h>
2 #include <logging/logging.h>
3 #include <boost/program_options.hpp>
4 #include <iostream>
5 #include <thread>
6 
7 #include "check.h"
8 #include "provision.h"
9 #include "sslinit.h"
10 #ifdef BUILD_OSTREE
11 #include "treehub.h"
12 #endif
13 
14 namespace bpo = boost::program_options;
15 
16 void checkForUpdatesCmd(const std::vector<std::string> &opts) {
17  namespace fs = boost::filesystem;
18  unsigned int devicesPerSec;
19  unsigned int opsNr;
20  unsigned int parallelism;
21  std::string inputDir;
22  bpo::options_description description("Check for update options");
23  // clang-format off
24  description.add_options()
25  ("inputdir,i", bpo::value<std::string>(&inputDir)->required(), "path to the input data")
26  ("rate,r", bpo::value<unsigned int>(&devicesPerSec)->default_value(5), "devices/sec")
27  ("number,n", bpo::value<unsigned int>(&opsNr)->default_value(100), "number of operation to execute")
28  ("threads,t", bpo::value<unsigned int>(&parallelism)->default_value(std::thread::hardware_concurrency()), "number of worker threads");
29  // clang-format on
30 
31  bpo::variables_map vm;
32  bpo::store(bpo::command_line_parser(opts).options(description).run(), vm);
33  bpo::notify(vm);
34 
35  const fs::path inputPath(inputDir);
36  LOG_INFO << "Checking for updates...";
37  checkForUpdates(inputPath, devicesPerSec, opsNr, parallelism);
38 }
39 
40 #ifdef BUILD_OSTREE
41 void fetchRemoteCmd(const std::vector<std::string> &opts) {
42  std::string inputDir;
43  std::string outDir;
44  std::string branchName;
45  std::string remoteUrl;
46  unsigned int opsPerSec;
47  unsigned int opsNr;
48  unsigned int parallelism;
49  bpo::options_description description("Fetch from ostree");
50  // clang-format off
51  description.add_options()
52  ("inputdir,i", bpo::value<std::string>(&inputDir)->required(), "Directory containig provisioned devices.")
53  ("outputdir,o", bpo::value<std::string>(&outDir)->required(), "Directory where repos will be created")
54  ("branch,b", bpo::value<std::string>(&branchName)->required(), "Name of a branch to pull")
55  ("url,u", bpo::value<std::string>(&remoteUrl)->required(), "Url of the repository")
56  ("number,n", bpo::value<unsigned int>(&opsNr)->default_value(100), "number of operation to execute")
57  ("threads,t", bpo::value<unsigned int>(&parallelism)->default_value(std::thread::hardware_concurrency()), "number of worker threads")
58  ("rate,r", bpo::value<unsigned int>(&opsPerSec)->default_value(50), "repo pulls per second");
59  // clang-format on
60 
61  bpo::variables_map vm;
62  bpo::store(bpo::command_line_parser(opts).options(description).run(), vm);
63  bpo::notify(vm);
64 
65  const boost::filesystem::path outputPath(outDir);
66  fetchFromOstree(inputDir, outputPath, branchName, remoteUrl, opsPerSec, opsNr, parallelism);
67 }
68 
69 void checkAndFetchCmd(const std::vector<std::string> &opts) {
70  namespace fs = boost::filesystem;
71  unsigned int checkPerSec;
72  unsigned int checkNr;
73  unsigned int checkParallelism;
74  std::string branchName;
75  std::string remoteUrl;
76  unsigned int fetchesPerSec;
77  unsigned int fetchesNr;
78  unsigned int fetchesParallelism;
79  std::string inputDir;
80  std::string outDir;
81  bpo::options_description description("Check for update options");
82  // clang-format off
83  description.add_options()
84  ("inputdir,i", bpo::value<std::string>(&inputDir)->required(), "path to the input data")
85  ("outputdir,o", bpo::value<std::string>(&outDir)->required(), "Directory where repos will be created")
86  ("branch,b", bpo::value<std::string>(&branchName)->required(), "Name of a branch to pull")
87  ("url,u", bpo::value<std::string>(&remoteUrl)->required(), "Url of the repository")
88  ("fn", bpo::value<unsigned int>(&fetchesNr)->default_value(100), "number of fetches from treehub")
89  ("ft", bpo::value<unsigned int>(&fetchesParallelism)->default_value(std::thread::hardware_concurrency()), "number of fetch worker threads")
90  ("fr", bpo::value<unsigned int>(&fetchesPerSec)->default_value(50), "fetches per second")
91  ("cr", bpo::value<unsigned int>(&checkPerSec)->default_value(5), "check for update/sec")
92  ("cn", bpo::value<unsigned int>(&checkNr)->default_value(100), "number of checks to execute")
93  ("ct", bpo::value<unsigned int>(&checkParallelism)->default_value(std::thread::hardware_concurrency()), "number of check worker threads");
94  // clang-format on
95 
96  bpo::variables_map vm;
97  bpo::store(bpo::command_line_parser(opts).options(description).run(), vm);
98  bpo::notify(vm);
99 
100  const fs::path inputPath(inputDir);
101  const fs::path outputPath(outDir);
102  std::thread checkThread{checkForUpdates, std::ref(inputPath), checkPerSec, checkNr, checkParallelism};
103  std::thread fetchThread{
104  fetchFromOstree, std::ref(inputPath), std::ref(outputPath), std::ref(branchName), std::ref(remoteUrl),
105  fetchesPerSec, fetchesNr, fetchesParallelism};
106  checkThread.join();
107  fetchThread.join();
108 }
109 #endif
110 
111 void provisionDevicesCmd(const std::vector<std::string> &opts) {
112  using namespace boost::filesystem;
113  unsigned int devicesNr;
114  size_t parallelism;
115  uint devicesPerSec;
116  std::string outDir;
117  std::string pathToCredentials;
118  std::string gwUrl;
119  bpo::options_description description("Register devices");
120 
121  // clang-format off
122  description.add_options()
123  ("outputdir,o", bpo::value<std::string>(&outDir)->required(), "output directory")
124  ("gateway,g", bpo::value<std::string>(&gwUrl)->required(), "url of the device gateway")
125  ("credentials,c", bpo::value<std::string>(&pathToCredentials), "path to a provisioning credentials")
126  ("dev-number,n", bpo::value<unsigned int>(&devicesNr)->default_value(100), "number of devices")
127  ("rate,r", bpo::value<uint>(&devicesPerSec)->default_value(2), "devices/sec")
128  ("threads,t", bpo::value<size_t>(&parallelism)->default_value(std::thread::hardware_concurrency()), "number of worker threads");
129  // clang-format on
130 
131  bpo::variables_map vm;
132  bpo::store(bpo::command_line_parser(opts).options(description).run(), vm);
133  bpo::notify(vm);
134 
135  const path devicesDir(outDir);
136 
137  const path credentialsFile(pathToCredentials);
138  mkDevices(devicesDir, credentialsFile, gwUrl, parallelism, devicesNr, devicesPerSec);
139 }
140 
141 void setLogLevel(const bpo::variables_map &vm) {
142  // set the log level from command line option
143  boost::log::trivial::severity_level severity =
144  static_cast<boost::log::trivial::severity_level>(vm["loglevel"].as<int>());
145  if (severity < boost::log::trivial::trace) {
146  LOG_DEBUG << "Invalid log level";
147  severity = boost::log::trivial::trace;
148  }
149  if (boost::log::trivial::fatal < severity) {
150  LOG_WARNING << "Invalid log level";
151  severity = boost::log::trivial::fatal;
152  }
153  LoggerConfig loggerConfig{};
154  loggerConfig.loglevel = severity;
155  logger_set_threshold(loggerConfig);
156 }
157 
158 int main(int argc, char *argv[]) {
159  std::srand(static_cast<unsigned int>(std::time(0)));
160 
161  std::map<std::string, std::function<void(std::vector<std::string>)>> commands{{"provision", provisionDevicesCmd},
162  {"check", checkForUpdatesCmd}
163 #ifdef BUILD_OSTREE
164  ,
165  {"checkfetch", checkAndFetchCmd},
166  {"fetch", fetchRemoteCmd}
167 #endif
168  };
169 
170  std::stringstream acc;
171  bool first = true;
172  acc << "Supported tests: ";
173  for (auto const &elem : commands) {
174  if (!first) {
175  acc << ", ";
176  } else {
177  first = false;
178  };
179  acc << elem.first;
180  };
181  std::string supportedTests = acc.str();
182  std::string cmd;
183  bpo::options_description description("OTA load tests");
184  description.add_options()("help,h", "Show help message")("loglevel", bpo::value<int>()->default_value(3),
185  "set log level 0-4 (trace, debug, warning, info, error)")(
186  "test", bpo::value<std::string>(&cmd), supportedTests.c_str());
187 
188  bpo::variables_map vm;
189  bpo::parsed_options parsed = bpo::command_line_parser(argc, argv).options(description).allow_unregistered().run();
190  bpo::store(parsed, vm);
191  bpo::notify(vm);
192 
193  if (vm.count("help")) {
194  std::cout << description << std::endl;
195  return 0;
196  }
197 
198  logger_init();
199  setLogLevel(&vm);
200 
201  if (vm.count("test")) {
202  auto fn = commands.find(cmd);
203  if (fn != commands.end()) {
204  openssl_callbacks_setup();
205  std::vector<std::string> unprocessedOptions = bpo::collect_unrecognized(parsed.options, bpo::include_positional);
206  fn->second(unprocessedOptions);
207  openssl_callbacks_cleanup();
208  } else {
209  LOG_ERROR << supportedTests;
210  }
211  }
212  return 0;
213 }