GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/notify/cmd_sub.cc
Date: 2025-06-22 02:36:02
Exec Total Coverage
Lines: 0 63 0.0%
Branches: 0 38 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 "cmd_sub.h"
11
12 #include <inttypes.h>
13
14 #include "crypto/signature.h"
15 #include "manifest.h"
16 #include "manifest_fetch.h"
17 #include "network/download.h"
18 #include "notify/messages.h"
19 #include "options.h"
20 #include "subscriber_sse.h"
21 #include "subscriber_supervisor.h"
22 #include "supervisor.h"
23 #include "util/logging.h"
24 #include "util/pointer.h"
25 #include "util/posix.h"
26 #include "util/string.h"
27
28 namespace {
29
30 const LogFacilities &kLogInfo = DefaultLogging::info;
31 const LogFacilities &kLogError = DefaultLogging::error;
32
33 const int kMaxPoolHandles = 1;
34
35 class SwissknifeSubscriber : public notify::SubscriberSSE {
36 public:
37 SwissknifeSubscriber(const std::string &server_url,
38 const std::string &repository, uint64_t min_revision,
39 bool continuous, bool verbose)
40 : notify::SubscriberSSE(server_url)
41 , repository_(repository)
42 , stats_()
43 , dl_mgr_(new download::DownloadManager(
44 kMaxPoolHandles, perf::StatisticsTemplate("download", &stats_)))
45 , sig_mgr_(new signature::SignatureManager())
46 , revision_(min_revision)
47 , continuous_(continuous)
48 , verbose_(verbose) { }
49 virtual ~SwissknifeSubscriber() { sig_mgr_->Fini(); }
50
51 bool Init() {
52 const std::string config_file = "/etc/cvmfs/repositories.d/" + repository_
53 + "/client.conf";
54 SimpleOptionsParser options;
55 if (!options.TryParsePath(config_file)) {
56 LogCvmfs(kLogCvmfs, kLogError,
57 "SwissknifeSubscriber - could not parse configuration file");
58 return false;
59 }
60
61 std::string arg;
62 if (options.GetValue("CVMFS_SERVER_URL", &arg)) {
63 dl_mgr_->SetHostChain(arg);
64 }
65
66 sig_mgr_->Init();
67
68 const std::string public_keys =
69 JoinStrings(FindFilesBySuffix("/etc/cvmfs/keys", ".pub"), ":");
70 if (!sig_mgr_->LoadPublicRsaKeys(public_keys)) {
71 LogCvmfs(kLogCvmfs, kLogError,
72 "SwissknifeSubscriber - could not load public keys");
73 return false;
74 }
75
76 return true;
77 }
78
79 private:
80 virtual notify::Subscriber::Status Consume(const std::string &repo,
81 const std::string &msg_text) {
82 notify::msg::Activity msg;
83 if (!msg.FromJSONString(msg_text)) {
84 LogCvmfs(kLogCvmfs, kLogError,
85 "SwissknifeSubscriber - could not decode message.");
86 return notify::Subscriber::kError;
87 }
88
89 manifest::ManifestEnsemble ensemble;
90 const manifest::Failures res =
91 manifest::Verify(reinterpret_cast<unsigned char *>(&(msg.manifest_[0])),
92 msg.manifest_.size(), "", repo, 0, NULL,
93 sig_mgr_.weak_ref(), dl_mgr_.weak_ref(), &ensemble);
94
95 if (res != manifest::kFailOk) {
96 LogCvmfs(kLogCvmfs, kLogError,
97 "SwissknifeSubscriber - manifest has invalid signature: %d",
98 res);
99 return notify::Subscriber::kError;
100 }
101
102 const UniquePtr<manifest::Manifest> manifest(manifest::Manifest::LoadMem(
103 reinterpret_cast<const unsigned char *>(msg.manifest_.data()),
104 msg.manifest_.size()));
105
106 if (!manifest.IsValid()) {
107 LogCvmfs(kLogCvmfs, kLogError,
108 "SwissknifeSubscriber - could not parse manifest.");
109 return notify::Subscriber::kError;
110 }
111
112 const uint64_t new_revision = manifest->revision();
113 bool triggered = false;
114 if (new_revision > revision_) {
115 LogCvmfs(
116 kLogCvmfs, kLogInfo,
117 "SwissknifeSubscriber - repository %s is now at revision %" PRIu64
118 ".",
119 repo.c_str(), new_revision);
120 if (verbose_) {
121 LogCvmfs(kLogCvmfs, kLogInfo, "%s", msg_text.c_str());
122 }
123 revision_ = new_revision;
124 triggered = true;
125 }
126
127 if (!continuous_ && triggered) {
128 return notify::Subscriber::kFinish;
129 }
130
131 return notify::Subscriber::kContinue;
132 }
133
134 std::string repository_;
135
136 perf::Statistics stats_;
137 UniquePtr<download::DownloadManager> dl_mgr_;
138 UniquePtr<signature::SignatureManager> sig_mgr_;
139
140 uint64_t revision_;
141 bool continuous_;
142 bool verbose_;
143 };
144
145 } // namespace
146
147 namespace notify {
148
149 int DoSubscribe(const std::string &server_url, const std::string &repo,
150 uint64_t min_revision, bool continuous, bool verbose) {
151 SwissknifeSubscriber subscriber(server_url, repo, min_revision, continuous,
152 verbose);
153
154 if (!subscriber.Init()) {
155 LogCvmfs(kLogCvmfs, kLogError, "Could not initialize SwissknifeSubscriber");
156 return 1;
157 }
158
159 // Retry settings: accept no more than 10 failures in the last minute
160 const int num_retries = 10;
161 const uint64_t interval = 60;
162 SubscriberSupervisor supervisor(&subscriber, repo, num_retries, interval);
163 supervisor.Run();
164
165 return 0;
166 }
167
168 } // namespace notify
169