1
0
Fork 0

added database.init-database

This commit is contained in:
Frank Celler 2016-06-08 21:40:09 +02:00
parent 967d709f28
commit a92d566234
10 changed files with 330 additions and 60 deletions

View File

@ -242,6 +242,7 @@ add_executable(${BIN_ARANGOD}
RestServer/EndpointFeature.cpp RestServer/EndpointFeature.cpp
RestServer/FileDescriptorsFeature.cpp RestServer/FileDescriptorsFeature.cpp
RestServer/FrontendFeature.cpp RestServer/FrontendFeature.cpp
RestServer/InitDatabaseFeature.cpp
RestServer/QueryRegistryFeature.cpp RestServer/QueryRegistryFeature.cpp
RestServer/RestServerFeature.cpp RestServer/RestServerFeature.cpp
RestServer/ScriptFeature.cpp RestServer/ScriptFeature.cpp

View File

@ -30,8 +30,8 @@
#include "ProgramOptions/Section.h" #include "ProgramOptions/Section.h"
#include "Rest/Version.h" #include "Rest/Version.h"
#include "RestServer/DatabaseServerFeature.h" #include "RestServer/DatabaseServerFeature.h"
#include "RestServer/RestServerFeature.h"
#include "RestServer/QueryRegistryFeature.h" #include "RestServer/QueryRegistryFeature.h"
#include "RestServer/RestServerFeature.h"
#include "V8Server/V8DealerFeature.h" #include "V8Server/V8DealerFeature.h"
#include "V8Server/v8-query.h" #include "V8Server/v8-query.h"
#include "V8Server/v8-vocbase.h" #include "V8Server/v8-vocbase.h"
@ -65,12 +65,14 @@ DatabaseFeature::DatabaseFeature(ApplicationServer* server)
requiresElevatedPrivileges(false); requiresElevatedPrivileges(false);
startsAfter("DatabaseServer"); startsAfter("DatabaseServer");
startsAfter("LogfileManager"); startsAfter("LogfileManager");
startsAfter("InitDatabase");
} }
void DatabaseFeature::collectOptions(std::shared_ptr<ProgramOptions> options) { void DatabaseFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
options->addSection("database", "Configure the database"); options->addSection("database", "Configure the database");
options->addOldOption("server.disable-replication-applier", "database.replication-applier"); options->addOldOption("server.disable-replication-applier",
"database.replication-applier");
options->addOption("--database.directory", "path to the database directory", options->addOption("--database.directory", "path to the database directory",
new StringParameter(&_directory)); new StringParameter(&_directory));
@ -197,9 +199,9 @@ void DatabaseFeature::updateContexts() {
auto vocbase = _vocbase; auto vocbase = _vocbase;
V8DealerFeature* dealer = V8DealerFeature* dealer =
ApplicationServer::getFeature<V8DealerFeature>("V8Dealer"); ApplicationServer::getFeature<V8DealerFeature>("V8Dealer");
dealer->defineContextUpdate( dealer->defineContextUpdate(
[queryRegistry, server, vocbase]( [queryRegistry, server, vocbase](
v8::Isolate* isolate, v8::Handle<v8::Context> context, size_t i) { v8::Isolate* isolate, v8::Handle<v8::Context> context, size_t i) {
@ -243,16 +245,15 @@ void DatabaseFeature::openDatabases() {
defaults.forceSyncProperties = _forceSyncProperties; defaults.forceSyncProperties = _forceSyncProperties;
// get authentication (if available) // get authentication (if available)
RestServerFeature* rest = RestServerFeature* rest =
ApplicationServer::getFeature<RestServerFeature>("RestServer"); ApplicationServer::getFeature<RestServerFeature>("RestServer");
defaults.requireAuthentication = rest->authentication(); defaults.requireAuthentication = rest->authentication();
defaults.requireAuthenticationUnixSockets = defaults.requireAuthenticationUnixSockets = rest->authenticationUnixSockets();
rest->authenticationUnixSockets();
defaults.authenticateSystemOnly = rest->authenticationSystemOnly(); defaults.authenticateSystemOnly = rest->authenticationSystemOnly();
bool const iterateMarkersOnOpen = bool const iterateMarkersOnOpen =
!wal::LogfileManager::instance()->hasFoundLastTick(); !wal::LogfileManager::instance()->hasFoundLastTick();
int res = TRI_InitServer( int res = TRI_InitServer(
DatabaseServerFeature::SERVER, DatabaseServerFeature::INDEX_POOL, DatabaseServerFeature::SERVER, DatabaseServerFeature::INDEX_POOL,
@ -267,15 +268,20 @@ void DatabaseFeature::openDatabases() {
res = TRI_StartServer(DatabaseServerFeature::SERVER, _checkVersion, _upgrade); res = TRI_StartServer(DatabaseServerFeature::SERVER, _checkVersion, _upgrade);
if (res != TRI_ERROR_NO_ERROR) { if (res != TRI_ERROR_NO_ERROR) {
if (_checkVersion && res == TRI_ERROR_ARANGO_EMPTY_DATADIR) { if (res == TRI_ERROR_ARANGO_EMPTY_DATADIR) {
LOG_TOPIC(TRACE, Logger::STARTUP) << "database is empty";
_isInitiallyEmpty = true; _isInitiallyEmpty = true;
} else { }
if (! _checkVersion || ! _isInitiallyEmpty) {
LOG(FATAL) << "cannot start server: " << TRI_errno_string(res); LOG(FATAL) << "cannot start server: " << TRI_errno_string(res);
FATAL_ERROR_EXIT(); FATAL_ERROR_EXIT();
} }
} }
LOG_TOPIC(TRACE, Logger::STARTUP) << "found system database"; if (!_isInitiallyEmpty) {
LOG_TOPIC(TRACE, Logger::STARTUP) << "found system database";
}
} }
void DatabaseFeature::closeDatabases() { void DatabaseFeature::closeDatabases() {

View File

@ -0,0 +1,175 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
////////////////////////////////////////////////////////////////////////////////
#include "InitDatabaseFeature.h"
#include "Basics/FileUtils.h"
#include "Logger/LoggerFeature.h"
#include "Logger/LoggerFeature.h"
#include "ProgramOptions/ProgramOptions.h"
#include "ProgramOptions/Section.h"
#include "RestServer/DatabaseFeature.h"
using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::basics;
using namespace arangodb::options;
InitDatabaseFeature::InitDatabaseFeature(ApplicationServer* server)
: ApplicationFeature(server, "InitDatabase") {
setOptional(false);
requiresElevatedPrivileges(false);
startsAfter("Logger");
}
void InitDatabaseFeature::collectOptions(
std::shared_ptr<ProgramOptions> options) {
options->addSection("database", "Configure the database");
options->addHiddenOption("--database.init-database",
"initializes an empty database",
new BooleanParameter(&_initDatabase));
options->addHiddenOption("--database.password",
"initial password of root user",
new StringParameter(&_password));
}
void InitDatabaseFeature::validateOptions(
std::shared_ptr<ProgramOptions> options) {
ProgramOptions::ProcessingResult const& result = options->processingResult();
_seenPassword = result.touched("database.password");
}
void InitDatabaseFeature::prepare() {
if (!_seenPassword) {
std::string env = "ARANGODB_DEFAULT_ROOT_PASSWORD";
char const* passworde = getenv(env.c_str());
if (passworde != nullptr && *passworde != '\0') {
env += "=";
putenv(const_cast<char*>(env.c_str()));
_password = passworde;
_seenPassword = true;
}
}
if (!_initDatabase) {
return;
}
checkEmptyDatabase();
if (!_seenPassword) {
while (true) {
std::string password1 =
readPassword("Please enter password for root user");
if (!password1.empty()) {
std::string password2 = readPassword("Repeat password");
if (password1 == password2) {
_password = password1;
break;
}
LOG(ERR) << "passwords do not match, please repeat";
} else {
LOG(FATAL) << "initialization aborted by user";
FATAL_ERROR_EXIT();
}
}
}
}
void InitDatabaseFeature::start() {
if (!_initDatabase) {
return;
}
}
std::string InitDatabaseFeature::readPassword(std::string const& message) {
std::string password;
arangodb::Logger::flush();
std::cout << message << ": " << std::flush;
#ifdef TRI_HAVE_TERMIOS_H
TRI_SetStdinVisibility(false);
std::getline(std::cin, password);
TRI_SetStdinVisibility(true);
#else
std::getline(std::cin, password);
#endif
std::cout << std::endl;
return password;
}
void InitDatabaseFeature::checkEmptyDatabase() {
auto database = ApplicationServer::getFeature<DatabaseFeature>("Database");
std::string path = database->directory();
std::string journals = FileUtils::buildFilename(path, "journals");
bool empty = false;
std::string message;
int code = 2;
if (FileUtils::exists(path)) {
if (!FileUtils::isDirectory(path)) {
message = "database path '" + path + "' is not a directory";
code = EXIT_FAILURE;
goto doexit;
}
if (FileUtils::exists(journals)) {
if (!FileUtils::isDirectory(journals)) {
message =
"database journals path '" + journals + "' is not a directory";
code = EXIT_FAILURE;
goto doexit;
}
} else {
empty = true;
}
} else {
empty = true;
}
if (!empty) {
message = "database already initialized, refusing to change root user";
goto doexit;
}
return;
doexit:
LOG(FATAL) << message;
auto logger = ApplicationServer::getFeature<LoggerFeature>("Logger");
logger->unprepare();
TRI_EXIT_FUNCTION(code, nullptr);
exit(code);
}

View File

@ -0,0 +1,57 @@
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
////////////////////////////////////////////////////////////////////////////////
#ifndef APPLICATION_FEATURES_INIT_DATABASE_FEATURE_H
#define APPLICATION_FEATURES_INIT_DATABASE_FEATURE_H 1
#include "ApplicationFeatures/ApplicationFeature.h"
namespace arangodb {
class InitDatabaseFeature final
: public application_features::ApplicationFeature {
public:
explicit InitDatabaseFeature(application_features::ApplicationServer* server);
public:
std::string const& defaultPassword() const { return _password; }
bool isInitDatabase() const { return _initDatabase; }
private:
bool _initDatabase = false;
std::string _password;
public:
void collectOptions(std::shared_ptr<options::ProgramOptions>) override final;
void validateOptions(std::shared_ptr<options::ProgramOptions>) override final;
void start() override final;
void prepare() override final;
private:
void checkEmptyDatabase();
std::string readPassword(std::string const&);
private:
bool _seenPassword = false;
};
}
#endif

View File

@ -27,6 +27,7 @@
#include "ProgramOptions/Section.h" #include "ProgramOptions/Section.h"
#include "RestServer/DatabaseFeature.h" #include "RestServer/DatabaseFeature.h"
#include "RestServer/DatabaseServerFeature.h" #include "RestServer/DatabaseServerFeature.h"
#include "RestServer/InitDatabaseFeature.h"
#include "V8/v8-globals.h" #include "V8/v8-globals.h"
#include "V8Server/V8Context.h" #include "V8Server/V8Context.h"
#include "V8Server/V8DealerFeature.h" #include "V8Server/V8DealerFeature.h"
@ -58,7 +59,7 @@ UpgradeFeature::UpgradeFeature(
void UpgradeFeature::collectOptions(std::shared_ptr<ProgramOptions> options) { void UpgradeFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
options->addSection("database", "Configure the database"); options->addSection("database", "Configure the database");
options->addOldOption("upgrade", "--database.auto-upgrade"); options->addOldOption("upgrade", "--database.auto-upgrade");
options->addOption("--database.auto-upgrade", options->addOption("--database.auto-upgrade",
@ -86,12 +87,12 @@ void UpgradeFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
ApplicationServer::forceDisableFeatures(_nonServerFeatures); ApplicationServer::forceDisableFeatures(_nonServerFeatures);
DatabaseFeature* database = DatabaseFeature* database =
ApplicationServer::getFeature<DatabaseFeature>("Database"); ApplicationServer::getFeature<DatabaseFeature>("Database");
database->disableReplicationApplier(); database->disableReplicationApplier();
database->enableUpgrade(); database->enableUpgrade();
ClusterFeature* cluster = ClusterFeature* cluster =
ApplicationServer::getFeature<ClusterFeature>("Cluster"); ApplicationServer::getFeature<ClusterFeature>("Cluster");
cluster->forceDisable(); cluster->forceDisable();
} }
@ -103,7 +104,9 @@ void UpgradeFeature::start() {
} }
// and force shutdown // and force shutdown
if (_upgrade) { auto init = ApplicationServer::getFeature<InitDatabaseFeature>("InitDatabase");
if (_upgrade || init->isInitDatabase()) {
server()->beginShutdown(); server()->beginShutdown();
} }
} }
@ -147,27 +150,38 @@ void UpgradeFeature::upgradeDatabase() {
v8::HandleScope scope(context->_isolate); v8::HandleScope scope(context->_isolate);
v8::Handle<v8::Object> args = v8::Object::New(context->_isolate); v8::Handle<v8::Object> args = v8::Object::New(context->_isolate);
args->Set(TRI_V8_ASCII_STRING2(context->_isolate, "upgrade"), args->Set(TRI_V8_ASCII_STRING2(context->_isolate, "upgrade"),
v8::Boolean::New(context->_isolate, _upgrade)); v8::Boolean::New(context->_isolate, _upgrade));
auto init = ApplicationServer::getFeature<InitDatabaseFeature>(
"InitDatabase");
if (init != nullptr) {
args->Set(
TRI_V8_ASCII_STRING2(context->_isolate, "password"),
TRI_V8_STD_STRING2(context->_isolate, init->defaultPassword()));
}
localContext->Global()->Set( localContext->Global()->Set(
TRI_V8_ASCII_STRING2(context->_isolate, "UPGRADE_ARGS"), args); TRI_V8_ASCII_STRING2(context->_isolate, "UPGRADE_ARGS"), args);
bool ok = TRI_UpgradeDatabase(vocbase, localContext); bool ok = TRI_UpgradeDatabase(vocbase, localContext);
if (!ok) { if (!ok) {
if (localContext->Global()->Has( if (localContext->Global()->Has(TRI_V8_ASCII_STRING2(
TRI_V8_ASCII_STRING2(context->_isolate, "UPGRADE_STARTED"))) { context->_isolate, "UPGRADE_STARTED"))) {
localContext->Exit(); localContext->Exit();
if (_upgrade) { if (_upgrade) {
LOG(FATAL) << "Database '" << vocbase->_name LOG(FATAL) << "Database '" << vocbase->_name
<< "' upgrade failed. Please inspect the logs from " << "' upgrade failed. Please inspect the logs from "
"the upgrade procedure"; "the upgrade procedure";
FATAL_ERROR_EXIT(); FATAL_ERROR_EXIT();
} else { } else {
LOG(FATAL) << "Database '" << vocbase->_name LOG(FATAL)
<< "' needs upgrade. Please start the server with the " << "Database '" << vocbase->_name
"--database.auto-upgrade option"; << "' needs upgrade. Please start the server with the "
"--database.auto-upgrade option";
FATAL_ERROR_EXIT(); FATAL_ERROR_EXIT();
} }
} else { } else {
@ -175,12 +189,14 @@ void UpgradeFeature::upgradeDatabase() {
FATAL_ERROR_EXIT(); FATAL_ERROR_EXIT();
} }
LOG(DEBUG) << "database '" << vocbase->_name << "' init/upgrade done"; LOG(DEBUG) << "database '" << vocbase->_name
<< "' init/upgrade done";
} }
} }
} }
// finally leave the context. otherwise v8 will crash with assertion failure // finally leave the context. otherwise v8 will crash with assertion
// failure
// when we delete // when we delete
// the context locker below // the context locker below
localContext->Exit(); localContext->Exit();

View File

@ -56,6 +56,7 @@
#include "RestServer/EndpointFeature.h" #include "RestServer/EndpointFeature.h"
#include "RestServer/FileDescriptorsFeature.h" #include "RestServer/FileDescriptorsFeature.h"
#include "RestServer/FrontendFeature.h" #include "RestServer/FrontendFeature.h"
#include "RestServer/InitDatabaseFeature.h"
#include "RestServer/QueryRegistryFeature.h" #include "RestServer/QueryRegistryFeature.h"
#include "RestServer/RestServerFeature.h" #include "RestServer/RestServerFeature.h"
#include "RestServer/ScriptFeature.h" #include "RestServer/ScriptFeature.h"
@ -119,6 +120,7 @@ static int runServer(int argc, char** argv) {
server.addFeature(new FileDescriptorsFeature(&server)); server.addFeature(new FileDescriptorsFeature(&server));
server.addFeature(new FoxxQueuesFeature(&server)); server.addFeature(new FoxxQueuesFeature(&server));
server.addFeature(new FrontendFeature(&server)); server.addFeature(new FrontendFeature(&server));
server.addFeature(new InitDatabaseFeature(&server));
server.addFeature(new LanguageFeature(&server)); server.addFeature(new LanguageFeature(&server));
server.addFeature(new LogfileManager(&server)); server.addFeature(new LogfileManager(&server));
server.addFeature(new LoggerBufferFeature(&server)); server.addFeature(new LoggerBufferFeature(&server));

View File

@ -3050,8 +3050,10 @@ bool TRI_UpgradeDatabase(TRI_vocbase_t* vocbase,
v8g->_vocbase = vocbase; v8g->_vocbase = vocbase;
auto startupLoader = V8DealerFeature::DEALER->startupLoader(); auto startupLoader = V8DealerFeature::DEALER->startupLoader();
v8::Handle<v8::Value> result = startupLoader->executeGlobalScript( v8::Handle<v8::Value> result = startupLoader->executeGlobalScript(
isolate, isolate->GetCurrentContext(), "server/upgrade-database.js"); isolate, isolate->GetCurrentContext(), "server/upgrade-database.js");
bool ok = TRI_ObjectToBoolean(result); bool ok = TRI_ObjectToBoolean(result);
if (!ok) { if (!ok) {

View File

@ -31,7 +31,10 @@
/// @author Copyright 2014, triAGENS GmbH, Cologne, Germany /// @author Copyright 2014, triAGENS GmbH, Cologne, Germany
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
(function(args) { (function() {
var args = global.UPGRADE_ARGS;
delete global.UPGRADE_ARGS;
const internal = require("internal"); const internal = require("internal");
const fs = require("fs"); const fs = require("fs");
const console = require("console"); const console = require("console");
@ -40,7 +43,7 @@
const db = internal.db; const db = internal.db;
const shallowCopy = require("@arangodb/util").shallowCopy; const shallowCopy = require("@arangodb/util").shallowCopy;
const defaultRootPW = require("process").env.ARANGODB_DEFAULT_ROOT_PASSWORD || ""; const defaultRootPW = args.password || "";
function upgrade() { function upgrade() {
@ -776,8 +779,6 @@
// set this global variable to inform the server we actually got until here... // set this global variable to inform the server we actually got until here...
global.UPGRADE_STARTED = true; global.UPGRADE_STARTED = true;
delete global.UPGRADE_ARGS;
// and run the upgrade // and run the upgrade
return upgrade(); return upgrade();
}(global.UPGRADE_ARGS)); }());

View File

@ -25,8 +25,8 @@
#include "ApplicationFeatures/ApplicationFeature.h" #include "ApplicationFeatures/ApplicationFeature.h"
#include "ApplicationFeatures/PrivilegeFeature.h" #include "ApplicationFeatures/PrivilegeFeature.h"
#include "Basics/StringUtils.h" #include "Basics/StringUtils.h"
#include "ProgramOptions/ArgumentParser.h"
#include "Logger/Logger.h" #include "Logger/Logger.h"
#include "ProgramOptions/ArgumentParser.h"
using namespace arangodb::application_features; using namespace arangodb::application_features;
using namespace arangodb::basics; using namespace arangodb::basics;
@ -194,7 +194,6 @@ void ApplicationServer::run(int argc, char* argv[]) {
reportServerProgress(_state); reportServerProgress(_state);
start(); start();
// wait until we get signaled the shutdown request // wait until we get signaled the shutdown request
_state = ServerState::IN_WAIT; _state = ServerState::IN_WAIT;
reportServerProgress(_state); reportServerProgress(_state);
@ -268,11 +267,13 @@ void ApplicationServer::collectOptions() {
_options->addHiddenOption("--dump-dependencies", "dump dependency graph", _options->addHiddenOption("--dump-dependencies", "dump dependency graph",
new BooleanParameter(&_dumpDependencies)); new BooleanParameter(&_dumpDependencies));
apply([this](ApplicationFeature* feature) { apply(
LOG_TOPIC(TRACE, Logger::STARTUP) << feature->name() << "::loadOptions"; [this](ApplicationFeature* feature) {
feature->collectOptions(_options); LOG_TOPIC(TRACE, Logger::STARTUP) << feature->name() << "::loadOptions";
reportFeatureProgress(_state, feature->name()); feature->collectOptions(_options);
}, true); reportFeatureProgress(_state, feature->name());
},
true);
} }
void ApplicationServer::parseOptions(int argc, char* argv[]) { void ApplicationServer::parseOptions(int argc, char* argv[]) {
@ -366,18 +367,21 @@ void ApplicationServer::setupDependencies(bool failOnMissing) {
// first check if a feature references an unknown other feature // first check if a feature references an unknown other feature
if (failOnMissing) { if (failOnMissing) {
apply([this](ApplicationFeature* feature) { apply(
for (auto& other : feature->requires()) { [this](ApplicationFeature* feature) {
if (!this->exists(other)) { for (auto& other : feature->requires()) {
fail("feature '" + feature->name() + if (!this->exists(other)) {
"' depends on unknown feature '" + other + "'"); fail("feature '" + feature->name() +
} "' depends on unknown feature '" + other + "'");
if (!this->feature(other)->isEnabled()) { }
fail("enabled feature '" + feature->name() + if (!this->feature(other)->isEnabled()) {
"' depends on other feature '" + other + "', which is disabled"); fail("enabled feature '" + feature->name() +
} "' depends on other feature '" + other +
} "', which is disabled");
}, true); }
}
},
true);
} }
// first insert all features, even the inactive ones // first insert all features, even the inactive ones
@ -478,14 +482,16 @@ void ApplicationServer::prepare() {
feature->prepare(); feature->prepare();
feature->state(FeatureState::PREPARED); feature->state(FeatureState::PREPARED);
} catch (std::exception const& ex) { } catch (std::exception const& ex) {
LOG(ERR) << "caught exception during prepare of feature " << feature->name() << ": " << ex.what(); LOG(ERR) << "caught exception during prepare of feature "
<< feature->name() << ": " << ex.what();
// restore original privileges // restore original privileges
if (!privilegesElevated) { if (!privilegesElevated) {
raisePrivilegesTemporarily(); raisePrivilegesTemporarily();
} }
throw; throw;
} catch (...) { } catch (...) {
LOG(ERR) << "caught unknown exception during prepare of feature " << feature->name(); LOG(ERR) << "caught unknown exception during prepare of feature "
<< feature->name();
// restore original privileges // restore original privileges
if (!privilegesElevated) { if (!privilegesElevated) {
raisePrivilegesTemporarily(); raisePrivilegesTemporarily();
@ -511,16 +517,19 @@ void ApplicationServer::start() {
feature->state(FeatureState::STARTED); feature->state(FeatureState::STARTED);
reportFeatureProgress(_state, feature->name()); reportFeatureProgress(_state, feature->name());
} catch (std::exception const& ex) { } catch (std::exception const& ex) {
LOG(ERR) << "caught exception during start of feature " << feature->name() << ": " << ex.what() << ". shutting down"; LOG(ERR) << "caught exception during start of feature " << feature->name()
<< ": " << ex.what() << ". shutting down";
abortStartup = true; abortStartup = true;
} catch (...) { } catch (...) {
LOG(ERR) << "caught unknown exception during start of feature " << feature->name() << ". shutting down"; LOG(ERR) << "caught unknown exception during start of feature "
<< feature->name() << ". shutting down";
abortStartup = true; abortStartup = true;
} }
if (abortStartup) { if (abortStartup) {
// try to stop all feature that we just started // try to stop all feature that we just started
for (auto it = _orderedFeatures.rbegin(); it != _orderedFeatures.rend(); ++it) { for (auto it = _orderedFeatures.rbegin(); it != _orderedFeatures.rend();
++it) {
auto feature = *it; auto feature = *it;
if (feature->state() == FeatureState::STARTED) { if (feature->state() == FeatureState::STARTED) {
LOG(TRACE) << "forcefully stopping feature " << feature->name(); LOG(TRACE) << "forcefully stopping feature " << feature->name();
@ -541,7 +550,8 @@ void ApplicationServer::start() {
void ApplicationServer::stop() { void ApplicationServer::stop() {
LOG_TOPIC(TRACE, Logger::STARTUP) << "ApplicationServer::stop"; LOG_TOPIC(TRACE, Logger::STARTUP) << "ApplicationServer::stop";
for (auto it = _orderedFeatures.rbegin(); it != _orderedFeatures.rend(); ++it) { for (auto it = _orderedFeatures.rbegin(); it != _orderedFeatures.rend();
++it) {
auto feature = *it; auto feature = *it;
LOG_TOPIC(TRACE, Logger::STARTUP) << feature->name() << "::stop"; LOG_TOPIC(TRACE, Logger::STARTUP) << feature->name() << "::stop";
@ -554,7 +564,8 @@ void ApplicationServer::stop() {
void ApplicationServer::unprepare() { void ApplicationServer::unprepare() {
LOG_TOPIC(TRACE, Logger::STARTUP) << "ApplicationServer::unprepare"; LOG_TOPIC(TRACE, Logger::STARTUP) << "ApplicationServer::unprepare";
for (auto it = _orderedFeatures.rbegin(); it != _orderedFeatures.rend(); ++it) { for (auto it = _orderedFeatures.rbegin(); it != _orderedFeatures.rend();
++it) {
auto feature = *it; auto feature = *it;
LOG_TOPIC(TRACE, Logger::STARTUP) << feature->name() << "::unprepare"; LOG_TOPIC(TRACE, Logger::STARTUP) << feature->name() << "::unprepare";

View File

@ -30,7 +30,8 @@ using namespace arangodb;
using namespace arangodb::options; using namespace arangodb::options;
ShutdownFeature::ShutdownFeature( ShutdownFeature::ShutdownFeature(
application_features::ApplicationServer* server, std::vector<std::string> const& features) application_features::ApplicationServer* server,
std::vector<std::string> const& features)
: ApplicationFeature(server, "Shutdown") { : ApplicationFeature(server, "Shutdown") {
setOptional(true); setOptional(true);
requiresElevatedPrivileges(false); requiresElevatedPrivileges(false);
@ -43,6 +44,4 @@ ShutdownFeature::ShutdownFeature(
} }
} }
void ShutdownFeature::start() { void ShutdownFeature::start() { server()->beginShutdown(); }
server()->beginShutdown();
}