Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
deploy.cc
1 #include "deploy.h"
2 
3 #include <boost/filesystem.hpp>
4 #include <boost/intrusive_ptr.hpp>
5 
6 #include "authenticate.h"
7 #include "logging/logging.h"
8 #include "ostree_object.h"
9 #include "rate_controller.h"
10 #include "request_pool.h"
11 #include "treehub_server.h"
12 #include "utilities/utils.h"
13 
14 bool CheckPoolState(const OSTreeObject::ptr &root_object, const RequestPool &request_pool) {
15  switch (request_pool.run_mode()) {
16  case RunMode::kWalkTree:
17  case RunMode::kPushTree:
18  return !request_pool.is_stopped() && !request_pool.is_idle();
19  case RunMode::kDefault:
20  case RunMode::kDryRun:
21  default:
22  return root_object->is_on_server() != PresenceOnServer::kObjectPresent && !request_pool.is_stopped();
23  }
24 }
25 
26 bool UploadToTreehub(const OSTreeRepo::ptr &src_repo, TreehubServer &push_server, const OSTreeHash &ostree_commit,
27  const RunMode mode, const int max_curl_requests) {
28  assert(max_curl_requests > 0);
29 
30  OSTreeObject::ptr root_object;
31  try {
32  root_object = src_repo->GetObject(ostree_commit, OstreeObjectType::OSTREE_OBJECT_TYPE_COMMIT);
33  } catch (const OSTreeObjectMissing &error) {
34  LOG_FATAL << "OSTree commit " << ostree_commit << " was not found in src repository";
35  return false;
36  }
37 
38  RequestPool request_pool(push_server, max_curl_requests, mode);
39 
40  // Add commit object to the queue.
41  request_pool.AddQuery(root_object);
42 
43  // Main curl event loop.
44  // request_pool takes care of holding number of outstanding requests below.
45  // OSTreeObject::CurlDone() adds new requests to the pool and stops the pool
46  // on error.
47  do {
48  request_pool.Loop();
49  } while (CheckPoolState(root_object, request_pool));
50 
51  if (root_object->is_on_server() == PresenceOnServer::kObjectPresent) {
52  if (mode == RunMode::kDefault || mode == RunMode::kPushTree) {
53  LOG_INFO << "Upload to Treehub complete after " << request_pool.total_requests_made() << " requests";
54  } else {
55  LOG_INFO << "Dry run. No objects uploaded.";
56  }
57  } else {
58  LOG_ERROR << "One or more errors while pushing";
59  }
60 
61  return root_object->is_on_server() == PresenceOnServer::kObjectPresent;
62 }
63 
64 bool OfflineSignRepo(const ServerCredentials &push_credentials, const std::string &name, const OSTreeHash &hash,
65  const std::string &hardwareids) {
66  const boost::filesystem::path local_repo{"./tuf/aktualizr"};
67 
68  // OTA-682: Do NOT keep the local tuf directory around in case the user tries
69  // a different set of push credentials.
70  if (boost::filesystem::is_directory(local_repo)) {
71  boost::filesystem::remove_all(local_repo);
72  }
73 
74  std::string init_cmd("garage-sign init --repo aktualizr --credentials ");
75  if (system((init_cmd + push_credentials.GetPathOnDisk().string()).c_str()) != 0) {
76  LOG_ERROR << "Could not initilaize tuf repo for sign";
77  return false;
78  }
79 
80  if (system("garage-sign targets pull --repo aktualizr") != 0) {
81  LOG_ERROR << "Could not pull targets";
82  return false;
83  }
84 
85  std::string cmd("garage-sign targets add --repo aktualizr --format OSTREE --length 0");
86  cmd += " --name " + name + " --version " + hash.string() + " --sha256 " + hash.string();
87  cmd += " --hardwareids " + hardwareids;
88  if (system(cmd.c_str()) != 0) {
89  LOG_ERROR << "Could not add targets";
90  return false;
91  }
92 
93  LOG_INFO << "Signing...\n";
94  if (system("garage-sign targets sign --key-name targets --repo aktualizr") != 0) {
95  LOG_ERROR << "Could not sign targets";
96  return false;
97  }
98  if (system("garage-sign targets push --repo aktualizr") != 0) {
99  LOG_ERROR << "Could not push signed repo";
100  return false;
101  }
102 
103  boost::filesystem::remove_all(local_repo);
104  LOG_INFO << "Success";
105  return true;
106 }
107 
108 bool PushRootRef(const TreehubServer &push_server, const OSTreeRef &ref) {
109  CurlEasyWrapper easy_handle;
110  curlEasySetoptWrapper(easy_handle.get(), CURLOPT_VERBOSE, get_curlopt_verbose());
111  ref.PushRef(push_server, easy_handle.get());
112  CURLcode err = curl_easy_perform(easy_handle.get());
113  if (err != 0U) {
114  LOG_ERROR << "Error pushing root ref: " << curl_easy_strerror(err);
115  return false;
116  }
117  long rescode; // NOLINT(google-runtime-int)
118  curl_easy_getinfo(easy_handle.get(), CURLINFO_RESPONSE_CODE, &rescode);
119  if (rescode < 200 || rescode >= 400) {
120  LOG_ERROR << "Error pushing root ref, got " << rescode << " HTTP response";
121  return false;
122  }
123 
124  return true;
125 }
CurlEasyWrapper
Definition: utils.h:168
OSTreeObjectMissing
Thrown by GetObject when the object requested is not present in the repository.
Definition: ostree_repo.h:45
RunMode::kPushTree
Walk the entire tree and upload any missing objects.
OSTreeHash
Definition: ostree_hash.h:9
ServerCredentials
Definition: server_credentials.h:25
ServerCredentials::GetPathOnDisk
boost::filesystem::path GetPathOnDisk() const
Path to the original credentials.zip on disk.
Definition: server_credentials.h:43
RunMode::kWalkTree
Walk the entire tree (without uploading).
RequestPool::Loop
void Loop()
One iteration of request-listen loop, launches multiple requests, then listens for the result.
Definition: request_pool.cc:158
TreehubServer
Definition: treehub_server.h:11
RequestPool
Definition: request_pool.h:12
RunMode::kDefault
Default operation.
RequestPool::total_requests_made
int total_requests_made()
The number of HEAD + PUT requests that have been sent to curl.
Definition: request_pool.h:36
RunMode::kDryRun
Dry run.
OSTreeRef
Definition: ostree_ref.h:13
RunMode
RunMode
Execution mode to run garage tools in.
Definition: garage_common.h:6