Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
garage_deploy.cc
1 #include <chrono>
2 #include <string>
3 
4 #include <boost/filesystem.hpp>
5 #include <boost/program_options.hpp>
6 
7 #include "authenticate.h"
8 #include "check.h"
9 #include "deploy.h"
10 #include "garage_common.h"
11 #include "garage_tools_version.h"
12 #include "logging/logging.h"
13 #include "ostree_http_repo.h"
14 
15 namespace po = boost::program_options;
16 
17 int main(int argc, char **argv) {
18  logger_init();
19 
20  auto start_time = std::chrono::system_clock::now();
21 
22  std::string ostree_commit;
23  std::string name;
24  boost::filesystem::path fetch_cred;
25  boost::filesystem::path push_cred;
26  std::string hardwareids;
27  std::string cacerts;
28  int max_curl_requests;
30  po::options_description desc("garage-deploy command line options");
31  // clang-format off
32  desc.add_options()
33  ("help", "print usage")
34  ("version", "Current garage-deploy version")
35  ("verbose,v", "Verbose logging (loglevel 1)")
36  ("quiet,q", "Quiet mode (loglevel 3)")
37  ("loglevel", po::value<int>(), "set log level 0-5 (trace, debug, info, warning, error, fatal)")
38  ("commit", po::value<std::string>(&ostree_commit)->required(), "OSTree commit to deploy")
39  ("name", po::value<std::string>(&name)->required(), "Name of image")
40  ("fetch-credentials,f", po::value<boost::filesystem::path>(&fetch_cred)->required(), "path to source credentials")
41  ("push-credentials,p", po::value<boost::filesystem::path>(&push_cred)->required(), "path to destination credentials")
42  ("hardwareids,h", po::value<std::string>(&hardwareids)->required(), "list of hardware ids")
43  ("cacert", po::value<std::string>(&cacerts), "override path to CA root certificates, in the same format as curl --cacert")
44  ("jobs", po::value<int>(&max_curl_requests)->default_value(30), "maximum number of parallel requests")
45  ("dry-run,n", "check arguments and authenticate but don't upload");
46  // clang-format on
47 
48  po::variables_map vm;
49 
50  try {
51  po::store(po::parse_command_line(argc, reinterpret_cast<const char *const *>(argv), desc), vm);
52 
53  if (vm.count("help") != 0U) {
54  LOG_INFO << desc;
55  return EXIT_SUCCESS;
56  }
57  if (vm.count("version") != 0) {
58  LOG_INFO << "Current garage-deploy version is: " << garage_tools_version();
59  exit(EXIT_SUCCESS);
60  }
61  po::notify(vm);
62  } catch (const po::error &o) {
63  LOG_ERROR << o.what();
64  LOG_ERROR << desc;
65  return EXIT_FAILURE;
66  }
67 
68  // Configure logging. Try loglevel first, then verbose, then quiet.
69  try {
70  if (vm.count("loglevel") != 0) {
71  const int loglevel = vm["loglevel"].as<int>();
72  logger_set_threshold(static_cast<boost::log::trivial::severity_level>(loglevel));
73  LOG_INFO << "Loglevel set to " << loglevel;
74  } else if (static_cast<int>(vm.count("verbose")) != 0) {
75  logger_set_threshold(boost::log::trivial::debug);
76  LOG_DEBUG << "Debug level debugging enabled";
77  } else if (static_cast<int>(vm.count("quiet")) != 0) {
78  logger_set_threshold(boost::log::trivial::warning);
79  } else {
80  logger_set_threshold(boost::log::trivial::info);
81  }
82  } catch (std::exception &e) {
83  LOG_FATAL << e.what();
84  return EXIT_FAILURE;
85  }
86 
87  Utils::setUserAgent(std::string("garage-deploy/") + garage_tools_version());
88 
89  if (vm.count("dry-run") != 0U) {
90  mode = RunMode::kDryRun;
91  }
92 
93  if (max_curl_requests < 1) {
94  LOG_FATAL << "--jobs must be greater than 0";
95  return EXIT_FAILURE;
96  }
97 
98  ServerCredentials fetch_credentials(fetch_cred);
99  TreehubServer fetch_server;
100  if (authenticate(cacerts, fetch_credentials, fetch_server) != EXIT_SUCCESS) {
101  LOG_FATAL << "Authentication with fetch server failed";
102  return EXIT_FAILURE;
103  }
104 
105  ServerCredentials push_credentials(push_cred);
106  TreehubServer push_server;
107  if (authenticate(cacerts, push_credentials, push_server) != EXIT_SUCCESS) {
108  LOG_FATAL << "Authentication with push server failed";
109  return EXIT_FAILURE;
110  }
111 
112  OSTreeRepo::ptr src_repo = std::make_shared<OSTreeHttpRepo>(&fetch_server);
113  try {
114  OSTreeHash commit(OSTreeHash::Parse(ostree_commit));
115  // Since the fetches happen on a single thread in OSTreeHttpRepo, there
116  // isn't much reason to upload in parallel, but why hold the system back if
117  // the fetching is faster than the uploading?
118  if (!UploadToTreehub(src_repo, push_server, commit, mode, max_curl_requests)) {
119  LOG_FATAL << "Upload to treehub failed";
120  return EXIT_FAILURE;
121  }
122 
123  if (mode == RunMode::kDefault || mode == RunMode::kPushTree) {
124  if (!push_credentials.CanSignOffline()) {
125  LOG_FATAL << "Provided push credentials are missing required components to sign Targets metadata.";
126  return EXIT_FAILURE;
127  }
128  if (!OfflineSignRepo(ServerCredentials(push_credentials.GetPathOnDisk()), name, commit, hardwareids)) {
129  return EXIT_FAILURE;
130  }
131 
132  if (CheckRefValid(push_server, ostree_commit, mode, max_curl_requests) != EXIT_SUCCESS) {
133  LOG_FATAL << "Check if the ref is present on the server or in targets.json failed";
134  return EXIT_FAILURE;
135  }
136  } else {
137  LOG_INFO << "Dry run. Not attempting offline signing.";
138  }
139  } catch (OSTreeCommitParseError &e) {
140  LOG_FATAL << e.what();
141  return EXIT_FAILURE;
142  }
143 
144  auto end_time = std::chrono::system_clock::now();
145  std::chrono::duration<double> diff_time = end_time - start_time;
146  LOG_INFO << "Total runtime: " << diff_time.count() << " seconds.";
147 
148  return EXIT_SUCCESS;
149 }
150 // vim: set tabstop=2 shiftwidth=2 expandtab:
RunMode::kPushTree
@ kPushTree
Walk the entire tree and upload any missing objects.
OSTreeHash
Definition: ostree_hash.h:10
ServerCredentials
Definition: server_credentials.h:25
OSTreeCommitParseError
Definition: ostree_hash.h:30
TreehubServer
Definition: treehub_server.h:11
OSTreeHash::Parse
static OSTreeHash Parse(const std::string &hash)
Parse an OSTree hash from a string.
Definition: ostree_hash.cc:7
garage_common.h
RunMode::kDefault
@ kDefault
Default operation.
RunMode::kDryRun
@ kDryRun
Dry run.
RunMode
RunMode
Execution mode to run garage tools in.
Definition: garage_common.h:6