GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/notification_client.cc
Date: 2024-04-21 02:33:16
Exec Total Coverage
Lines: 0 72 0.0%
Branches: 0 75 0.0%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5 #ifndef __STDC_FORMAT_MACROS
6 // NOLINTNEXTLINE
7 #define __STDC_FORMAT_MACROS
8 #endif
9
10 #include "notification_client.h"
11
12 #include <inttypes.h>
13
14 #include <string>
15 #include <vector>
16
17 #include "crypto/signature.h"
18 #include "manifest.h"
19 #include "manifest_fetch.h"
20 #include "notify/messages.h"
21 #include "notify/subscriber_sse.h"
22 #include "notify/subscriber_supervisor.h"
23 #include "supervisor.h"
24 #include "util/logging.h"
25 #include "util/posix.h"
26
27 namespace {
28
29 class ActivitySubscriber : public notify::SubscriberSSE {
30 public:
31 ActivitySubscriber(const std::string& server_url, FuseRemounter* remounter,
32 download::DownloadManager* dl_mgr,
33 signature::SignatureManager* sig_mgr)
34 : SubscriberSSE(server_url),
35 remounter_(remounter),
36 dl_mgr_(dl_mgr),
37 sig_mgr_(sig_mgr) {}
38
39 virtual ~ActivitySubscriber() {}
40
41 virtual notify::Subscriber::Status Consume(const std::string& repo_name,
42 const std::string& msg_text) {
43 notify::msg::Activity msg;
44 if (!msg.FromJSONString(msg_text)) {
45 LogCvmfs(kLogCvmfs, kLogSyslogErr,
46 "NotificationClient - could not decode message.");
47 return notify::Subscriber::kError;
48 }
49
50 manifest::ManifestEnsemble ensemble;
51 manifest::Failures res =
52 manifest::Verify(reinterpret_cast<unsigned char*>(&(msg.manifest_[0])),
53 msg.manifest_.size(), "",
54 repo_name, 0, NULL, sig_mgr_, dl_mgr_, &ensemble);
55
56 if (res != manifest::kFailOk) {
57 LogCvmfs(kLogCvmfs, kLogSyslogErr,
58 "NotificationClient - manifest has invalid signature.");
59 return notify::Subscriber::kError;
60 }
61
62 const UniquePtr<manifest::Manifest> manifest(manifest::Manifest::LoadMem(
63 reinterpret_cast<const unsigned char*>(msg.manifest_.data()),
64 msg.manifest_.size()));
65
66 if (!manifest.IsValid()) {
67 LogCvmfs(kLogCvmfs, kLogSyslogErr,
68 "NotificationClient - could not parse manifest.");
69 return notify::Subscriber::kError;
70 }
71
72 uint64_t new_revision = manifest->revision();
73 LogCvmfs(kLogCvmfs, kLogSyslog,
74 "NotificationClient - repository %s is now at revision %" PRIu64
75 ", root hash: %s", repo_name.c_str(), new_revision,
76 manifest->catalog_hash().ToString().c_str());
77
78 FuseRemounter::Status status = remounter_->CheckSynchronously();
79 switch (status) {
80 case FuseRemounter::kStatusFailGeneral:
81 LogCvmfs(kLogCvmfs, kLogSyslog, "NotificationClient - remount failed");
82 break;
83 case FuseRemounter::kStatusFailNoSpace:
84 LogCvmfs(kLogCvmfs, kLogSyslog,
85 "NotificationClient - remount failed (no space)");
86 break;
87 case FuseRemounter::kStatusUp2Date:
88 LogCvmfs(kLogCvmfs, kLogSyslog,
89 "NotificationClient - catalog up to date");
90 break;
91 case FuseRemounter::kStatusMaintenance:
92 LogCvmfs(kLogCvmfs, kLogSyslog,
93 "NotificationClient - in maintenance mode");
94 break;
95 default:
96 LogCvmfs(kLogCvmfs, kLogSyslog, "NotificationClient - internal error");
97 }
98 return notify::Subscriber::kContinue;
99 }
100
101 private:
102 FuseRemounter* remounter_;
103 download::DownloadManager* dl_mgr_;
104 signature::SignatureManager* sig_mgr_;
105 };
106
107 } // namespace
108
109 NotificationClient::NotificationClient(const std::string& config,
110 const std::string& repo_name,
111 FuseRemounter* remounter,
112 download::DownloadManager* dl_mgr,
113 signature::SignatureManager* sig_mgr)
114 : config_(config),
115 repo_name_(repo_name),
116 remounter_(remounter),
117 dl_mgr_(dl_mgr),
118 sig_mgr_(sig_mgr),
119 subscriber_(),
120 thread_(),
121 spawned_(false) {}
122
123 NotificationClient::~NotificationClient() {
124 if (subscriber_.IsValid()) {
125 subscriber_->Unsubscribe();
126 }
127 if (spawned_) {
128 pthread_join(thread_, NULL);
129 spawned_ = false;
130 }
131 }
132
133 void NotificationClient::Spawn() {
134 if (!spawned_) {
135 if (pthread_create(&thread_, NULL, NotificationClient::Run, this)) {
136 LogCvmfs(kLogCvmfs, kLogSyslogErr,
137 "NotificationClient - Could not start background thread");
138 }
139 spawned_ = true;
140 }
141 }
142
143 void* NotificationClient::Run(void* data) {
144 NotificationClient* cl = static_cast<NotificationClient*>(data);
145
146 cl->subscriber_ = new ActivitySubscriber(cl->config_, cl->remounter_,
147 cl->dl_mgr_, cl->sig_mgr_);
148
149 LogCvmfs(
150 kLogCvmfs, kLogSyslog,
151 "NotificationClient - Entering subscription loop for repository: %s.",
152 cl->repo_name_.c_str());
153
154 // Retry settings: accept no more than 10 failures in the last minute
155 const int num_retries = 10;
156 const uint64_t interval = 60;
157 notify::SubscriberSupervisor supervisor(
158 cl->subscriber_.weak_ref(), cl->repo_name_, num_retries, interval);
159 supervisor.Run();
160
161 return NULL;
162 }
163