GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/publish/repository.h
Date: 2025-06-22 02:36:02
Exec Total Coverage
Lines: 0 13 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 <string>
9 #include <vector>
10
11 #include "gateway_util.h"
12 #include "history.h" // for History::Tag
13 #include "publish/settings.h"
14 #include "repository_util.h"
15 #include "upload_spooler_result.h"
16 #include "util/pointer.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 class 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() : keep_alive_(false), has_lease_(true) { }
248 explicit Session(const Settings &settings_session);
249 explicit Session(const SettingsPublisher &settings_publisher, int llvl = 0);
250 /**
251 * Drops the lease unless keep_alive_ is set
252 */
253 ~Session();
254
255 void Acquire();
256 void Drop();
257 void SetKeepAlive(bool value);
258
259 bool has_lease() const { return has_lease_; }
260 std::string token_path() const { return settings_.token_path; }
261
262 private:
263 Settings settings_;
264 /**
265 * If set to true, the session is not closed on destruction, i.e. the
266 * lease is not dropped and the lease token is not removed. A newly created
267 * Session object will pick up an existing lease token and not re-acquire
268 * it.
269 */
270 bool keep_alive_;
271 bool has_lease_;
272 }; // class Session
273
274 /**
275 * The directory layout of the publisher node must be of matching revision
276 */
277 static const unsigned kRequiredLayoutRevision = 143;
278
279 static Publisher *Create(const SettingsPublisher &settings);
280
281 explicit Publisher(const SettingsPublisher &settings,
282 const bool exists = true);
283 virtual ~Publisher();
284
285 void UpdateMetaInfo();
286 void Transaction();
287 void Abort();
288 void Publish();
289 void Ingest();
290 void Sync();
291
292 /**
293 * Automatically exit the ephemeral shell after abort or commit.
294 * TODO(avalenzu): Most of the logic of the enter shell is in the CmdEnter UI
295 * class. We should move at least the core functionality to libcvmfs_server
296 * and this includes the ExitShell() method.
297 */
298 void ExitShell();
299
300 /**
301 * Must not edit magic tags 'trunk' and 'trunk-previous'.
302 * Removal of non-existing tags is silently ignored. The caller needs to
303 * ensure that the data provided in new tags makes sense.
304 */
305 void EditTags(const std::vector<history::History::Tag> &add_tags,
306 const std::vector<std::string> &rm_tags);
307 /**
308 * Create empty $url/.cvmfs_master_replica
309 */
310 void MarkReplicatible(bool value);
311
312 void Rollback();
313 void Resign();
314 void Migrate();
315
316 const SettingsPublisher &settings() const { return settings_; }
317 const ServerFlagFile &in_transaction() const { return in_transaction_; }
318 const ServerLockFile &is_publishing() const { return is_publishing_; }
319 Session *session() const { return session_.weak_ref(); }
320 const upload::Spooler *spooler_files() const { return spooler_files_; }
321 const upload::Spooler *spooler_catalogs() const { return spooler_catalogs_; }
322
323 private:
324 /**
325 * Used just before a spooler is required, e.g. in Create()
326 */
327 void ConstructSpoolers();
328 /**
329 * Initializes the spooler, the writable catalog manager, and the sync
330 * mediator
331 */
332 void ConstructSyncManagers();
333 void WipeScratchArea();
334
335 void CreateKeychain();
336 void CreateStorage();
337 void CreateSpoolArea();
338 void CreateRootObjects();
339
340 void ExportKeychain();
341 void CreateDirectoryAsOwner(const std::string &path, int mode);
342 void InitSpoolArea();
343
344 void PushCertificate();
345 void PushHistory();
346 void PushManifest();
347 void PushMetainfo();
348 void PushReflog();
349 void PushWhitelist();
350
351 void OnProcessCertificate(const upload::SpoolerResult &result);
352 void OnProcessHistory(const upload::SpoolerResult &result);
353 void OnProcessMetainfo(const upload::SpoolerResult &result);
354 void OnUploadManifest(const upload::SpoolerResult &result);
355 void OnUploadReflog(const upload::SpoolerResult &result);
356 void OnUploadWhitelist(const upload::SpoolerResult &result);
357
358 void CheckTagName(const std::string &name);
359
360 void TransactionRetry();
361 void TransactionImpl(bool waiting_on_lease = false);
362
363 SettingsPublisher settings_;
364 UniquePtr<perf::StatisticsTemplate> statistics_publish_;
365 /**
366 * The log level, set to kLogNone if settings_.is_silent() == true
367 */
368 int llvl_;
369 ServerFlagFile in_transaction_;
370 ServerLockFile is_publishing_;
371 gateway::GatewayKey gw_key_;
372 /**
373 * Only really used gateway mode when a transaction is opened. The session
374 * takes an existing session token if it exists and drops the lease in abort.
375 * TODO(jblomer): that is not yet done. Once publish, tag, etc. are
376 * implemented, the lease should be dropped after the last successful write
377 * operation.
378 */
379 UniquePtr<Session> session_;
380 UniquePtr<ManagedNode> managed_node_;
381
382 upload::Spooler *spooler_files_;
383 upload::Spooler *spooler_catalogs_;
384 catalog::WritableCatalogManager *catalog_mgr_;
385 SyncParameters *sync_parameters_;
386 SyncMediator *sync_mediator_;
387 publish::SyncUnion *sync_union_;
388 };
389
390 class __attribute__((visibility("default"))) Replica : public Repository {
391 public:
392 static Replica *Create();
393 explicit Replica(const SettingsReplica &settings);
394 virtual ~Replica();
395
396 void Snapshot();
397 };
398
399 } // namespace publish
400
401 #endif // CVMFS_PUBLISH_REPOSITORY_H_
402