mirror of
https://github.com/facebook/sapling.git
synced 2024-10-10 16:57:49 +03:00
4f7fd33e29
Summary: Add a simple new wrapper daemon to manage the edenfs daemon. This is intended to provide a few different features: - Perform log rotation for EdenFS's output and the output of any of its spawned children processes. - Help schedule restarts of EdenFS when the system looks idle. - Provide a single process for the system to manage across graceful EdenFS restarts, to make management slightly simpler. This initial commit does not perform graceful restarts yet, but has the basic daemon management and log rotation present. Reviewed By: wez Differential Revision: D19588700 fbshipit-source-id: bba41c9f7efeb4417753c1d48dd72cf6d191f0c3
153 lines
4.6 KiB
C++
153 lines
4.6 KiB
C++
/*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This software may be used and distributed according to the terms of the
|
|
* GNU General Public License version 2.
|
|
*/
|
|
|
|
#include "eden/fs/service/EdenInit.h"
|
|
|
|
#include <boost/filesystem.hpp>
|
|
|
|
#include "eden/fs/config/EdenConfig.h"
|
|
#include "eden/fs/eden-config.h"
|
|
#include "eden/fs/fuse/privhelper/UserInfo.h"
|
|
#include "eden/fs/utils/PathFuncs.h"
|
|
|
|
using folly::StringPiece;
|
|
|
|
DEFINE_string(configPath, "", "The path of the ~/.edenrc config file");
|
|
DEFINE_string(edenDir, "", "The path to the .eden directory");
|
|
DEFINE_string(
|
|
etcEdenDir,
|
|
EDEN_ETC_EDEN_DIR,
|
|
"The directory holding all system configuration files");
|
|
DEFINE_bool(
|
|
foreground,
|
|
false,
|
|
"Run edenfs in the foreground, rather than daemonizing "
|
|
"as a background process");
|
|
DEFINE_string(
|
|
logPath,
|
|
"",
|
|
"If set, redirects stdout and stderr to the log file given.");
|
|
|
|
namespace {
|
|
using namespace facebook::eden;
|
|
|
|
constexpr StringPiece kDefaultUserConfigFile{".edenrc"};
|
|
constexpr StringPiece kEdenfsConfigFile{"edenfs.rc"};
|
|
|
|
void findEdenDir(EdenConfig& config) {
|
|
// Get the initial path to the Eden directory.
|
|
// We use the --edenDir flag if set, otherwise the value loaded from the
|
|
// config file.
|
|
boost::filesystem::path boostPath(
|
|
FLAGS_edenDir.empty() ? config.edenDir.getValue().value()
|
|
: FLAGS_edenDir);
|
|
|
|
try {
|
|
// Ensure that the directory exists, and then canonicalize its name with
|
|
// realpath(). Using realpath() requires that the directory exist.
|
|
boost::filesystem::create_directories(boostPath);
|
|
auto resolvedDir = facebook::eden::realpath(boostPath.string());
|
|
|
|
// Updating the value in the config using ConfigSource::CommandLine also
|
|
// makes sure that any future updates to the config file do not affect the
|
|
// value we use. Once we start we want to always use a fixed location for
|
|
// the eden directory.
|
|
config.edenDir.setValue(resolvedDir, ConfigSource::CommandLine);
|
|
} catch (const std::exception& ex) {
|
|
throw ArgumentError(
|
|
"error creating ", boostPath.string(), ": ", folly::exceptionStr(ex));
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
namespace facebook {
|
|
namespace eden {
|
|
|
|
PathComponentPiece getDefaultLogFileName() {
|
|
return "edenfs.log"_pc;
|
|
}
|
|
|
|
AbsolutePath makeDefaultLogDirectory(AbsolutePathPiece edenDir) {
|
|
auto logDir = edenDir + "logs"_pc;
|
|
ensureDirectoryExists(logDir);
|
|
return logDir;
|
|
}
|
|
|
|
std::string getLogPath(AbsolutePathPiece edenDir) {
|
|
// If a log path was explicitly specified as a command line argument use that
|
|
if (!FLAGS_logPath.empty()) {
|
|
return FLAGS_logPath;
|
|
}
|
|
|
|
// If we are running in the foreground default to an empty log path
|
|
// (just log directly to stderr)
|
|
if (FLAGS_foreground) {
|
|
return "";
|
|
}
|
|
|
|
auto logDir = makeDefaultLogDirectory(edenDir);
|
|
return (logDir + getDefaultLogFileName()).value();
|
|
}
|
|
|
|
std::unique_ptr<EdenConfig> getEdenConfig(UserInfo& identity) {
|
|
// normalizeBestEffort() to try resolving symlinks in these paths but don't
|
|
// fail if they don't exist.
|
|
AbsolutePath systemConfigDir;
|
|
try {
|
|
systemConfigDir = normalizeBestEffort(FLAGS_etcEdenDir);
|
|
} catch (const std::exception& ex) {
|
|
throw ArgumentError(
|
|
"invalid flag value: ",
|
|
FLAGS_etcEdenDir,
|
|
": ",
|
|
folly::exceptionStr(ex));
|
|
}
|
|
const auto systemConfigPath =
|
|
systemConfigDir + PathComponentPiece{kEdenfsConfigFile};
|
|
|
|
const std::string configPathStr = FLAGS_configPath;
|
|
AbsolutePath userConfigPath;
|
|
if (configPathStr.empty()) {
|
|
userConfigPath = identity.getHomeDirectory() +
|
|
PathComponentPiece{kDefaultUserConfigFile};
|
|
} else {
|
|
try {
|
|
userConfigPath = normalizeBestEffort(configPathStr);
|
|
} catch (const std::exception& ex) {
|
|
throw ArgumentError(
|
|
"invalid flag value: ",
|
|
FLAGS_configPath,
|
|
": ",
|
|
folly::exceptionStr(ex));
|
|
}
|
|
}
|
|
// Create the default EdenConfig. Next, update with command line arguments.
|
|
// Command line arguments will take precedence over config file settings.
|
|
auto edenConfig = std::make_unique<EdenConfig>(
|
|
identity.getUsername(),
|
|
identity.getUid(),
|
|
identity.getHomeDirectory(),
|
|
userConfigPath,
|
|
systemConfigDir,
|
|
systemConfigPath);
|
|
|
|
// Load system and user configurations
|
|
edenConfig->loadSystemConfig();
|
|
edenConfig->loadUserConfig();
|
|
|
|
// Determine the location of the Eden state directory, and update this value
|
|
// in the EdenConfig object. This also creates the directory if it does not
|
|
// exist.
|
|
findEdenDir(*edenConfig);
|
|
|
|
return edenConfig;
|
|
}
|
|
|
|
} // namespace eden
|
|
} // namespace facebook
|