GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/publish/repository.h
Date: 2026-08-30 02:40:36
Exec Total Coverage
Lines: 0 16 0.0%
Branches: 0 0 -%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5 #ifndef CVMFS_PUBLISH_REPOSITORY_H_
6 #define CVMFS_PUBLISH_REPOSITORY_H_
7
8 #include <memory>
9 #include <string>
10 #include <vector>
11
12 #include "gateway_util.h"
13 #include "history.h" // for History::Tag
14 #include "publish/settings.h"
15 #include "repository_util.h"
16 #include "upload_spooler_result.h"
17 #include "util/single_copy.h"
18
19 namespace catalog {
20 class DeltaCounters;
21 class DirectoryEntry;
22 class SimpleCatalogManager;
23 class WritableCatalogManager;
24 } // namespace catalog
25 namespace download {
26 class DownloadManager;
27 }
28 namespace history {
29 class SqliteHistory;
30 }
31 namespace manifest {
32 class Manifest;
33 class Reflog;
34 } // namespace manifest
35 namespace perf {
36 class Statistics;
37 class StatisticsTemplate;
38 } // namespace perf
39 namespace signature {
40 class SignatureManager;
41 }
42 struct SyncParameters;
43 namespace upload {
44 class Spooler;
45 }
46 namespace whitelist {
47 class Whitelist;
48 }
49
50 namespace publish {
51
52 class SyncMediator;
53 class SyncUnion;
54
55 /**
56 * Users create derived instances to react on repository diffs
57 */
58 class __attribute__((visibility("default"))) DiffListener {
59 public:
60 virtual ~DiffListener() { }
61 virtual void OnInit(const history::History::Tag &from_tag,
62 const history::History::Tag &to_tag) = 0;
63 virtual void OnStats(const catalog::DeltaCounters &delta) = 0;
64 virtual void OnAdd(const std::string &path,
65 const catalog::DirectoryEntry &entry) = 0;
66 virtual void OnRemove(const std::string &path,
67 const catalog::DirectoryEntry &entry) = 0;
68 virtual void OnModify(const std::string &path,
69 const catalog::DirectoryEntry &entry_from,
70 const catalog::DirectoryEntry &entry_to) = 0;
71 };
72
73
74 class __attribute__((visibility("default"))) Env {
75 public:
76 /**
77 * Depending on the desired course of action, the permitted capabilities of
78 * the binary (cap_dac_read_search, cap_sys_admin) needs to be dropped or
79 * gained. Dropped for creating user namespaces in `enter`, gained for walking
80 * through overlayfs.
81 */
82 static void DropCapabilities();
83
84 /**
85 * If in an ephemeral writable shell, return the session directory.
86 * Otherwise return the empty string.
87 */
88 static std::string GetEnterSessionDir();
89 };
90
91
92 class __attribute__((visibility("default"))) Repository : SingleCopy {
93 public:
94 /**
95 * Tag names beginning with @ are interpreted as raw hashes
96 */
97 static const char kRawHashSymbol = '@';
98
99 static std::string GetFqrnFromUrl(const std::string &url);
100
101 explicit Repository(const SettingsRepository &settings,
102 const bool exists = true);
103 virtual ~Repository();
104
105 void Check();
106 void GarbageCollect();
107 void List();
108
109 /**
110 * From and to are either tag names or catalog root hashes preceded by
111 * a '@'.
112 */
113 void Diff(const std::string &from, const std::string &to,
114 DiffListener *diff_listener);
115
116 /**
117 * Checks whether the $url/.cvmfs_master_replica is available
118 */
119 bool IsMasterReplica();
120
121 const signature::SignatureManager *signature_mgr() const {
122 return signature_mgr_;
123 }
124 const whitelist::Whitelist *whitelist() const { return whitelist_; }
125 const manifest::Manifest *manifest() const { return manifest_; }
126 // Inheritance of History and SqliteHistory unknown in the header
127 const history::History *history() const;
128 std::string meta_info() const { return meta_info_; }
129
130 protected:
131 void DownloadRootObjects(const std::string &url,
132 const std::string &fqrn,
133 const std::string &tmp_dir);
134 catalog::SimpleCatalogManager *GetSimpleCatalogManager();
135
136 const SettingsRepository settings_;
137
138 perf::Statistics *statistics_;
139 signature::SignatureManager *signature_mgr_;
140 download::DownloadManager *download_mgr_;
141 /**
142 * The read-only catalog manager, loaded on demand
143 */
144 catalog::SimpleCatalogManager *simple_catalog_mgr_;
145 whitelist::Whitelist *whitelist_;
146 manifest::Reflog *reflog_;
147 manifest::Manifest *manifest_;
148 history::SqliteHistory *history_;
149 // TODO(jblomer): make MetaInfo class
150 std::string meta_info_;
151 };
152
153 class __attribute__((visibility("default"))) Publisher : public Repository {
154 public:
155 /**
156 * Encapsulates operations on a dedicated publisher
157 */
158 class ManagedNode {
159 public:
160 /**
161 * Collection of publisher failure states (see Check())
162 */
163 enum EFailures {
164 kFailOk = 0,
165 kFailRdOnlyBroken = 0x01,
166 kFailRdOnlyOutdated = 0x02,
167 kFailRdOnlyWrongRevision = 0x04,
168 kFailUnionBroken = 0x08,
169 kFailUnionWritable = 0x10,
170 kFailUnionLocked = 0x20,
171 };
172
173 explicit ManagedNode(Publisher *p) : publisher_(p) { }
174 /**
175 * Verifies the mountpoints and the transaction status. Returns a bit map
176 * of EFailures codes.
177 */
178 int Check(bool is_quiet = false);
179 /**
180 * Re-mount /cvmfs/$fqrn read-writable
181 */
182 void Open();
183 /**
184 * Re-mount /cvmfs/$fqrn read-only
185 */
186 void Lock();
187 /**
188 * Regular unmount of the read-write and the read-only layer and, if this
189 * does not work, a forced unmount
190 */
191 void Unmount();
192 /**
193 * Mounts the read-only layer followed by the union layer
194 */
195 void Mount();
196 /**
197 * Move scratch space to waste bin and clear it out asynchronously
198 */
199 void ClearScratch();
200
201 private:
202 /**
203 * Possible state transitions for the cvmfs read-only mountpoint and the
204 * union file system on /cvmfs/$fqrn
205 */
206 enum EMountpointAlterations {
207 kAlterUnionUnmount,
208 kAlterUnionLazyUnmount,
209 kAlterRdOnlyUnmount,
210 kAlterRdOnlyKillUnmount,
211 kAlterRdOnlyLazyUnmount,
212 kAlterUnionMount,
213 kAlterRdOnlyMount,
214 kAlterUnionOpen,
215 kAlterUnionLock,
216 kAlterScratchWipe,
217 };
218
219 void AlterMountpoint(EMountpointAlterations how, int log_level);
220 void SetRootHash(const shash::Any &hash);
221
222 Publisher *publisher_;
223 }; // class ManagedNode
224
225
226 /**
227 * A session encapsulates an active storage (gateway) lease
228 */
229 class Session : ::SingleCopy {
230 public:
231 struct Settings {
232 Settings() : llvl(0) { }
233 std::string service_endpoint;
234 /**
235 * $fqrn/$lease_path
236 */
237 std::string repo_path;
238 std::string gw_key_path;
239 std::string token_path;
240 int llvl;
241 };
242
243 /**
244 * For non-gateway nodes, we have an implicit lease for the entire
245 * repository
246 */
247 Session()
248 : keep_alive_(false), has_lease_(true), negotiated_api_version_(-1) { }
249 explicit Session(const Settings &settings_session);
250 explicit Session(const SettingsPublisher &settings_publisher, int llvl = 0);
251 /**
252 * Drops the lease unless keep_alive_ is set
253 */
254 ~Session();
255
256 void Acquire();
257 void Drop();
258 void SetKeepAlive(bool value);
259
260 bool has_lease() const { return has_lease_; }
261 std::string token_path() const { return settings_.token_path; }
262 std::string api_version_path() const {
263 return gateway::SessionTokenApiVersionPath(settings_.token_path);
264 }
265 /**
266 * The gateway API protocol version negotiated on lease acquisition
267 * (min of the publisher's and the gateway's supported versions). A
268 * pre-existing gateway token restores this value from its sidecar file;
269 * -1 means that an old token has no recorded negotiation.
270 */
271 int negotiated_api_version() const { return negotiated_api_version_; }
272
273 private:
274 Settings settings_;
275 /**
276 * If set to true, the session is not closed on destruction, i.e. the
277 * lease is not dropped and the lease token is not removed. A newly created
278 * Session object will pick up an existing lease token and not re-acquire
279 * it.
280 */
281 bool keep_alive_;
282 bool has_lease_;
283 int negotiated_api_version_;
284 }; // class Session
285
286 /**
287 * The directory layout of the publisher node must be of matching revision
288 */
289 static const unsigned kRequiredLayoutRevision = 143;
290
291 static Publisher *Create(const SettingsPublisher &settings);
292
293 explicit Publisher(const SettingsPublisher &settings,
294 const bool exists = true);
295 virtual ~Publisher();
296
297 void UpdateMetaInfo();
298 void Transaction();
299 void Abort();
300 void Publish();
301 void Ingest();
302 void Sync();
303
304 /**
305 * Automatically exit the ephemeral shell after abort or commit.
306 * TODO(avalenzu): Most of the logic of the enter shell is in the CmdEnter UI
307 * class. We should move at least the core functionality to libcvmfs_server
308 * and this includes the ExitShell() method.
309 */
310 void ExitShell();
311
312 /**
313 * Must not edit magic tags 'trunk' and 'trunk-previous'.
314 * Removal of non-existing tags is silently ignored. The caller needs to
315 * ensure that the data provided in new tags makes sense.
316 */
317 void EditTags(const std::vector<history::History::Tag> &add_tags,
318 const std::vector<std::string> &rm_tags);
319 /**
320 * Edit tags on a gateway repository. The publisher cannot write the tag
321 * database directly, so a lease is acquired and the add/remove is forwarded
322 * to the receiver, which applies it in the commit's history transaction.
323 * The catalog is unchanged, so the commit carries the current root hash as
324 * both old and new hash. Called by EditTags() for gateway storage.
325 */
326 void EditTagsGateway(const std::vector<history::History::Tag> &add_tags,
327 const std::vector<std::string> &rm_tags);
328 /**
329 * Create empty $url/.cvmfs_master_replica
330 */
331 void MarkReplicatible(bool value);
332
333 void Rollback();
334 void Resign();
335 void Migrate();
336
337 const SettingsPublisher &settings() const { return settings_; }
338 const ServerFlagFile &in_transaction() const { return in_transaction_; }
339 const ServerLockFile &is_publishing() const { return is_publishing_; }
340 Session *session() const { return session_.get(); }
341 const upload::Spooler *spooler_files() const { return spooler_files_; }
342 const upload::Spooler *spooler_catalogs() const { return spooler_catalogs_; }
343
344 private:
345 /**
346 * Used just before a spooler is required, e.g. in Create()
347 */
348 void ConstructSpoolers();
349 /**
350 * Initializes the spooler, the writable catalog manager, and the sync
351 * mediator
352 */
353 void ConstructSyncManagers();
354 void WipeScratchArea();
355
356 void CreateKeychain();
357 void CreateStorage();
358 void CreateSpoolArea();
359 void CreateRootObjects();
360
361 void ExportKeychain();
362 void CreateDirectoryAsOwner(const std::string &path, int mode);
363 void InitSpoolArea();
364
365 void PushCertificate();
366 void PushHistory();
367 void PushManifest();
368 void PushMetainfo();
369 void PushReflog();
370 void PushWhitelist();
371
372 void OnProcessCertificate(const upload::SpoolerResult &result);
373 void OnProcessHistory(const upload::SpoolerResult &result);
374 void OnProcessMetainfo(const upload::SpoolerResult &result);
375 void OnUploadManifest(const upload::SpoolerResult &result);
376 void OnUploadReflog(const upload::SpoolerResult &result);
377 void OnUploadWhitelist(const upload::SpoolerResult &result);
378
379 void CheckTagName(const std::string &name);
380
381 void TransactionRetry();
382 void TransactionImpl();
383
384 SettingsPublisher settings_;
385 std::unique_ptr<perf::StatisticsTemplate> statistics_publish_;
386 /**
387 * The log level, set to kLogNone if settings_.is_silent() == true
388 */
389 int llvl_;
390 ServerFlagFile in_transaction_;
391 ServerLockFile is_publishing_;
392 gateway::GatewayKey gw_key_;
393 /**
394 * Only really used gateway mode when a transaction is opened. The session
395 * takes an existing session token if it exists and drops the lease in abort.
396 * TODO(jblomer): that is not yet done. Once publish, tag, etc. are
397 * implemented, the lease should be dropped after the last successful write
398 * operation.
399 */
400 std::unique_ptr<Session> session_;
401 std::unique_ptr<ManagedNode> managed_node_;
402
403 upload::Spooler *spooler_files_;
404 upload::Spooler *spooler_catalogs_;
405 catalog::WritableCatalogManager *catalog_mgr_;
406 SyncParameters *sync_parameters_;
407 SyncMediator *sync_mediator_;
408 publish::SyncUnion *sync_union_;
409 };
410
411 class __attribute__((visibility("default"))) Replica : public Repository {
412 public:
413 static Replica *Create();
414 explicit Replica(const SettingsReplica &settings);
415 virtual ~Replica();
416
417 void Snapshot();
418 };
419
420 } // namespace publish
421
422 #endif // CVMFS_PUBLISH_REPOSITORY_H_
423