CernVM-FS  2.9.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 "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  const std::string rdonly_mnt =
87  publisher_->settings_.transaction().spool_area().readonly_mnt();
88  const std::string union_mnt =
89  publisher_->settings_.transaction().spool_area().union_mnt();
90  const std::string publishing_lock =
91  publisher_->settings_.transaction().spool_area().publishing_lock();
92  const std::string fqrn = publisher_->settings_.fqrn();
93  EUnionMountRepairMode repair_mode =
94  publisher_->settings_.transaction().spool_area().repair_mode();
95 
96  int result = kFailOk;
97 
98  shash::Any expected_hash = publisher_->manifest()->catalog_hash();
100  publisher_->settings_.transaction().spool_area().checkout_marker()));
101  if (marker.IsValid())
102  expected_hash = marker->hash();
103 
104  if (!IsMountPoint(rdonly_mnt)) {
105  result |= kFailRdOnlyBroken;
106  } else {
107  const std::string root_hash_xattr = "user.root_hash";
108  std::string root_hash_str;
109  bool retval = platform_getxattr(rdonly_mnt, root_hash_xattr,
110  &root_hash_str);
111  if (!retval)
112  throw EPublish("cannot retrieve root hash from read-only mount point");
113  shash::Any root_hash = shash::MkFromHexPtr(shash::HexPtr(root_hash_str),
115 
116  if (expected_hash != root_hash) {
117  if (marker.IsValid()) {
118  result |= kFailRdOnlyWrongRevision;
119  } else {
120  result |= kFailRdOnlyOutdated;
121  }
122  }
123  }
124 
125  // The process that opens the transaction does not stay alive for the life
126  // time of the transaction
127  if (!IsMountPoint(union_mnt)) {
128  result |= kFailUnionBroken;
129  } else {
130  FileSystemInfo fs_info = GetFileSystemInfo(union_mnt);
131  if (publisher_->in_transaction_ && fs_info.is_rdonly)
132  result |= kFailUnionLocked;
133  if (!publisher_->in_transaction_ && !fs_info.is_rdonly)
134  result |= kFailUnionWritable;
135  }
136 
137  if (result == kFailOk)
138  return result;
139 
140  // Report & Repair
141 
142  int logFlags = kLogStderr;
143  if (is_quiet)
144  logFlags |= kLogNone;
145  if (result & kFailRdOnlyBroken) {
146  LogCvmfs(kLogCvmfs, logFlags, "%s is not mounted properly",
147  rdonly_mnt.c_str());
148  }
149  if (result & kFailRdOnlyOutdated) {
150  LogCvmfs(kLogCvmfs, logFlags,
151  "%s is not based on the newest published revision", fqrn.c_str());
152  }
153  if (result & kFailRdOnlyWrongRevision) {
154  LogCvmfs(kLogCvmfs, logFlags,
155  "%s is not based on the checked out revision", fqrn.c_str());
156  }
157  if (result & kFailUnionBroken) {
158  LogCvmfs(kLogCvmfs, logFlags, "%s is not mounted properly",
159  union_mnt.c_str());
160  }
161  if (result & kFailUnionWritable) {
162  LogCvmfs(kLogCvmfs, logFlags,
163  "%s is not in a transaction but %s is mounted read/write",
164  fqrn.c_str(), union_mnt.c_str());
165  }
166  if (result & kFailUnionLocked) {
167  LogCvmfs(kLogCvmfs, logFlags,
168  "%s is in a transaction but %s is not mounted read/write",
169  fqrn.c_str(), union_mnt.c_str());
170  }
171 
172  // Check whether we can repair
173 
174  switch (repair_mode) {
176  return result;
178  break;
180  if (publisher_->is_publishing()) {
181  LogCvmfs(kLogCvmfs, logFlags,
182  "WARNING: The repository %s is currently publishing and should not\n"
183  "be touched. If you are absolutely sure, that this is _not_ the "
184  "case,\nplease run the following command and retry:\n\n"
185  " rm -fR %s\n",
186  fqrn.c_str(), publishing_lock.c_str());
187  return result;
188  }
189 
190  if (publisher_->in_transaction_) {
191  LogCvmfs(kLogCvmfs, logFlags,
192  "Repository %s is in a transaction and cannot be repaired.\n"
193  "--> Run `cvmfs_server abort $name` to revert and repair.",
194  fqrn.c_str());
195  return result;
196  }
197 
198  break;
199  default:
200  abort();
201  }
202 
203  LogCvmfs(kLogCvmfs, kLogSyslog, "(%s) attempting mountpoint repair (%d)",
204  fqrn.c_str(), result);
205 
206  // consecutively bring the mountpoints into a sane state by working bottom up:
207  // 1. solve problems with the rdonly mountpoint
208  // Note: this might require to 'break' the union mount
209  // (kFailUnionBroken -> 1)
210  // 1.1. solve outdated rdonly mountpoint (kFailRdOnlyOutdated -> 0)
211  // 1.2. remount rdonly mountpoint (kFailRdOnlyBroken -> 0)
212  // 2. solve problems with the union mountpoint
213  // 2.1. mount the union mountpoint read-only (kFailUnionBroken -> 0)
214  // 2.2. remount the union mountpoint read-only (kFailUnionWritable -> 0)
215  // 2.2. remount the union mountpoint read-write (kFailUnionLocked -> 0)
216 
217  int log_flags = kLogSyslog;
218  if (!is_quiet)
219  log_flags |= kLogStderr;
220 
221  if ((result & kFailRdOnlyOutdated) || (result & kFailRdOnlyWrongRevision)) {
222  if ((result & kFailUnionBroken) == 0) {
224  result |= kFailUnionBroken;
225  }
226 
227  if ((result & kFailRdOnlyBroken) == 0) {
229  result |= kFailRdOnlyBroken;
230  }
231 
232  SetRootHash(expected_hash);
233  result &= ~kFailRdOnlyOutdated;
234  result &= ~kFailRdOnlyWrongRevision;
235  }
236 
237  if (result & kFailRdOnlyBroken) {
238  if ((result & kFailUnionBroken) == 0) {
240  result |= kFailUnionBroken;
241  }
243  result &= ~kFailRdOnlyBroken;
244  }
245 
246  if (result & kFailUnionBroken) {
247  AlterMountpoint(kAlterUnionMount, log_flags);
248  // read-only mount by default
249  if (publisher_->in_transaction_)
250  result |= kFailUnionLocked;
251 
252  result &= ~kFailUnionBroken;
253  result &= ~kFailUnionWritable;
254  }
255 
256  if (result & kFailUnionLocked) {
257  AlterMountpoint(kAlterUnionOpen, log_flags);
258  result &= ~kFailUnionLocked;
259  }
260 
261  if (result & kFailUnionWritable) {
262  AlterMountpoint(kAlterUnionLock, log_flags);
263  result &= ~kFailUnionWritable;
264  }
265 
266  LogCvmfs(kLogCvmfs, kLogSyslog, "finished mountpoint repair (%d)", result);
267 
268  return result;
269 }
270 
272  EMountpointAlterations how, int log_level)
273 {
274  std::string mountpoint;
275  std::string info_msg;
276  std::string suid_helper_verb;
277  switch (how) {
278  case kAlterUnionUnmount:
279  mountpoint = publisher_->settings_.transaction().spool_area().union_mnt();
280  info_msg = "Trying to unmount " + mountpoint;
281  suid_helper_verb = "rw_umount";
282  break;
284  mountpoint = publisher_->settings_.transaction().spool_area().union_mnt();
285  info_msg = "Trying to lazily unmount " + mountpoint;
286  suid_helper_verb = "rw_lazy_umount";
287  break;
288  case kAlterRdOnlyUnmount:
289  mountpoint =
290  publisher_->settings_.transaction().spool_area().readonly_mnt();
291  info_msg = "Trying to unmount " + mountpoint;
292  suid_helper_verb = "rdonly_umount";
293  break;
295  mountpoint =
296  publisher_->settings_.transaction().spool_area().readonly_mnt();
297  info_msg = "Trying to forcefully stop " + mountpoint;
298  suid_helper_verb = "kill_cvmfs";
299  break;
301  mountpoint =
302  publisher_->settings_.transaction().spool_area().readonly_mnt();
303  info_msg = "Trying to lazily unmount " + mountpoint;
304  suid_helper_verb = "rdonly_lazy_umount";
305  break;
306  case kAlterUnionMount:
307  mountpoint = publisher_->settings_.transaction().spool_area().union_mnt();
308  info_msg = "Trying to mount " + mountpoint;
309  suid_helper_verb = "rw_mount";
310  break;
311  case kAlterRdOnlyMount:
312  mountpoint =
313  publisher_->settings_.transaction().spool_area().readonly_mnt();
314  info_msg = "Trying to mount " + mountpoint;
315  suid_helper_verb = "rdonly_mount";
316  break;
317  case kAlterUnionOpen:
318  mountpoint = publisher_->settings_.transaction().spool_area().union_mnt();
319  info_msg = "Trying to remount " + mountpoint + " read/write";
320  suid_helper_verb = "open";
321  break;
322  case kAlterUnionLock:
323  mountpoint =
324  publisher_->settings_.transaction().spool_area().union_mnt();
325  info_msg = "Trying to remount " + mountpoint + " read-only";
326  suid_helper_verb = "lock";
327  break;
328  case kAlterScratchWipe:
329  mountpoint =
330  publisher_->settings_.transaction().spool_area().scratch_dir();
331  info_msg = "Trying to wipe out " + mountpoint + " (async cleanup)";
332  suid_helper_verb = "clear_scratch_async";
333  break;
334  default:
335  throw EPublish("internal error: unknown mountpoint alteration");
336  }
337 
338  if (log_level & kLogStdout) {
339  LogCvmfs(kLogCvmfs, kLogStderr | kLogNoLinebreak, "Note: %s... ",
340  info_msg.c_str());
341  }
342 
343  try {
344  RunSuidHelper(suid_helper_verb, publisher_->settings_.fqrn());
345  LogCvmfs(kLogCvmfs, (log_level & ~kLogStdout), "%s... success",
346  info_msg.c_str());
347  if (log_level & kLogStdout)
348  LogCvmfs(kLogCvmfs, kLogStdout, "success");
349  } catch (const EPublish&) {
350  LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr, "%s... fail",
351  info_msg.c_str());
352  throw EPublish(info_msg + "... fail");
353  }
354 }
355 
356 
358  const std::string config_path =
359  publisher_->settings_.transaction().spool_area().client_lconfig();
360  SetInConfig(config_path, "CVMFS_ROOT_HASH", hash.ToString());
361 }
362 
363 } // namespace publish
#define LogCvmfs(source, mask,...)
Definition: logging.h:20
static void Mount(const string &path)
Publisher * publisher_
Definition: repository.h:222
const int kPrivateDirMode
Definition: posix.h:35
void Lock()
EUnionMountRepairMode
Definition: settings.h:68
std::string ToString(const bool with_suffix=false) const
Definition: hash.h:245
void Open()
void AlterMountpoint(EMountpointAlterations how, int log_level)
bool is_rdonly
Definition: posix.h:52
void Check()
FileSystemInfo GetFileSystemInfo(const std::string &path)
Definition: posix.cc:216
bool platform_getxattr(const std::string &path, const std::string &name, std::string *value)
const char kSuffixCatalog
Definition: hash.h:52
void SetInConfig(const std::string &path, const std::string &key, const std::string &value)
Any MkFromHexPtr(const HexPtr hex, const char suffix)
Definition: hash.cc:83
EMountpointAlterations
Definition: repository.h:206
std::string CreateTempDir(const std::string &path_prefix)
Definition: posix.cc:1072
bool HasPrefix(const string &str, const string &prefix, const bool ignore_case)
Definition: string.cc:265
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:1233
void SetRootHash(const shash::Any &hash)
bool IsMountPoint(const std::string &path)
Definition: posix.cc:299
static CheckoutMarker * CreateFrom(const std::string &path)