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 |
|
|
} |
25 |
|
|
namespace download { |
26 |
|
|
class DownloadManager; |
27 |
|
|
} |
28 |
|
|
namespace history { |
29 |
|
|
class SqliteHistory; |
30 |
|
|
} |
31 |
|
|
namespace manifest { |
32 |
|
|
class Manifest; |
33 |
|
|
class Reflog; |
34 |
|
|
} |
35 |
|
|
namespace perf { |
36 |
|
|
class Statistics; |
37 |
|
|
class StatisticsTemplate; |
38 |
|
|
} |
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 the |
78 |
|
|
* binary (cap_dac_read_search, cap_sys_admin) needs to be dropped or gained. |
79 |
|
|
* Dropped for creating user namespaces in `enter`, gained for walking through |
80 |
|
|
* 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( |
132 |
|
|
const std::string &url, |
133 |
|
|
const std::string &fqrn, |
134 |
|
|
const std::string &tmp_dir); |
135 |
|
|
catalog::SimpleCatalogManager *GetSimpleCatalogManager(); |
136 |
|
|
|
137 |
|
|
const SettingsRepository settings_; |
138 |
|
|
|
139 |
|
|
perf::Statistics *statistics_; |
140 |
|
|
signature::SignatureManager *signature_mgr_; |
141 |
|
|
download::DownloadManager *download_mgr_; |
142 |
|
|
/** |
143 |
|
|
* The read-only catalog manager, loaded on demand |
144 |
|
|
*/ |
145 |
|
|
catalog::SimpleCatalogManager *simple_catalog_mgr_; |
146 |
|
|
whitelist::Whitelist *whitelist_; |
147 |
|
|
manifest::Reflog *reflog_; |
148 |
|
|
manifest::Manifest *manifest_; |
149 |
|
|
history::SqliteHistory *history_; |
150 |
|
|
// TODO(jblomer): make MetaInfo class |
151 |
|
|
std::string meta_info_; |
152 |
|
|
}; |
153 |
|
|
|
154 |
|
|
class __attribute__((visibility("default"))) Publisher : public Repository { |
155 |
|
|
public: |
156 |
|
|
/** |
157 |
|
|
* Encapsulates operations on a dedicated publisher |
158 |
|
|
*/ |
159 |
|
|
class ManagedNode { |
160 |
|
|
public: |
161 |
|
|
/** |
162 |
|
|
* Collection of publisher failure states (see Check()) |
163 |
|
|
*/ |
164 |
|
|
enum EFailures { |
165 |
|
|
kFailOk = 0, |
166 |
|
|
kFailRdOnlyBroken = 0x01, |
167 |
|
|
kFailRdOnlyOutdated = 0x02, |
168 |
|
|
kFailRdOnlyWrongRevision = 0x04, |
169 |
|
|
kFailUnionBroken = 0x08, |
170 |
|
|
kFailUnionWritable = 0x10, |
171 |
|
|
kFailUnionLocked = 0x20, |
172 |
|
|
}; |
173 |
|
|
|
174 |
|
✗ |
explicit ManagedNode(Publisher *p) : publisher_(p) {} |
175 |
|
|
/** |
176 |
|
|
* Verifies the mountpoints and the transaction status. Returns a bit map |
177 |
|
|
* of EFailures codes. |
178 |
|
|
*/ |
179 |
|
|
int Check(bool is_quiet = false); |
180 |
|
|
/** |
181 |
|
|
* Re-mount /cvmfs/$fqrn read-writable |
182 |
|
|
*/ |
183 |
|
|
void Open(); |
184 |
|
|
/** |
185 |
|
|
* Re-mount /cvmfs/$fqrn read-only |
186 |
|
|
*/ |
187 |
|
|
void Lock(); |
188 |
|
|
/** |
189 |
|
|
* Regular unmount of the read-write and the read-only layer and, if this |
190 |
|
|
* does not work, a forced unmount |
191 |
|
|
*/ |
192 |
|
|
void Unmount(); |
193 |
|
|
/** |
194 |
|
|
* Mounts the read-only layer followed by the union layer |
195 |
|
|
*/ |
196 |
|
|
void Mount(); |
197 |
|
|
/** |
198 |
|
|
* Move scratch space to waste bin and clear it out asynchronously |
199 |
|
|
*/ |
200 |
|
|
void ClearScratch(); |
201 |
|
|
|
202 |
|
|
private: |
203 |
|
|
/** |
204 |
|
|
* Possible state transitions for the cvmfs read-only mountpoint and the |
205 |
|
|
* union file system on /cvmfs/$fqrn |
206 |
|
|
*/ |
207 |
|
|
enum EMountpointAlterations { |
208 |
|
|
kAlterUnionUnmount, |
209 |
|
|
kAlterUnionLazyUnmount, |
210 |
|
|
kAlterRdOnlyUnmount, |
211 |
|
|
kAlterRdOnlyKillUnmount, |
212 |
|
|
kAlterRdOnlyLazyUnmount, |
213 |
|
|
kAlterUnionMount, |
214 |
|
|
kAlterRdOnlyMount, |
215 |
|
|
kAlterUnionOpen, |
216 |
|
|
kAlterUnionLock, |
217 |
|
|
kAlterScratchWipe, |
218 |
|
|
}; |
219 |
|
|
|
220 |
|
|
void AlterMountpoint(EMountpointAlterations how, int log_level); |
221 |
|
|
void SetRootHash(const shash::Any &hash); |
222 |
|
|
|
223 |
|
|
Publisher *publisher_; |
224 |
|
|
}; // class ManagedNode |
225 |
|
|
|
226 |
|
|
|
227 |
|
|
/** |
228 |
|
|
* A session encapsulates an active storage (gateway) lease |
229 |
|
|
*/ |
230 |
|
|
class Session : ::SingleCopy { |
231 |
|
|
public: |
232 |
|
|
struct Settings { |
233 |
|
✗ |
Settings() : llvl(0) {} |
234 |
|
|
std::string service_endpoint; |
235 |
|
|
/** |
236 |
|
|
* $fqrn/$lease_path |
237 |
|
|
*/ |
238 |
|
|
std::string repo_path; |
239 |
|
|
std::string gw_key_path; |
240 |
|
|
std::string token_path; |
241 |
|
|
int llvl; |
242 |
|
|
}; |
243 |
|
|
|
244 |
|
|
/** |
245 |
|
|
* For non-gateway nodes, we have an implicit lease for the entire |
246 |
|
|
* repository |
247 |
|
|
*/ |
248 |
|
|
Session() : keep_alive_(false), has_lease_(true) {} |
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 |
|
|
|
263 |
|
|
private: |
264 |
|
|
Settings settings_; |
265 |
|
|
/** |
266 |
|
|
* If set to true, the session is not closed on destruction, i.e. the |
267 |
|
|
* lease is not dropped and the lease token is not removed. A newly created |
268 |
|
|
* Session object will pick up an existing lease token and not re-acquire |
269 |
|
|
* it. |
270 |
|
|
*/ |
271 |
|
|
bool keep_alive_; |
272 |
|
|
bool has_lease_; |
273 |
|
|
}; // class Session |
274 |
|
|
|
275 |
|
|
/** |
276 |
|
|
* The directory layout of the publisher node must be of matching revision |
277 |
|
|
*/ |
278 |
|
|
static const unsigned kRequiredLayoutRevision = 143; |
279 |
|
|
|
280 |
|
|
static Publisher *Create(const SettingsPublisher &settings); |
281 |
|
|
|
282 |
|
|
explicit Publisher(const SettingsPublisher &settings, |
283 |
|
|
const bool exists = true); |
284 |
|
|
virtual ~Publisher(); |
285 |
|
|
|
286 |
|
|
void UpdateMetaInfo(); |
287 |
|
|
void Transaction(); |
288 |
|
|
void Abort(); |
289 |
|
|
void Publish(); |
290 |
|
|
void Ingest(); |
291 |
|
|
void Sync(); |
292 |
|
|
|
293 |
|
|
/** |
294 |
|
|
* Automatically exit the ephemeral shell after abort or commit. |
295 |
|
|
* TODO(avalenzu): Most of the logic of the enter shell is in the CmdEnter UI class. |
296 |
|
|
* We should move at least the core functionality to libcvmfs_server and this includes |
297 |
|
|
* the ExitShell() method. |
298 |
|
|
*/ |
299 |
|
|
void ExitShell(); |
300 |
|
|
|
301 |
|
|
/** |
302 |
|
|
* Must not edit magic tags 'trunk' and 'trunk-previous'. |
303 |
|
|
* Removal of non-existing tags is silently ignored. The caller needs to |
304 |
|
|
* ensure that the data provided in new tags makes sense. |
305 |
|
|
*/ |
306 |
|
|
void EditTags(const std::vector<history::History::Tag> &add_tags, |
307 |
|
|
const std::vector<std::string> &rm_tags); |
308 |
|
|
/** |
309 |
|
|
* Create empty $url/.cvmfs_master_replica |
310 |
|
|
*/ |
311 |
|
|
void MarkReplicatible(bool value); |
312 |
|
|
|
313 |
|
|
void Rollback(); |
314 |
|
|
void Resign(); |
315 |
|
|
void Migrate(); |
316 |
|
|
|
317 |
|
✗ |
const SettingsPublisher &settings() const { return settings_; } |
318 |
|
✗ |
const ServerFlagFile &in_transaction() const { return in_transaction_; } |
319 |
|
|
const ServerLockFile &is_publishing() const { return is_publishing_; } |
320 |
|
✗ |
Session *session() const { return session_.weak_ref(); } |
321 |
|
|
const upload::Spooler *spooler_files() const { return spooler_files_; } |
322 |
|
|
const upload::Spooler *spooler_catalogs() const { return spooler_catalogs_; } |
323 |
|
|
|
324 |
|
|
private: |
325 |
|
|
/** |
326 |
|
|
* Used just before a spooler is required, e.g. in Create() |
327 |
|
|
*/ |
328 |
|
|
void ConstructSpoolers(); |
329 |
|
|
/** |
330 |
|
|
* Initializes the spooler, the writable catalog manager, and the sync |
331 |
|
|
* mediator |
332 |
|
|
*/ |
333 |
|
|
void ConstructSyncManagers(); |
334 |
|
|
void WipeScratchArea(); |
335 |
|
|
|
336 |
|
|
void CreateKeychain(); |
337 |
|
|
void CreateStorage(); |
338 |
|
|
void CreateSpoolArea(); |
339 |
|
|
void CreateRootObjects(); |
340 |
|
|
|
341 |
|
|
void ExportKeychain(); |
342 |
|
|
void CreateDirectoryAsOwner(const std::string &path, int mode); |
343 |
|
|
void InitSpoolArea(); |
344 |
|
|
|
345 |
|
|
void PushCertificate(); |
346 |
|
|
void PushHistory(); |
347 |
|
|
void PushManifest(); |
348 |
|
|
void PushMetainfo(); |
349 |
|
|
void PushReflog(); |
350 |
|
|
void PushWhitelist(); |
351 |
|
|
|
352 |
|
|
void OnProcessCertificate(const upload::SpoolerResult &result); |
353 |
|
|
void OnProcessHistory(const upload::SpoolerResult &result); |
354 |
|
|
void OnProcessMetainfo(const upload::SpoolerResult &result); |
355 |
|
|
void OnUploadManifest(const upload::SpoolerResult &result); |
356 |
|
|
void OnUploadReflog(const upload::SpoolerResult &result); |
357 |
|
|
void OnUploadWhitelist(const upload::SpoolerResult &result); |
358 |
|
|
|
359 |
|
|
void CheckTagName(const std::string &name); |
360 |
|
|
|
361 |
|
|
void TransactionRetry(); |
362 |
|
|
void TransactionImpl(bool waiting_on_lease=false); |
363 |
|
|
|
364 |
|
|
SettingsPublisher settings_; |
365 |
|
|
UniquePtr<perf::StatisticsTemplate> statistics_publish_; |
366 |
|
|
/** |
367 |
|
|
* The log level, set to kLogNone if settings_.is_silent() == true |
368 |
|
|
*/ |
369 |
|
|
int llvl_; |
370 |
|
|
ServerFlagFile in_transaction_; |
371 |
|
|
ServerLockFile is_publishing_; |
372 |
|
|
gateway::GatewayKey gw_key_; |
373 |
|
|
/** |
374 |
|
|
* Only really used gateway mode when a transaction is opened. The session |
375 |
|
|
* takes an existing session token if it exists and drops the lease in abort. |
376 |
|
|
* TODO(jblomer): that is not yet done. Once publish, tag, etc. are |
377 |
|
|
* implemented, the lease should be dropped after the last successful write |
378 |
|
|
* operation. |
379 |
|
|
*/ |
380 |
|
|
UniquePtr<Session> session_; |
381 |
|
|
UniquePtr<ManagedNode> managed_node_; |
382 |
|
|
|
383 |
|
|
upload::Spooler *spooler_files_; |
384 |
|
|
upload::Spooler *spooler_catalogs_; |
385 |
|
|
catalog::WritableCatalogManager *catalog_mgr_; |
386 |
|
|
SyncParameters *sync_parameters_; |
387 |
|
|
SyncMediator *sync_mediator_; |
388 |
|
|
publish::SyncUnion *sync_union_; |
389 |
|
|
}; |
390 |
|
|
|
391 |
|
|
class __attribute__((visibility("default"))) Replica : public Repository { |
392 |
|
|
public: |
393 |
|
|
static Replica *Create(); |
394 |
|
|
explicit Replica(const SettingsReplica &settings); |
395 |
|
|
virtual ~Replica(); |
396 |
|
|
|
397 |
|
|
void Snapshot(); |
398 |
|
|
}; |
399 |
|
|
|
400 |
|
|
} // namespace publish |
401 |
|
|
|
402 |
|
|
#endif // CVMFS_PUBLISH_REPOSITORY_H_ |
403 |
|
|
|