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