mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of ssh://github.com/ArangoDB/ArangoDB into devel
This commit is contained in:
commit
b622ea68d9
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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");
|
||||||
|
|
||||||
|
|
|
@ -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");
|
||||||
|
}());
|
|
@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue