1
0
Fork 0

Merge branch 'devel' of ssh://github.com/ArangoDB/ArangoDB into devel

This commit is contained in:
Max Neunhoeffer 2016-06-09 15:30:16 +02:00
commit b622ea68d9
9 changed files with 212 additions and 68 deletions

View File

@ -49,6 +49,10 @@ void InitDatabaseFeature::collectOptions(
"initializes an empty database", "initializes an empty database",
new BooleanParameter(&_initDatabase)); new BooleanParameter(&_initDatabase));
options->addHiddenOption("--database.restore-admin",
"resets the admin users and sets a new password",
new BooleanParameter(&_restoreAdmin));
options->addHiddenOption("--database.password", options->addHiddenOption("--database.password",
"initial password of root user", "initial password of root user",
new StringParameter(&_password)); new StringParameter(&_password));
@ -73,11 +77,13 @@ void InitDatabaseFeature::prepare() {
} }
} }
if (!_initDatabase) { if (!_initDatabase && !_restoreAdmin) {
return; return;
} }
if (_initDatabase) {
checkEmptyDatabase(); checkEmptyDatabase();
}
if (!_seenPassword) { if (!_seenPassword) {
while (true) { while (true) {
@ -101,12 +107,6 @@ void InitDatabaseFeature::prepare() {
} }
} }
void InitDatabaseFeature::start() {
if (!_initDatabase) {
return;
}
}
std::string InitDatabaseFeature::readPassword(std::string const& message) { std::string InitDatabaseFeature::readPassword(std::string const& message) {
std::string password; std::string password;

View File

@ -34,15 +34,16 @@ class InitDatabaseFeature final
public: public:
std::string const& defaultPassword() const { return _password; } std::string const& defaultPassword() const { return _password; }
bool isInitDatabase() const { return _initDatabase; } bool isInitDatabase() const { return _initDatabase; }
bool restoreAdmin() const { return _restoreAdmin; }
private: private:
bool _initDatabase = false; bool _initDatabase = false;
bool _restoreAdmin = false;
std::string _password; std::string _password;
public: public:
void collectOptions(std::shared_ptr<options::ProgramOptions>) override final; void collectOptions(std::shared_ptr<options::ProgramOptions>) override final;
void validateOptions(std::shared_ptr<options::ProgramOptions>) override final; void validateOptions(std::shared_ptr<options::ProgramOptions>) override final;
void start() override final;
void prepare() override final; void prepare() override final;
private: private:

View File

@ -98,20 +98,83 @@ void UpgradeFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
} }
void UpgradeFeature::start() { void UpgradeFeature::start() {
auto init =
ApplicationServer::getFeature<InitDatabaseFeature>("InitDatabase");
// upgrade the database // upgrade the database
if (_upgradeCheck) { if (_upgradeCheck) {
upgradeDatabase(); upgradeDatabase(init->defaultPassword());
}
// change admin user
if (init->restoreAdmin()) {
changeAdminPassword(init->defaultPassword());
} }
// and force shutdown // and force shutdown
auto init = ApplicationServer::getFeature<InitDatabaseFeature>("InitDatabase"); if (_upgrade || init->isInitDatabase() || init->restoreAdmin()) {
if (_upgrade || init->isInitDatabase()) {
server()->beginShutdown(); server()->beginShutdown();
} }
} }
void UpgradeFeature::upgradeDatabase() { void UpgradeFeature::changeAdminPassword(std::string const& defaultPassword) {
LOG(TRACE) << "starting to restore admin user";
auto* systemVocbase = DatabaseFeature::DATABASE->vocbase();
// enter context and isolate
{
V8Context* context =
V8DealerFeature::DEALER->enterContext(systemVocbase, true, 0);
if (context == nullptr) {
LOG(FATAL) << "could not enter context #0";
FATAL_ERROR_EXIT();
}
{
v8::HandleScope scope(context->_isolate);
auto localContext =
v8::Local<v8::Context>::New(context->_isolate, context->_context);
localContext->Enter();
{
v8::Context::Scope contextScope(localContext);
// run upgrade script
LOG(DEBUG) << "running admin recreation script";
// special check script to be run just once in first thread (not in
// all) but for all databases
v8::HandleScope scope(context->_isolate);
v8::Handle<v8::Object> args = v8::Object::New(context->_isolate);
args->Set(TRI_V8_ASCII_STRING2(context->_isolate, "password"),
TRI_V8_STD_STRING2(context->_isolate, defaultPassword));
localContext->Global()->Set(
TRI_V8_ASCII_STRING2(context->_isolate, "UPGRADE_ARGS"), args);
auto startupLoader = V8DealerFeature::DEALER->startupLoader();
startupLoader->executeGlobalScript(context->_isolate, localContext,
"server/restore-admin-user.js");
}
// finally leave the context. otherwise v8 will crash with assertion
// failure when we delete the context locker below
localContext->Exit();
}
V8DealerFeature::DEALER->exitContext(context);
}
// and return from the context
LOG(TRACE) << "finished to restore admin user";
}
void UpgradeFeature::upgradeDatabase(std::string const& defaultPassword) {
LOG(TRACE) << "starting database init/upgrade"; LOG(TRACE) << "starting database init/upgrade";
auto* server = DatabaseServerFeature::SERVER; auto* server = DatabaseServerFeature::SERVER;
@ -154,14 +217,8 @@ void UpgradeFeature::upgradeDatabase() {
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>( args->Set(TRI_V8_ASCII_STRING2(context->_isolate, "password"),
"InitDatabase"); TRI_V8_STD_STRING2(context->_isolate, defaultPassword));
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);

View File

@ -41,7 +41,8 @@ class UpgradeFeature final : public application_features::ApplicationFeature {
bool _upgradeCheck; bool _upgradeCheck;
private: private:
void upgradeDatabase(); void changeAdminPassword(std::string const& defaultPassword);
void upgradeDatabase(std::string const& defaultPassword);
private: private:
int* _result; int* _result;

View File

@ -132,6 +132,7 @@ const optionsDocumentation = [
]; ];
const optionsDefaults = { const optionsDefaults = {
"agencySize": 3,
"build": "", "build": "",
"buildType": "", "buildType": "",
"cleanup": true, "cleanup": true,
@ -1888,6 +1889,7 @@ function splitBuckets(options, cases) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
let allTests = [ let allTests = [
"agency",
"arangosh", "arangosh",
"authentication", "authentication",
"authentication_parameters", "authentication_parameters",
@ -3751,9 +3753,6 @@ testFuncs.agency = function(options) {
options.agency = true; options.agency = true;
options.cluster = false; options.cluster = false;
if (options.agencySize === undefined) {
options.agencySize = 1;
}
let instanceInfo = startInstance("tcp", options, {}, "agency"); let instanceInfo = startInstance("tcp", options, {}, "agency");

View File

@ -0,0 +1,40 @@
/*jshint -W051:true, -W069:true */
'use strict';
////////////////////////////////////////////////////////////////////////////////
/// 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 Frank Celler
/// @author Copyright 2016, ArangoDB GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
(function() {
var args = global.UPGRADE_ARGS;
delete global.UPGRADE_ARGS;
const users = require("@arangodb/users");
try {
users.remove("root");
} catch (e) {
}
users.save("root", args.password, true);
users.grantDatabase("root", "*", "rw");
}());

View File

@ -24,9 +24,9 @@
#include <iostream> #include <iostream>
#include "Logger/Logger.h"
#include "Basics/FileUtils.h" #include "Basics/FileUtils.h"
#include "Basics/StringUtils.h" #include "Basics/StringUtils.h"
#include "Logger/Logger.h"
#include "ProgramOptions/IniFileParser.h" #include "ProgramOptions/IniFileParser.h"
#include "ProgramOptions/ProgramOptions.h" #include "ProgramOptions/ProgramOptions.h"
#include "ProgramOptions/Section.h" #include "ProgramOptions/Section.h"
@ -51,42 +51,63 @@ void ConfigFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
options->addOption("--configuration,-c", "the configuration file or 'none'", options->addOption("--configuration,-c", "the configuration file or 'none'",
new StringParameter(&_file)); new StringParameter(&_file));
// add --config as an alias for --configuration. both point to the same variable! // add --config as an alias for --configuration. both point to the same
// variable!
options->addHiddenOption("--config", "the configuration file or 'none'", options->addHiddenOption("--config", "the configuration file or 'none'",
new StringParameter(&_file)); new StringParameter(&_file));
options->addOption("--check-configuration", "check the configuration and exists", options->addOption("--check-configuration",
"check the configuration and exists",
new BooleanParameter(&_checkConfiguration)); new BooleanParameter(&_checkConfiguration));
} }
void ConfigFeature::loadOptions(std::shared_ptr<ProgramOptions> options) { void ConfigFeature::loadOptions(std::shared_ptr<ProgramOptions> options) {
loadConfigFile(options); loadConfigFile(options, _progname);
if (_checkConfiguration) { if (_checkConfiguration) {
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
} }
void ConfigFeature::loadConfigFile(std::shared_ptr<ProgramOptions> options) { void ConfigFeature::loadConfigFile(std::shared_ptr<ProgramOptions> options,
std::string const& progname) {
if (StringUtils::tolower(_file) == "none") { if (StringUtils::tolower(_file) == "none") {
LOG_TOPIC(DEBUG, Logger::CONFIG) << "use no config file at all"; LOG_TOPIC(DEBUG, Logger::CONFIG) << "use no config file at all";
return; return;
} }
IniFileParser parser(options.get()); std::vector<std::string> files;
std::set<std::string> seen;
// always prefer an explicitly given config file // always prefer an explicitly given config file
if (!_file.empty()) { if (_file.empty()) {
files.emplace_back(progname);
} else {
LOG_TOPIC(DEBUG, Logger::CONFIG) << "using user supplied conifg file '" LOG_TOPIC(DEBUG, Logger::CONFIG) << "using user supplied conifg file '"
<< _file << "'"; << _file << "'";
IniFileParser parser(options.get());
if (!parser.parse(_file)) { if (!parser.parse(_file)) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
return; auto includes = parser.includes();
files.insert(files.end(), includes.begin(), includes.end());
LOG_TOPIC(DEBUG, Logger::CONFIG) << "seen @includes: " << includes;
} }
for (size_t i = 0; i < files.size(); ++i) {
auto name = files[i];
if (seen.find(name) != seen.end()) {
LOG(FATAL) << "circluar includes, seen '" << name << "' twice";
FATAL_ERROR_EXIT();
}
seen.insert(name);
// clang-format off // clang-format off
// //
// check in order: // check in order:
@ -98,7 +119,7 @@ void ConfigFeature::loadConfigFile(std::shared_ptr<ProgramOptions> options) {
// //
// clang-format on // clang-format on
std::string basename = _progname + ".conf"; std::string basename = name + ".conf";
std::string filename = std::string filename =
FileUtils::buildFilename(FileUtils::currentDirectory(), basename); FileUtils::buildFilename(FileUtils::currentDirectory(), basename);
@ -111,7 +132,8 @@ void ConfigFeature::loadConfigFile(std::shared_ptr<ProgramOptions> options) {
LOG_TOPIC(DEBUG, Logger::CONFIG) << "checking '" << filename << "'"; LOG_TOPIC(DEBUG, Logger::CONFIG) << "checking '" << filename << "'";
if (!FileUtils::exists(filename)) { if (!FileUtils::exists(filename)) {
filename = FileUtils::buildFilename(FileUtils::homeDirectory(), basename); filename =
FileUtils::buildFilename(FileUtils::homeDirectory(), basename);
LOG_TOPIC(DEBUG, Logger::CONFIG) << "checking '" << filename << "'"; LOG_TOPIC(DEBUG, Logger::CONFIG) << "checking '" << filename << "'";
@ -129,6 +151,8 @@ void ConfigFeature::loadConfigFile(std::shared_ptr<ProgramOptions> options) {
} }
} }
IniFileParser parser(options.get());
std::string local = filename + ".local"; std::string local = filename + ".local";
LOG_TOPIC(DEBUG, Logger::CONFIG) << "checking override '" << local << "'"; LOG_TOPIC(DEBUG, Logger::CONFIG) << "checking override '" << local << "'";
@ -146,4 +170,8 @@ void ConfigFeature::loadConfigFile(std::shared_ptr<ProgramOptions> options) {
if (!parser.parse(filename)) { if (!parser.parse(filename)) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
auto includes = parser.includes();
files.insert(files.end(), includes.begin(), includes.end());
}
} }

View File

@ -40,7 +40,8 @@ class ConfigFeature final : public application_features::ApplicationFeature {
bool _checkConfiguration; bool _checkConfiguration;
private: private:
void loadConfigFile(std::shared_ptr<options::ProgramOptions>); void loadConfigFile(std::shared_ptr<options::ProgramOptions>,
std::string const& progname);
private: private:
std::string _progname; std::string _progname;

View File

@ -47,6 +47,10 @@ class IniFileParser {
_matchers.assignment = std::regex( _matchers.assignment = std::regex(
"^[ \t]*(([-_A-Za-z0-9]*\\.)?[-_A-Za-z0-9]*)[ \t]*=[ \t]*(.*?)?[ \t]*$", "^[ \t]*(([-_A-Za-z0-9]*\\.)?[-_A-Za-z0-9]*)[ \t]*=[ \t]*(.*?)?[ \t]*$",
std::regex::ECMAScript); std::regex::ECMAScript);
// an include line
_matchers.include = std::regex(
"^[ \t]*@include[ \t]*([-_A-Za-z0-9]*)[ \t]*$",
std::regex::ECMAScript);
} }
// parse a config file. returns true if all is well, false otherwise // parse a config file. returns true if all is well, false otherwise
@ -80,6 +84,12 @@ class IniFileParser {
if (std::regex_match(line, match, _matchers.section)) { if (std::regex_match(line, match, _matchers.section)) {
// found section // found section
currentSection = match[1].str(); currentSection = match[1].str();
} else if (std::regex_match(line, match, _matchers.include)) {
// found include
std::string option;
std::string value(match[1].str());
_includes.emplace_back(value);
} else if (std::regex_match(line, match, _matchers.assignment)) { } else if (std::regex_match(line, match, _matchers.assignment)) {
// found assignment // found assignment
std::string option; std::string option;
@ -107,13 +117,20 @@ class IniFileParser {
return true; return true;
} }
// seen includes
std::vector<std::string> const& includes() const {
return _includes;
}
private: private:
ProgramOptions* _options; ProgramOptions* _options;
std::vector<std::string> _includes;
struct { struct {
std::regex comment; std::regex comment;
std::regex section; std::regex section;
std::regex assignment; std::regex assignment;
std::regex include;
} _matchers; } _matchers;
}; };
} }