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.head_requests_made() << " HEAD requests and "
54  << request_pool.put_requests_made() << " PUT requests.";
55  LOG_INFO << "Total size of uploaded objects: " << request_pool.total_object_size() << " bytes.";
56  } else {
57  LOG_INFO << "Dry run. No objects uploaded.";
58  }
59  } else {
60  LOG_ERROR << "One or more errors while pushing";
61  }
62 
63  return root_object->is_on_server() == PresenceOnServer::kObjectPresent;
64 }
65 
66 bool OfflineSignRepo(const ServerCredentials &push_credentials, const std::string &name, const OSTreeHash &hash,
67  const std::string &hardwareids) {
68  const boost::filesystem::path local_repo{"./tuf/aktualizr"};
69 
70  // OTA-682: Do NOT keep the local tuf directory around in case the user tries
71  // a different set of push credentials.
72  if (boost::filesystem::is_directory(local_repo)) {
73  boost::filesystem::remove_all(local_repo);
74  }
75 
76  std::string init_cmd("garage-sign init --repo aktualizr --credentials ");
77  if (system((init_cmd + push_credentials.GetPathOnDisk().string()).c_str()) != 0) {
78  LOG_ERROR << "Could not initilaize tuf repo for sign";
79  return false;
80  }
81 
82  if (system("garage-sign targets pull --repo aktualizr") != 0) {
83  LOG_ERROR << "Could not pull targets";
84  return false;
85  }
86 
87  std::string cmd("garage-sign targets add --repo aktualizr --format OSTREE --length 0");
88  cmd += " --name " + name + " --version " + hash.string() + " --sha256 " + hash.string();
89  cmd += " --hardwareids " + hardwareids;
90  if (system(cmd.c_str()) != 0) {
91  LOG_ERROR << "Could not add targets";
92  return false;
93  }
94 
95  LOG_INFO << "Signing...\n";
96  if (system("garage-sign targets sign --key-name targets --repo aktualizr") != 0) {
97  LOG_ERROR << "Could not sign targets";
98  return false;
99  }
100  if (system("garage-sign targets push --repo aktualizr") != 0) {
101  LOG_ERROR << "Could not push signed repo";
102  return false;
103  }
104 
105  boost::filesystem::remove_all(local_repo);
106  LOG_INFO << "Success";
107  return true;
108 }
109 
110 bool PushRootRef(const TreehubServer &push_server, const OSTreeRef &ref) {
111  CurlEasyWrapper easy_handle;
112  curlEasySetoptWrapper(easy_handle.get(), CURLOPT_VERBOSE, get_curlopt_verbose());
113  ref.PushRef(push_server, easy_handle.get());
114  CURLcode err = curl_easy_perform(easy_handle.get());
115  if (err != 0U) {
116  LOG_ERROR << "Error pushing root ref: " << curl_easy_strerror(err);
117  return false;
118  }
119  long rescode; // NOLINT(google-runtime-int)
120  curl_easy_getinfo(easy_handle.get(), CURLINFO_RESPONSE_CODE, &rescode);
121  if (rescode < 200 || rescode >= 400) {
122  LOG_ERROR << "Error pushing root ref, got " << rescode << " HTTP response";
123  return false;
124  }
125 
126  return true;
127 }
CurlEasyWrapper
Definition: utils.h:146
OSTreeObjectMissing
Thrown by GetObject when the object requested is not present in the repository.
Definition: ostree_repo.h:46
RunMode::kPushTree
@ kPushTree
Walk the entire tree and upload any missing objects.
OSTreeHash
Definition: ostree_hash.h:10
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:44
RunMode::kWalkTree
@ kWalkTree
Walk the entire tree (without uploading).
RequestPool::put_requests_made
int put_requests_made()
The number of HEAD + PUT requests that have been sent to curl.
Definition: request_pool.h:36
RequestPool::Loop
void Loop()
One iteration of request-listen loop, launches multiple requests, then listens for the result.
Definition: request_pool.cc:161
TreehubServer
Definition: treehub_server.h:11
RequestPool
Definition: request_pool.h:12
RunMode::kDefault
@ kDefault
Default operation.
RunMode::kDryRun
@ kDryRun
Dry run.
OSTreeRef
Definition: ostree_ref.h:13
RunMode
RunMode
Execution mode to run garage tools in.
Definition: garage_common.h:6