CernVM-FS  2.13.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
repository_managed.cc
Go to the documentation of this file.
1 
6 #include <cstdio>
7 
8 #include "crypto/hash.h"
9 #include "manifest.h"
10 #include "publish/except.h"
11 #include "publish/repository.h"
13 #include "upload.h"
15 #include "util/pointer.h"
16 #include "util/posix.h"
17 #include "util/string.h"
18 
19 
20 namespace publish {
21 
24 }
25 
26 
29 }
30 
31 
33  try {
35  } catch (const EPublish &e) {
39  return;
40  }
41 
42  try {
44  } catch (const EPublish &e) {
47  }
48 }
49 
53 }
54 
56  const std::string scratch_dir = publisher_->settings_.transaction()
57  .spool_area()
58  .scratch_dir();
59  const std::string scratch_wastebin = publisher_->settings_.transaction()
60  .spool_area()
61  .scratch_wastebin();
62  const std::string
63  tmp_dir = publisher_->settings_.transaction().spool_area().tmp_dir();
64 
65  std::string waste_dir = CreateTempDir(scratch_wastebin + "/waste");
66  if (waste_dir.empty())
67  throw EPublish("cannot create wastebin directory");
68  int rvi = rename(scratch_dir.c_str(), (waste_dir + "/delete-me").c_str());
69  if (rvi != 0)
70  throw EPublish("cannot move scratch directory to wastebin");
71 
72  publisher_->CreateDirectoryAsOwner(scratch_dir, kDefaultDirMode);
73 
75 
76  std::vector<mode_t> modes;
77  std::vector<std::string> names;
78  ListDirectory(tmp_dir, &names, &modes);
79  for (unsigned i = 0; i < names.size(); ++i) {
80  if (HasPrefix(names[i], "receiver.", false /* ignore_case */))
81  continue;
82 
83  unlink((tmp_dir + "/" + names[i]).c_str());
84  }
85 }
86 
87 
88 int Publisher::ManagedNode::Check(bool is_quiet) {
89  ServerLockFileCheck publish_check(publisher_->is_publishing_);
90  const std::string rdonly_mnt = publisher_->settings_.transaction()
91  .spool_area()
92  .readonly_mnt();
93  const std::string
94  union_mnt = publisher_->settings_.transaction().spool_area().union_mnt();
95  const std::string fqrn = publisher_->settings_.fqrn();
96  EUnionMountRepairMode repair_mode = publisher_->settings_.transaction()
97  .spool_area()
98  .repair_mode();
99 
100  int result = kFailOk;
101 
102  shash::Any expected_hash = publisher_->manifest()->catalog_hash();
104  publisher_->settings_.transaction().spool_area().checkout_marker()));
105  if (marker.IsValid())
106  expected_hash = marker->hash();
107 
108  if (!IsMountPoint(rdonly_mnt)) {
109  result |= kFailRdOnlyBroken;
110  } else {
111  const std::string root_hash_xattr = "user.root_hash";
112  std::string root_hash_str;
113  bool retval = platform_getxattr(rdonly_mnt, root_hash_xattr,
114  &root_hash_str);
115  if (retval) {
116  shash::Any root_hash = shash::MkFromHexPtr(shash::HexPtr(root_hash_str),
118  if (expected_hash != root_hash) {
119  if (marker.IsValid()) {
120  result |= kFailRdOnlyWrongRevision;
121  } else {
122  result |= kFailRdOnlyOutdated;
123  }
124  }
125  } else {
126  if (errno == ENOTCONN) {
127  // Fuse module crashed
128  result |= kFailRdOnlyBroken;
129  } else {
130  throw EPublish("cannot retrieve root hash from read-only mount point");
131  }
132  }
133  }
134 
135  // The process that opens the transaction does not stay alive for the life
136  // time of the transaction
137  if (!IsMountPoint(union_mnt)) {
138  result |= kFailUnionBroken;
139  } else {
140  FileSystemInfo fs_info = GetFileSystemInfo(union_mnt);
141  if (publisher_->in_transaction_.IsSet() && fs_info.is_rdonly)
142  result |= kFailUnionLocked;
143  if (!publisher_->in_transaction_.IsSet() && !fs_info.is_rdonly)
144  result |= kFailUnionWritable;
145  }
146 
147  if (result == kFailOk)
148  return result;
149 
150  // Report & Repair
151 
152  int logFlags = kLogStderr;
153  if (is_quiet)
154  logFlags |= kLogNone;
155  if (result & kFailRdOnlyBroken) {
156  LogCvmfs(kLogCvmfs, logFlags, "%s is not mounted properly",
157  rdonly_mnt.c_str());
158  }
159  if (result & kFailRdOnlyOutdated) {
160  LogCvmfs(kLogCvmfs, logFlags,
161  "%s is not based on the newest published revision", fqrn.c_str());
162  }
163  if (result & kFailRdOnlyWrongRevision) {
164  LogCvmfs(kLogCvmfs, logFlags, "%s is not based on the checked out revision",
165  fqrn.c_str());
166  }
167  if (result & kFailUnionBroken) {
168  LogCvmfs(kLogCvmfs, logFlags, "%s is not mounted properly",
169  union_mnt.c_str());
170  }
171  if (result & kFailUnionWritable) {
172  LogCvmfs(kLogCvmfs, logFlags,
173  "%s is not in a transaction but %s is mounted read/write",
174  fqrn.c_str(), union_mnt.c_str());
175  }
176  if (result & kFailUnionLocked) {
177  LogCvmfs(kLogCvmfs, logFlags,
178  "%s is in a transaction but %s is not mounted read/write",
179  fqrn.c_str(), union_mnt.c_str());
180  }
181 
182  // Check whether we can repair
183 
184  switch (repair_mode) {
186  return result;
188  break;
190  if (!publish_check.owns_lock()) {
191  LogCvmfs(
192  kLogCvmfs, logFlags,
193  "WARNING: The repository %s is currently publishing and should "
194  "not\n"
195  "be touched. If you are absolutely sure, that this is _not_ the "
196  "case,\nplease run the following command and retry:\n\n"
197  " rm -fR %s\n",
198  fqrn.c_str(), publisher_->is_publishing_.path().c_str());
199  return result;
200  }
201 
202  if (publisher_->in_transaction_.IsSet()) {
203  LogCvmfs(kLogCvmfs, logFlags,
204  "Repository %s is in a transaction and cannot be repaired.\n"
205  "--> Run `cvmfs_server abort $name` to revert and repair.",
206  fqrn.c_str());
207  return result;
208  }
209 
210  break;
211  default:
212  abort();
213  }
214 
215  LogCvmfs(kLogCvmfs, kLogSyslog, "(%s) attempting mountpoint repair (%d)",
216  fqrn.c_str(), result);
217 
218  // consecutively bring the mountpoints into a sane state by working bottom up:
219  // 1. solve problems with the rdonly mountpoint
220  // Note: this might require to 'break' the union mount
221  // (kFailUnionBroken -> 1)
222  // 1.1. solve outdated rdonly mountpoint (kFailRdOnlyOutdated -> 0)
223  // 1.2. remount rdonly mountpoint (kFailRdOnlyBroken -> 0)
224  // 2. solve problems with the union mountpoint
225  // 2.1. mount the union mountpoint read-only (kFailUnionBroken -> 0)
226  // 2.2. remount the union mountpoint read-only (kFailUnionWritable -> 0)
227  // 2.2. remount the union mountpoint read-write (kFailUnionLocked -> 0)
228 
229  int log_flags = kLogSyslog;
230  if (!is_quiet)
231  log_flags |= kLogStderr;
232 
233  if ((result & kFailRdOnlyOutdated) || (result & kFailRdOnlyWrongRevision)) {
234  if ((result & kFailUnionBroken) == 0) {
236  result |= kFailUnionBroken;
237  }
238 
239  if ((result & kFailRdOnlyBroken) == 0) {
241  result |= kFailRdOnlyBroken;
242  }
243 
244  SetRootHash(expected_hash);
245  result &= ~kFailRdOnlyOutdated;
246  result &= ~kFailRdOnlyWrongRevision;
247  }
248 
249  if (result & kFailRdOnlyBroken) {
250  if ((result & kFailUnionBroken) == 0) {
252  result |= kFailUnionBroken;
253  }
255  result &= ~kFailRdOnlyBroken;
256  }
257 
258  if (result & kFailUnionBroken) {
259  AlterMountpoint(kAlterUnionMount, log_flags);
260  // read-only mount by default
261  if (publisher_->in_transaction_.IsSet())
262  result |= kFailUnionLocked;
263 
264  result &= ~kFailUnionBroken;
265  result &= ~kFailUnionWritable;
266  }
267 
268  if (result & kFailUnionLocked) {
269  AlterMountpoint(kAlterUnionOpen, log_flags);
270  result &= ~kFailUnionLocked;
271  }
272 
273  if (result & kFailUnionWritable) {
274  AlterMountpoint(kAlterUnionLock, log_flags);
275  result &= ~kFailUnionWritable;
276  }
277 
278  LogCvmfs(kLogCvmfs, kLogSyslog, "finished mountpoint repair (%d)", result);
279 
280  return result;
281 }
282 
284  int log_level) {
285  std::string mountpoint;
286  std::string info_msg;
287  std::string suid_helper_verb;
288  switch (how) {
289  case kAlterUnionUnmount:
290  mountpoint = publisher_->settings_.transaction().spool_area().union_mnt();
291  info_msg = "Trying to unmount " + mountpoint;
292  suid_helper_verb = "rw_umount";
293  break;
295  mountpoint = publisher_->settings_.transaction().spool_area().union_mnt();
296  info_msg = "Trying to lazily unmount " + mountpoint;
297  suid_helper_verb = "rw_lazy_umount";
298  break;
299  case kAlterRdOnlyUnmount:
300  mountpoint = publisher_->settings_.transaction()
301  .spool_area()
302  .readonly_mnt();
303  info_msg = "Trying to unmount " + mountpoint;
304  suid_helper_verb = "rdonly_umount";
305  break;
307  mountpoint = publisher_->settings_.transaction()
308  .spool_area()
309  .readonly_mnt();
310  info_msg = "Trying to forcefully stop " + mountpoint;
311  suid_helper_verb = "kill_cvmfs";
312  break;
314  mountpoint = publisher_->settings_.transaction()
315  .spool_area()
316  .readonly_mnt();
317  info_msg = "Trying to lazily unmount " + mountpoint;
318  suid_helper_verb = "rdonly_lazy_umount";
319  break;
320  case kAlterUnionMount:
321  mountpoint = publisher_->settings_.transaction().spool_area().union_mnt();
322  info_msg = "Trying to mount " + mountpoint;
323  suid_helper_verb = "rw_mount";
324  break;
325  case kAlterRdOnlyMount:
326  mountpoint = publisher_->settings_.transaction()
327  .spool_area()
328  .readonly_mnt();
329  info_msg = "Trying to mount " + mountpoint;
330  suid_helper_verb = "rdonly_mount";
331  break;
332  case kAlterUnionOpen:
333  mountpoint = publisher_->settings_.transaction().spool_area().union_mnt();
334  info_msg = "Trying to remount " + mountpoint + " read/write";
335  suid_helper_verb = "open";
336  break;
337  case kAlterUnionLock:
338  mountpoint = publisher_->settings_.transaction().spool_area().union_mnt();
339  info_msg = "Trying to remount " + mountpoint + " read-only";
340  suid_helper_verb = "lock";
341  break;
342  case kAlterScratchWipe:
343  mountpoint = publisher_->settings_.transaction()
344  .spool_area()
345  .scratch_dir();
346  info_msg = "Trying to wipe out " + mountpoint + " (async cleanup)";
347  suid_helper_verb = "clear_scratch_async";
348  break;
349  default:
350  throw EPublish("internal error: unknown mountpoint alteration");
351  }
352 
353  if (log_level & kLogStdout) {
354  LogCvmfs(kLogCvmfs, kLogStderr | kLogNoLinebreak, "Note: %s... ",
355  info_msg.c_str());
356  }
357 
358  try {
359  RunSuidHelper(suid_helper_verb, publisher_->settings_.fqrn());
360  LogCvmfs(kLogCvmfs, (log_level & ~kLogStdout), "%s... success",
361  info_msg.c_str());
362  if (log_level & kLogStdout)
363  LogCvmfs(kLogCvmfs, kLogStdout, "success");
364  } catch (const EPublish &) {
365  LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr, "%s... fail",
366  info_msg.c_str());
367  throw EPublish(info_msg + "... fail");
368  }
369 }
370 
371 
373  const std::string config_path = publisher_->settings_.transaction()
374  .spool_area()
375  .client_lconfig();
376  SetInConfig(config_path, "CVMFS_ROOT_HASH", hash.ToString());
377 }
378 
379 } // namespace publish
static void Mount(const string &path)
Publisher * publisher_
Definition: repository.h:222
void Lock()
EUnionMountRepairMode
Definition: settings.h:63
std::string ToString(const bool with_suffix=false) const
Definition: hash.h:241
void Open()
void AlterMountpoint(EMountpointAlterations how, int log_level)
bool is_rdonly
Definition: posix.h:56
void Check()
const int kDefaultDirMode
Definition: posix.h:33
FileSystemInfo GetFileSystemInfo(const std::string &path)
Definition: posix.cc:179
bool platform_getxattr(const std::string &path, const std::string &name, std::string *value)
const char kSuffixCatalog
Definition: hash.h:54
void SetInConfig(const std::string &path, const std::string &key, const std::string &value)
EMountpointAlterations
Definition: repository.h:206
std::string CreateTempDir(const std::string &path_prefix)
Definition: posix.cc:1054
bool HasPrefix(const string &str, const string &prefix, const bool ignore_case)
Definition: string.cc:279
void ClearScratch()
void RunSuidHelper(const std::string &verb, const std::string &fqrn)
bool ListDirectory(const std::string &directory, std::vector< std::string > *names, std::vector< mode_t > *modes)
Definition: posix.cc:1206
Any MkFromHexPtr(const HexPtr hex, const char suffix)
Definition: hash.cc:82
void SetRootHash(const shash::Any &hash)
bool IsMountPoint(const std::string &path)
Definition: posix.cc:264
static CheckoutMarker * CreateFrom(const std::string &path)
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)
Definition: logging.cc:545