1
0
Fork 0

Various authentication related issues (#2824)

This commit is contained in:
Simon Grätzer 2017-07-18 22:22:09 +02:00 committed by Frank Celler
parent 17a8049e50
commit f50a36181d
17 changed files with 184 additions and 203 deletions

View File

@ -81,8 +81,7 @@ struct LPComputation : public VertexComputation<LPValue, int8_t, uint64_t> {
uint64_t newCommunity = mutableVertexData()->currentCommunity;
if (messages.size() == 1) {
newCommunity = std::min(**messages, newCommunity);
}
if (messages.size() > 1) {
} else if (messages.size() > 1) {
newCommunity = mostFrequent(messages);
}

View File

@ -22,16 +22,17 @@
#include "InitDatabaseFeature.h"
#include <iostream>
#include "Basics/FileUtils.h"
#include "Basics/terminal-utils.h"
#include "Cluster/ServerState.h"
#include "Logger/Logger.h"
#include "Logger/LoggerFeature.h"
#include "ProgramOptions/ProgramOptions.h"
#include "ProgramOptions/Section.h"
#include "RestServer/DatabasePathFeature.h"
#include <iostream>
using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::basics;
@ -71,6 +72,7 @@ void InitDatabaseFeature::validateOptions(
if (_initDatabase || _restoreAdmin) {
ApplicationServer::forceDisableFeatures(_nonServerFeatures);
ServerState::instance()->setRole(ServerState::ROLE_SINGLE);
}
}
@ -140,7 +142,7 @@ std::string InitDatabaseFeature::readPassword(std::string const& message) {
void InitDatabaseFeature::checkEmptyDatabase() {
auto database = ApplicationServer::getFeature<DatabasePathFeature>("DatabasePath");
std::string path = database->directory();
std::string journals = database->subdirectoryName("journals");
std::string serverFile = database->subdirectoryName("SERVER");
bool empty = false;
std::string message;
@ -153,10 +155,10 @@ void InitDatabaseFeature::checkEmptyDatabase() {
goto doexit;
}
if (FileUtils::exists(journals)) {
if (!FileUtils::isDirectory(journals)) {
if (FileUtils::exists(serverFile)) {
if (FileUtils::isDirectory(serverFile)) {
message =
"database journals path '" + journals + "' is not a directory";
"database SERVER '" + serverFile + "' is not a file";
code = EXIT_FAILURE;
goto doexit;
}
@ -168,7 +170,7 @@ void InitDatabaseFeature::checkEmptyDatabase() {
}
if (!empty) {
message = "database already initialized, refusing to change root user";
message = "database already initialized, refusing to initialize it again";
goto doexit;
}

View File

@ -23,6 +23,7 @@
#include "UpgradeFeature.h"
#include "Cluster/ClusterFeature.h"
#include "GeneralServer/AuthenticationFeature.h"
#include "Logger/Logger.h"
#include "ProgramOptions/ProgramOptions.h"
#include "ProgramOptions/Section.h"
@ -101,15 +102,46 @@ void UpgradeFeature::validateOptions(std::shared_ptr<ProgramOptions> options) {
void UpgradeFeature::start() {
auto init =
ApplicationServer::getFeature<InitDatabaseFeature>("InitDatabase");
AuthInfo *ai = AuthenticationFeature::INSTANCE->authInfo();
// upgrade the database
if (_upgradeCheck) {
upgradeDatabase(init->defaultPassword());
upgradeDatabase();
if (!init->restoreAdmin() && !init->defaultPassword().empty()) {
ai->updateUser("root", [&](AuthUserEntry& entry) {
entry.updatePassword(init->defaultPassword());
});
}
}
// change admin user
if (init->restoreAdmin()) {
changeAdminPassword(init->defaultPassword());
Result res;
res = ai->removeAllUsers();
if (res.fail()) {
LOG_TOPIC(WARN, arangodb::Logger::FIXME) << "failed to create clear users: "
<< res.errorMessage();
*_result = EXIT_FAILURE;
return;
}
res = ai->storeUser(true, "root", init->defaultPassword(), true);
if (res.fail() && res.errorNumber() == TRI_ERROR_USER_NOT_FOUND) {
res = ai->storeUser(false, "root", init->defaultPassword(), true);
}
if (res.fail()) {
LOG_TOPIC(WARN, arangodb::Logger::FIXME) << "failed to create root user: "
<< res.errorMessage();
*_result = EXIT_FAILURE;
return;
}
*_result = EXIT_SUCCESS;
}
// and force shutdown
@ -117,71 +149,12 @@ void UpgradeFeature::start() {
if (init->isInitDatabase()) {
*_result = EXIT_SUCCESS;
}
server()->beginShutdown();
}
}
void UpgradeFeature::changeAdminPassword(std::string const& defaultPassword) {
LOG_TOPIC(TRACE, arangodb::Logger::FIXME) << "starting to restore admin user";
auto* systemVocbase = DatabaseFeature::DATABASE->systemDatabase();
// enter context and isolate
{
V8Context* context =
V8DealerFeature::DEALER->enterContext(systemVocbase, true, 0);
if (context == nullptr) {
LOG_TOPIC(FATAL, arangodb::Logger::FIXME) << "could not enter context #0";
FATAL_ERROR_EXIT();
}
TRI_DEFER(V8DealerFeature::DEALER->exitContext(context));
{
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_TOPIC(DEBUG, arangodb::Logger::FIXME) << "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();
}
}
// and return from the context
LOG_TOPIC(TRACE, arangodb::Logger::FIXME) << "finished to restore admin user";
*_result = EXIT_SUCCESS;
}
void UpgradeFeature::upgradeDatabase(std::string const& defaultPassword) {
void UpgradeFeature::upgradeDatabase() {
LOG_TOPIC(TRACE, arangodb::Logger::FIXME) << "starting database init/upgrade";
DatabaseFeature* databaseFeature = application_features::ApplicationServer::getFeature<DatabaseFeature>("Database");
@ -224,8 +197,6 @@ void UpgradeFeature::upgradeDatabase(std::string const& defaultPassword) {
args->Set(TRI_V8_ASCII_STRING2(context->_isolate, "upgrade"),
v8::Boolean::New(context->_isolate, _upgrade));
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);

View File

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

View File

@ -1026,7 +1026,8 @@ static void JS_DropVocbaseCol(v8::FunctionCallbackInfo<v8::Value> const& args) {
}
}
if (auth->isActive()) {
if (auth->isActive() && (ServerState::instance()->isCoordinator() ||
!ServerState::instance()->isRunningInCluster())) {
auth->authInfo()->enumerateUsers([&](AuthUserEntry& entry) {
entry.removeCollection(dbname, collName);
});
@ -2766,17 +2767,6 @@ static void JS_TruncateVocbaseCol(
TRI_V8_THROW_EXCEPTION_INTERNAL("cannot extract collection");
}
AuthenticationFeature* auth = FeatureCacheFeature::instance()->authenticationFeature();
if (auth->isActive() && ExecContext::CURRENT != nullptr) {
CollectionNameResolver resolver(collection->vocbase());
std::string const cName = resolver.getCollectionNameCluster(collection->cid());
AuthLevel level = auth->canUseCollection(ExecContext::CURRENT->user(),
collection->vocbase()->name(), cName);
if (level != AuthLevel::RW) {
TRI_V8_THROW_EXCEPTION(TRI_ERROR_FORBIDDEN);
}
}
// optionally specify non trx remove
bool unsafeTruncate = false;
if (args.Length() > 0) {

View File

@ -304,8 +304,11 @@ static void CreateVocBase(v8::FunctionCallbackInfo<v8::Value> const& args,
if (result.IsEmpty()) {
TRI_V8_THROW_EXCEPTION_MEMORY();
}
// in case of success we grant the creating user RW access
if (auth->isActive() && ExecContext::CURRENT != nullptr) {
if (auth->isActive() && ExecContext::CURRENT != nullptr &&
(ServerState::instance()->isCoordinator() ||
!ServerState::instance()->isRunningInCluster())) {
// this should not fail, we can not get here without database RW access
auth->authInfo()->updateUser(ExecContext::CURRENT->user(),
[&](AuthUserEntry& entry) {

View File

@ -229,18 +229,21 @@ void AuthInfo::loadFromDB() {
MUTEX_LOCKER(locker, _loadFromDBLock);
// double check to be sure after we got the lock
if (!_outdated) {
return;
}
auto role = ServerState::instance()->getRole();
if (role != ServerState::ROLE_SINGLE &&
role != ServerState::ROLE_COORDINATOR) {
TRI_ASSERT(false);
_outdated = false;
return;
}
{
if (_authInfo.empty()) {// should only work once
WRITE_LOCKER(writeLocker, _authInfoLock);
insertInitial();
}
@ -252,15 +255,16 @@ void AuthInfo::loadFromDB() {
if (builder) {
VPackSlice usersSlice = builder->slice();
if (usersSlice.length() == 0) {
insertInitial();
} else {
if (usersSlice.length() != 0) {
parseUsers(usersSlice);
}
_outdated = false;
} else {
}
if (_authInfo.empty()) {
insertInitial();
}
_outdated = false;
}
// private, must be called with _authInfoLock in write mode
@ -461,6 +465,7 @@ static Result UpdateUser(VPackSlice const& user) {
Result AuthInfo::enumerateUsers(
std::function<void(AuthUserEntry&)> const& func) {
loadFromDB();
// we require an consisten view on the user object
{
WRITE_LOCKER(guard, _authInfoLock);
@ -484,6 +489,7 @@ Result AuthInfo::updateUser(std::string const& user,
if (user.empty()) {
return TRI_ERROR_USER_NOT_FOUND;
}
loadFromDB();
VPackBuilder data;
{ // we require an consisten view on the user object
WRITE_LOCKER(guard, _authInfoLock);
@ -506,6 +512,7 @@ Result AuthInfo::updateUser(std::string const& user,
Result AuthInfo::accessUser(std::string const& user,
std::function<void(AuthUserEntry const&)> const& func) {
loadFromDB();
READ_LOCKER(guard, _authInfoLock);
auto it = _authInfo.find(user);
if (it != _authInfo.end()) {
@ -516,6 +523,7 @@ Result AuthInfo::accessUser(std::string const& user,
}
VPackBuilder AuthInfo::serializeUser(std::string const& user) {
loadFromDB();
VPackBuilder doc = QueryUser(_queryRegistry, user);
VPackBuilder result;
if (!doc.isEmpty()) {
@ -524,6 +532,42 @@ VPackBuilder AuthInfo::serializeUser(std::string const& user) {
return result;
}
static Result removeUserInternal(AuthUserEntry const& entry) {
TRI_ASSERT(!entry.key().empty());
TRI_vocbase_t* vocbase = DatabaseFeature::DATABASE->systemDatabase();
if (vocbase == nullptr) {
return Result(TRI_ERROR_INTERNAL);
}
// we cannot set this execution context, otherwise the transaction
// will ask us again for permissions and we get a deadlock
ExecContext* oldExe = ExecContext::CURRENT;
ExecContext::CURRENT = nullptr;
TRI_DEFER(ExecContext::CURRENT = oldExe);
std::shared_ptr<transaction::Context> ctx(
new transaction::StandaloneContext(vocbase));
SingleCollectionTransaction trx(ctx, TRI_COL_NAME_USERS,
AccessMode::Type::WRITE);
trx.addHint(transaction::Hints::Hint::SINGLE_OPERATION);
Result res = trx.begin();
if (res.ok()) {
VPackBuilder builder;
{
VPackObjectBuilder guard(&builder);
builder.add(StaticStrings::KeyString, VPackValue(entry.key()));
// TODO maybe protect with a revision ID?
}
OperationResult result =
trx.remove(TRI_COL_NAME_USERS, builder.slice(), OperationOptions());
res = trx.finish(result.code);
}
return res;
}
Result AuthInfo::removeUser(std::string const& user) {
if (user.empty()) {
return TRI_ERROR_USER_NOT_FOUND;
@ -534,57 +578,51 @@ Result AuthInfo::removeUser(std::string const& user) {
loadFromDB();
WRITE_LOCKER(guard, _authInfoLock);
auto it = _authInfo.find(user);
auto const& it = _authInfo.find(user);
if (it == _authInfo.end()) {
return Result(TRI_ERROR_USER_NOT_FOUND);
return TRI_ERROR_USER_NOT_FOUND;
}
TRI_ASSERT(!it->second.key().empty());
TRI_vocbase_t* vocbase = DatabaseFeature::DATABASE->systemDatabase();
if (vocbase == nullptr) {
return Result(TRI_ERROR_INTERNAL);
}
// we cannot set this execution context, otherwise the transaction
// will ask us again for permissions and we get a deadlock
ExecContext* oldExe = ExecContext::CURRENT;
ExecContext::CURRENT = nullptr;
TRI_DEFER(ExecContext::CURRENT = oldExe);
std::shared_ptr<transaction::Context> ctx(
new transaction::StandaloneContext(vocbase));
SingleCollectionTransaction trx(ctx, TRI_COL_NAME_USERS,
AccessMode::Type::WRITE);
trx.addHint(transaction::Hints::Hint::SINGLE_OPERATION);
Result res = trx.begin();
Result res = removeUserInternal(it->second);
if (res.ok()) {
VPackBuilder builder;
{
VPackObjectBuilder guard(&builder);
builder.add(StaticStrings::KeyString, VPackValue(it->second.key()));
// TODO maybe protect with a revision ID?
}
OperationResult result =
trx.remove(TRI_COL_NAME_USERS, builder.slice(), OperationOptions());
res = trx.finish(result.code);
if (res.ok()) {
_authInfo.erase(it);
reloadAllUsers();
}
_authInfo.erase(it);
reloadAllUsers();
}
return res;
}
Result AuthInfo::removeAllUsers() {
loadFromDB();
WRITE_LOCKER(guard, _authInfoLock);
Result res;
for (auto const& pair : _authInfo) {
res = removeUserInternal(pair.second);
if (!res.ok()) {
break;
}
}
{// do not get into race conditions with loadFromDB
MUTEX_LOCKER(locker, _loadFromDBLock);
_authInfo.clear();
_outdated = true;
}
reloadAllUsers();
return res;
}
VPackBuilder AuthInfo::getConfigData(std::string const& username) {
loadFromDB();
VPackBuilder bb = QueryUser(_queryRegistry, username);
return VPackBuilder(bb.slice().get("configData"));
}
Result AuthInfo::setConfigData(std::string const& user,
velocypack::Slice const& data) {
loadFromDB();
READ_LOCKER(guard, _authInfoLock);
auto it = _authInfo.find(user);
if (it == _authInfo.end()) {
return Result(TRI_ERROR_USER_NOT_FOUND);
@ -601,12 +639,16 @@ Result AuthInfo::setConfigData(std::string const& user,
}
VPackBuilder AuthInfo::getUserData(std::string const& username) {
loadFromDB();
VPackBuilder bb = QueryUser(_queryRegistry, username);
return VPackBuilder(bb.slice().get("userData"));
}
Result AuthInfo::setUserData(std::string const& user,
velocypack::Slice const& data) {
loadFromDB();
READ_LOCKER(guard, _authInfoLock);
auto it = _authInfo.find(user);
if (it == _authInfo.end()) {
return Result(TRI_ERROR_USER_NOT_FOUND);
@ -702,8 +744,6 @@ AuthLevel AuthInfo::canUseCollection(std::string const& username,
// public called from HttpCommTask.cpp and VstCommTask.cpp
AuthResult AuthInfo::checkAuthentication(AuthenticationMethod authType,
std::string const& secret) {
loadFromDB();
switch (authType) {
case AuthenticationMethod::BASIC:
return checkAuthenticationBasic(secret);
@ -718,10 +758,15 @@ AuthResult AuthInfo::checkAuthentication(AuthenticationMethod authType,
// private
AuthResult AuthInfo::checkAuthenticationBasic(std::string const& secret) {
auto role = ServerState::instance()->getRole();
if (role != ServerState::ROLE_SINGLE &&
role != ServerState::ROLE_COORDINATOR) {
return AuthResult();
}
{
READ_LOCKER(guard, _authInfoLock);
auto const& it = _authBasicCache.find(secret);
if (it != _authBasicCache.end()) {
return it->second;
}
@ -729,9 +774,8 @@ AuthResult AuthInfo::checkAuthenticationBasic(std::string const& secret) {
std::string const up = StringUtils::decodeBase64(secret);
std::string::size_type n = up.find(':', 0);
if (n == std::string::npos || n == 0 || n + 1 > up.size()) {
LOG_TOPIC(TRACE, arangodb::Logger::FIXME)
LOG_TOPIC(TRACE, arangodb::Logger::AUTHENTICATION)
<< "invalid authentication data found, cannot extract "
"username/password";
return AuthResult();
@ -741,7 +785,6 @@ AuthResult AuthInfo::checkAuthenticationBasic(std::string const& secret) {
std::string password = up.substr(n + 1);
AuthResult result = checkPassword(username, password);
{
WRITE_LOCKER(guard, _authInfoLock);

View File

@ -90,6 +90,7 @@ class AuthInfo {
std::function<void(AuthUserEntry const&)> const&);
velocypack::Builder serializeUser(std::string const& user);
Result removeUser(std::string const& user);
Result removeAllUsers();
velocypack::Builder getConfigData(std::string const& user);
Result setConfigData(std::string const& user, velocypack::Slice const& data);

View File

@ -463,7 +463,8 @@ arangodb::Result Databases::drop(TRI_vocbase_t* systemVocbase,
}
auto auth = FeatureCacheFeature::instance()->authenticationFeature();
if (auth->isActive()) {
if (auth->isActive() && (ServerState::instance()->isCoordinator() ||
!ServerState::instance()->isRunningInCluster())) {
auth->authInfo()->enumerateUsers(
[&](AuthUserEntry& entry) { entry.removeDatabase(dbName); });
}

View File

@ -462,8 +462,10 @@ void ImportFeature::start() {
}
} else {
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "error message: "
<< ih.getErrorMessage();
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "error message:";
for (std::string const& msg : ih.getErrorMessages()) {
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << msg;
}
}
} catch (std::exception const& ex) {
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "Caught exception " << ex.what()

View File

@ -173,7 +173,7 @@ ImportHelper::ImportHelper(ClientFeature const* client,
while (true) {
uint32_t numReady = 0;
for (auto const& t : _senderThreads) {
if (t->isReady()) {
if (t->isIdle()) {
numReady++;
}
}
@ -200,7 +200,7 @@ bool ImportHelper::importDelimited(std::string const& collectionName,
_firstLine = "";
_outputBuffer.clear();
_lineBuffer.clear();
_errorMessage = "";
_errorMessages.clear();
_hasError = false;
// read and convert
@ -217,7 +217,7 @@ bool ImportHelper::importDelimited(std::string const& collectionName,
fd = TRI_TRACKED_OPEN_FILE(fileName.c_str(), O_RDONLY | TRI_O_CLOEXEC);
if (fd < 0) {
_errorMessage = TRI_LAST_ERROR_STR;
_errorMessages.push_back(TRI_LAST_ERROR_STR);
return false;
}
}
@ -235,8 +235,7 @@ bool ImportHelper::importDelimited(std::string const& collectionName,
if (fd != STDIN_FILENO) {
TRI_TRACKED_CLOSE_FILE(fd);
}
_errorMessage = "out of memory";
_errorMessages.push_back("out of memory");
return false;
}
@ -270,7 +269,7 @@ bool ImportHelper::importDelimited(std::string const& collectionName,
if (fd != STDIN_FILENO) {
TRI_TRACKED_CLOSE_FILE(fd);
}
_errorMessage = TRI_LAST_ERROR_STR;
_errorMessages.push_back(TRI_LAST_ERROR_STR);
return false;
} else if (n == 0) {
// we have read the entire file
@ -311,7 +310,7 @@ bool ImportHelper::importJson(std::string const& collectionName,
_collectionName = collectionName;
_firstLine = "";
_outputBuffer.clear();
_errorMessage = "";
_errorMessages.clear();
_hasError = false;
// read and convert
@ -328,7 +327,7 @@ bool ImportHelper::importJson(std::string const& collectionName,
fd = TRI_TRACKED_OPEN_FILE(fileName.c_str(), O_RDONLY | TRI_O_CLOEXEC);
if (fd < 0) {
_errorMessage = TRI_LAST_ERROR_STR;
_errorMessages.push_back(TRI_LAST_ERROR_STR);
return false;
}
}
@ -350,7 +349,7 @@ bool ImportHelper::importJson(std::string const& collectionName,
while (!_hasError) {
// reserve enough room to read more data
if (_outputBuffer.reserve(BUFFER_SIZE) == TRI_ERROR_OUT_OF_MEMORY) {
_errorMessage = TRI_errno_string(TRI_ERROR_OUT_OF_MEMORY);
_errorMessages.push_back(TRI_errno_string(TRI_ERROR_OUT_OF_MEMORY));
if (fd != STDIN_FILENO) {
TRI_TRACKED_CLOSE_FILE(fd);
@ -362,7 +361,7 @@ bool ImportHelper::importJson(std::string const& collectionName,
ssize_t n = TRI_READ(fd, _outputBuffer.end(), BUFFER_SIZE - 1);
if (n < 0) {
_errorMessage = TRI_LAST_ERROR_STR;
_errorMessages.push_back(TRI_LAST_ERROR_STR);
if (fd != STDIN_FILENO) {
TRI_TRACKED_CLOSE_FILE(fd);
}
@ -398,10 +397,9 @@ bool ImportHelper::importJson(std::string const& collectionName,
if (fd != STDIN_FILENO) {
TRI_TRACKED_CLOSE_FILE(fd);
}
_errorMessage =
"import file is too big. please increase the value of --batch-size "
"(currently " +
StringUtils::itoa(_maxUploadSize) + ")";
_errorMessages.push_back("import file is too big. please increase the value of --batch-size "
"(currently " +
StringUtils::itoa(_maxUploadSize) + ")");
return false;
}
@ -750,7 +748,7 @@ bool ImportHelper::truncateCollection() {
<< "unable to truncate collection '" << _collectionName
<< "', server returned status code: " << static_cast<int>(code);
_hasError = true;
_errorMessage = "Unable to overwrite collection";
_errorMessages.push_back("Unable to overwrite collection");
return false;
}
@ -832,7 +830,7 @@ SenderThread* ImportHelper::findSender() {
for (auto const& t : _senderThreads) {
if (t->hasError()) {
_hasError = true;
_errorMessage = t->errorMessage();
_errorMessages.push_back(t->errorMessage());
return nullptr;
} else if (t->isIdle()) {
return t.get();

View File

@ -233,7 +233,7 @@ class ImportHelper {
/// @return string get the error message
//////////////////////////////////////////////////////////////////////////////
std::string getErrorMessage() { return _errorMessage; }
std::vector<std::string> getErrorMessages() { return _errorMessages; }
private:
static void ProcessCsvBegin(TRI_csv_parser_t*, size_t);
@ -293,7 +293,7 @@ class ImportHelper {
std::unordered_map<std::string, std::string> _translations;
bool _hasError;
std::string _errorMessage;
std::vector<std::string> _errorMessages;
static double const ProgressStep;
};

View File

@ -58,7 +58,9 @@ class SenderThread : public arangodb::Thread {
void sendData(std::string const& url, basics::StringBuffer* sender);
bool hasError();
/// Ready to start sending
bool isReady();
/// Currently not sending data
bool isIdle();
bool isDone();

View File

@ -982,8 +982,12 @@ static void ClientConnection_importCsv(
TRI_V8_RETURN(result);
}
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_FAILED,
ih.getErrorMessage().c_str());
std::string error = "error messages:";
for (std::string const& msg : ih.getErrorMessages()) {
error.append(msg + ";\t");
}
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_FAILED, error.c_str());
TRI_V8_TRY_CATCH_END
}
@ -1046,9 +1050,13 @@ static void ClientConnection_importJson(
TRI_V8_RETURN(result);
}
std::string error = "error messages:";
for (std::string const& msg : ih.getErrorMessages()) {
error.append(msg + ";\t");
}
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_FAILED,
ih.getErrorMessage().c_str());
TRI_V8_THROW_EXCEPTION_MESSAGE(TRI_ERROR_FAILED, error.c_str());
TRI_V8_TRY_CATCH_END
}

View File

@ -971,6 +971,7 @@ function startInstanceCluster (instanceInfo, protocol, options,
throw new Error("startup timed out!");
}
}
arango.reconnect(instanceInfo.endpoint, '_system', 'root', '');
return true;
}

View File

@ -1,37 +0,0 @@
/*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;
require("internal").db._users.truncate();
const users = require("@arangodb/users");
users.save("root", args.password, true);
users.grantDatabase("root", "*", "rw");
}());

View File

@ -44,9 +44,7 @@
const db = internal.db;
const shallowCopy = require('@arangodb/util').shallowCopy;
const defaultRootPW = args.password || '';
function upgrade () {
function upgrade () {
// default replication factor for system collections
const DEFAULT_REPLICATION_FACTOR_SYSTEM = internal.DEFAULT_REPLICATION_FACTOR_SYSTEM;