1
0
Fork 0

Merge branch 'devel' of github.com:arangodb/arangodb into devel

This commit is contained in:
hkernbach 2016-04-29 12:46:43 +02:00
commit bcfb356e9e
11 changed files with 444 additions and 488 deletions

View File

@ -3,7 +3,7 @@ set -e
TAG=1 TAG=1
if [ "$1" == "--no-tag" ]; then if [ "$1" == "--no-commit" ]; then
TAG=0 TAG=0
shift shift
fi fi
@ -32,9 +32,9 @@ VERSION_MINOR=`echo $VERSION | awk -F. '{print $2}'`
VERSION_REVISION=`echo $VERSION | awk -F. '{print $3}'` VERSION_REVISION=`echo $VERSION | awk -F. '{print $3}'`
cat CMakeLists.txt \ cat CMakeLists.txt \
| sed -e "s~set(ARANGODB_VERSION_MAJOR.*~set(ARANGODB_VERSION_MAJOR \"$VERSION_MAJOR\")" \ | sed -e "s~set(ARANGODB_VERSION_MAJOR.*~set(ARANGODB_VERSION_MAJOR \"$VERSION_MAJOR\")~" \
| sed -e "s~set(ARANGODB_VERSION_MINOR.*~set(ARANGODB_VERSION_MINOR \"$VERSION_MINOR\")" \ | sed -e "s~set(ARANGODB_VERSION_MINOR.*~set(ARANGODB_VERSION_MINOR \"$VERSION_MINOR\")~" \
| sed -e "s~set(ARANGODB_VERSION_REVISION.*~set(ARANGODB_VERSION_REVISION \"$VERSION_REVISION\")" \ | sed -e "s~set(ARANGODB_VERSION_REVISION.*~set(ARANGODB_VERSION_REVISION \"$VERSION_REVISION\")~" \
> CMakeLists.txt.tmp > CMakeLists.txt.tmp
mv CMakeLists.txt.tmp CMakeLists.txt mv CMakeLists.txt.tmp CMakeLists.txt
@ -42,18 +42,22 @@ mv CMakeLists.txt.tmp CMakeLists.txt
CMAKE_CONFIGURE="-DUSE_MAINTAINER_MODE=ON" CMAKE_CONFIGURE="-DUSE_MAINTAINER_MODE=ON"
if [ `uname` == "Darwin" ]; then if [ `uname` == "Darwin" ]; then
CMAKE_CONFIGURE="${CMAKE_CONFIGURE} -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl" CMAKE_CONFIGURE="${CMAKE_CONFIGURE} -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl -DCMAKE_OSX_DEPLOYMENT_TARGET=10.11"
fi fi
if test 0 = 1; then
echo "COMPILING"
rm -rf build && mkdir build rm -rf build && mkdir build
./scripts/jsint.sh
( (
cd build cd build
cmake .. ${CMAKE_CONFIGURE} cmake .. ${CMAKE_CONFIGURE}
make -j 8 make -j 8
) )
fi
echo "LINTING"
./utils/jslint.sh
git add -f \ git add -f \
README \ README \
@ -67,13 +71,13 @@ git add -f \
js/common/bootstrap/errors.js \ js/common/bootstrap/errors.js \
CMakeLists.txt CMakeLists.txt
( echo "SWAGGER"
cd build ./utils/generateSwagger.sh
make swagger
)
./scripts/generateExamples echo "EXAMPLES"
./utils/generateExamples.sh
echo "GRUNT"
( (
cd js/apps/system/_admin/aardvark/APP cd js/apps/system/_admin/aardvark/APP
npm install --only=dev npm install --only=dev
@ -82,6 +86,7 @@ git add -f \
git add -f Documentation/Examples/*.generated git add -f Documentation/Examples/*.generated
echo "DOCUMENTATION"
cd Documentation/Books; make cd Documentation/Books; make
case "$TAG" in case "$TAG" in
@ -94,6 +99,8 @@ case "$TAG" in
esac esac
if [ "$TAG" == "1" ]; then if [ "$TAG" == "1" ]; then
echo "COMMIT"
git commit -m "release version $VERSION" -a git commit -m "release version $VERSION" -a
git push git push

View File

@ -21,16 +21,16 @@
/// @author Kaveh Vahedipour /// @author Kaveh Vahedipour
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include "Rest/HttpRequest.h"
#include "Rest/Version.h"
#include "RestAgencyHandler.h" #include "RestAgencyHandler.h"
#include "Agency/Agent.h"
#include <velocypack/Builder.h> #include <velocypack/Builder.h>
#include <velocypack/velocypack-aliases.h> #include <velocypack/velocypack-aliases.h>
#include "Agency/Agent.h"
#include "Basics/StaticStrings.h"
#include "Logger/Logger.h" #include "Logger/Logger.h"
#include "Rest/HttpRequest.h"
#include "Rest/Version.h"
using namespace arangodb; using namespace arangodb;
@ -74,8 +74,7 @@ void RestAgencyHandler::redirectRequest(arangodb::consensus::id_t leaderId) {
std::string url = Endpoint::uriForm( std::string url = Endpoint::uriForm(
_agent->config().endpoints.at(leaderId)) + _request->requestPath(); _agent->config().endpoints.at(leaderId)) + _request->requestPath();
createResponse(GeneralResponse::ResponseCode::TEMPORARY_REDIRECT); createResponse(GeneralResponse::ResponseCode::TEMPORARY_REDIRECT);
static std::string const location = "location"; _response->setHeaderNC(StaticStrings::Location, url);
_response->setHeaderNC(location, url);
} catch (std::exception const& e) { } catch (std::exception const& e) {
LOG_TOPIC(WARN, Logger::AGENCY) << e.what(); LOG_TOPIC(WARN, Logger::AGENCY) << e.what();
generateError(GeneralResponse::ResponseCode::SERVER_ERROR, generateError(GeneralResponse::ResponseCode::SERVER_ERROR,

View File

@ -84,7 +84,7 @@ HttpCommTask::HttpCommTask(HttpServer* server, TRI_socket_t socket,
<< _connectionInfo.clientPort; << _connectionInfo.clientPort;
// release the statistics object we got from the socket task first // release the statistics object we got from the socket task first
// this is required at the moment for proper statistics calculation // this is required at the moment for proper statistics calculation
connectionStatisticsAgentSetHttp(); connectionStatisticsAgentSetHttp();
ConnectionStatisticsAgent::release(); ConnectionStatisticsAgent::release();
@ -350,8 +350,10 @@ bool HttpCommTask::processRead() {
TRI_invalidatesocket(&_commSocket); TRI_invalidatesocket(&_commSocket);
// might delete this // might delete this
// note that as we closed the socket above, the response will not make it to // note that as we closed the socket above, the response will not make
// the client! will result in a "Empty reply from server" error in curl etc. // it to
// the client! will result in a "Empty reply from server" error in
// curl etc.
handleResponse(&response); handleResponse(&response);
return false; return false;
@ -536,14 +538,12 @@ bool HttpCommTask::processRead() {
else { else {
HttpResponse response(GeneralResponse::ResponseCode::UNAUTHORIZED, HttpResponse response(GeneralResponse::ResponseCode::UNAUTHORIZED,
compatibility); compatibility);
static std::string const wwwAuthenticate = "www-authenticate";
if (sendWwwAuthenticateHeader()) { if (sendWwwAuthenticateHeader()) {
static std::string const realm = static std::string const realm =
"basic realm=\"" + "basic realm=\"" +
_server->handlerFactory()->authenticationRealm(_request) + "\""; _server->handlerFactory()->authenticationRealm(_request) + "\"";
response.setHeaderNC(wwwAuthenticate, realm); response.setHeaderNC(StaticStrings::WwwAuthenticate, realm);
} }
clearRequest(); clearRequest();
@ -608,32 +608,27 @@ void HttpCommTask::addResponse(HttpResponse* response) {
// access-control-allow-origin header now // access-control-allow-origin header now
LOG(TRACE) << "handling CORS response"; LOG(TRACE) << "handling CORS response";
static std::string const accessControl = "access-control-expose-headers";
static std::string const exposedHeaders = static std::string const exposedHeaders =
"etag, content-encoding, content-length, location, " "etag, content-encoding, content-length, location, "
"server, x-arango-errors, x-arango-async-id"; "server, x-arango-errors, x-arango-async-id";
response->setHeaderNC(accessControl, exposedHeaders); response->setHeaderNC(StaticStrings::AccessControlExposeHeaders,
exposedHeaders);
// send back original value of "Origin" header // send back original value of "Origin" header
static std::string const accessOrigin = "access-control-allow-origin"; response->setHeaderNC(StaticStrings::AccessControlAllowOrigin, _origin);
response->setHeaderNC(accessOrigin, _origin);
// send back "Access-Control-Allow-Credentials" header // send back "Access-Control-Allow-Credentials" header
static std::string const accessCredentials = response->setHeaderNC(StaticStrings::AccessControlAllowCredentials,
"access-control-allow-credentials";
response->setHeaderNC(accessCredentials,
(_denyCredentials ? "false" : "true")); (_denyCredentials ? "false" : "true"));
} }
// CORS request handling EOF // CORS request handling EOF
// set "connection" header // set "connection" header
// keep-alive is the default // keep-alive is the default
static std::string const connection = "connection"; response->setHeaderNC(
StaticStrings::Connection,
response->setHeaderNC(connection, (_closeRequested ? "Close" : "Keep-Alive")); (_closeRequested ? StaticStrings::Close : StaticStrings::KeepAlive));
size_t const responseBodyLength = response->bodySize(); size_t const responseBodyLength = response->bodySize();
@ -780,40 +775,37 @@ void HttpCommTask::fillWriteBuffer() {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void HttpCommTask::processCorsOptions(uint32_t compatibility) { void HttpCommTask::processCorsOptions(uint32_t compatibility) {
static std::string const allowedMethods = "DELETE, GET, HEAD, PATCH, POST, PUT"; static std::string const allowedMethods =
"DELETE, GET, HEAD, PATCH, POST, PUT";
HttpResponse response(GeneralResponse::ResponseCode::OK, compatibility); HttpResponse response(GeneralResponse::ResponseCode::OK, compatibility);
static std::string const allow = "allow"; response.setHeaderNC(StaticStrings::Allow, allowedMethods);
response.setHeaderNC(allow, allowedMethods);
if (!_origin.empty()) { if (!_origin.empty()) {
LOG(TRACE) << "got CORS preflight request"; LOG(TRACE) << "got CORS preflight request";
std::string const allowHeaders = std::string const allowHeaders = StringUtils::trim(
StringUtils::trim(_request->header("access-control-request-headers")); _request->header(StaticStrings::AccessControlRequestHeaders));
// send back which HTTP methods are allowed for the resource // send back which HTTP methods are allowed for the resource
// we'll allow all // we'll allow all
static std::string const accessControl = "access-control-allow-methods"; response.setHeaderNC(StaticStrings::AccessControlAllowMethods,
response.setHeaderNC(accessControl, allowedMethods); allowedMethods);
if (!allowHeaders.empty()) { if (!allowHeaders.empty()) {
// allow all extra headers the client requested // allow all extra headers the client requested
// we don't verify them here. the worst that can happen is that the client // we don't verify them here. the worst that can happen is that the client
// sends some broken headers and then later cannot access the data on the // sends some broken headers and then later cannot access the data on the
// server. that's a client problem. // server. that's a client problem.
static std::string const accessControl = "access-control-allow-headers"; response.setHeaderNC(StaticStrings::AccessControlAllowHeaders,
response.setHeaderNC(accessControl, allowHeaders); allowHeaders);
LOG(TRACE) << "client requested validation of the following headers: " LOG(TRACE) << "client requested validation of the following headers: "
<< allowHeaders; << allowHeaders;
} }
// set caching time (hard-coded value) // set caching time (hard-coded value)
static std::string const accessAge = "access-control-max-age"; response.setHeaderNC(StaticStrings::AccessControlMaxAge, StaticStrings::N1800);
static std::string const maxAge = "1800";
response.setHeaderNC(accessAge, maxAge);
} }
clearRequest(); clearRequest();

View File

@ -22,6 +22,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include "RestBaseHandler.h" #include "RestBaseHandler.h"
#include "Basics/StaticStrings.h" #include "Basics/StaticStrings.h"
#include "Basics/StringUtils.h" #include "Basics/StringUtils.h"
#include "Basics/VPackStringBufferAdapter.h" #include "Basics/VPackStringBufferAdapter.h"
@ -149,7 +150,7 @@ void RestBaseHandler::dumpResponse(VPackSlice const& slice,
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
bool RestBaseHandler::returnVelocypack() const { bool RestBaseHandler::returnVelocypack() const {
std::string const& result = _request->header(StaticStrings::AcceptHeader); std::string const& result = _request->header(StaticStrings::Accept);
return (std::string::npos != result.find(StaticStrings::MimeTypeVPack)); return (std::string::npos != result.find(StaticStrings::MimeTypeVPack));
} }

View File

@ -59,10 +59,11 @@ HttpHandler::status_t RestVersionHandler::execute() {
Version::getVPack(result); Version::getVPack(result);
if (application_features::ApplicationServer::server != nullptr) { if (application_features::ApplicationServer::server != nullptr) {
auto server = application_features::ApplicationServer::server->getFeature<ServerFeature>("Server"); auto server = application_features::ApplicationServer::server
->getFeature<ServerFeature>("Server");
result.add("mode", VPackValue(server->operationModeString())); result.add("mode", VPackValue(server->operationModeString()));
} }
result.close(); result.close();
} }
result.close(); result.close();

View File

@ -0,0 +1,309 @@
virtual void startupProgress() override final {
SetServiceStatus(SERVICE_START_PENDING, NO_ERROR, _progress++, 20000);
}
virtual void startupFinished() override final {
// startup finished - signalize we're running.
SetServiceStatus(SERVICE_RUNNING, NO_ERROR, 0, 0);
}
virtual void shutDownBegins() override final {
// startup finished - signalize we're running.
SetServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, 0, 0);
}
static void WINAPI ServiceMain(DWORD dwArgc, LPSTR* lpszArgv) {
// register the service ctrl handler, lpszArgv[0] contains service name
ServiceStatus =
RegisterServiceCtrlHandlerA(lpszArgv[0], (LPHANDLER_FUNCTION)ServiceCtrl);
// set start pending
SetServiceStatus(SERVICE_START_PENDING, 0, 1, 10000);
// and fire up the service
STARTUP_FUNCTION(dwArgc, lpszArgv);
// service has stopped
SetServiceStatus(SERVICE_STOPPED, NO_ERROR, 0, 0);
TRI_CloseWindowsEventlog();
}
void WindowsService::startService(int argc, char** argv) {
SERVICE_TABLE_ENTRY ste[] = {{TEXT(""), (LPSERVICE_MAIN_FUNCTION)ServiceMain},
{nullptr, nullptr}};
if (!StartServiceCtrlDispatcher(ste)) {
std::cerr << "FATAL: StartServiceCtrlDispatcher has failed with "
<< GetLastError() << std::endl;
exit(EXIT_FAILURE);
}
}
void WindowsService::installService() {
CHAR path[MAX_PATH];
if (!GetModuleFileNameA(nullptr, path, MAX_PATH)) {
std::cerr << "FATAL: GetModuleFileNameA failed" << std::endl;
exit(EXIT_FAILURE);
}
// build command
std::string command;
command += "\"";
command += path;
command += "\"";
command += " --start-service";
// register service
InstallServiceCommand(command);
}
void WindowsService::uninstallService(bool force) {
CHAR path[MAX_PATH] = "";
if (!GetModuleFileNameA(nullptr, path, MAX_PATH)) {
std::cerr << "FATAL: GetModuleFileNameA failed" << std::endl;
exit(EXIT_FAILURE);
}
std::cout << "INFO: removing service '" << ServiceName << "'" << std::endl;
SC_HANDLE schSCManager =
OpenSCManager(nullptr, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
if (schSCManager == 0) {
std::cerr << "FATAL: OpenSCManager failed with " << GetLastError()
<< std::endl;
exit(EXIT_FAILURE);
}
SC_HANDLE schService = OpenServiceA(
schSCManager, // SCManager database
ServiceName.c_str(), // name of service
DELETE |
SERVICE_QUERY_CONFIG); // first validate whether its us, then delete.
char serviceConfigMemory[8192]; // msdn says: 8k is enough.
DWORD bytesNeeded = 0;
if (QueryServiceConfig(schService,
(LPQUERY_SERVICE_CONFIGA)&serviceConfigMemory,
sizeof(serviceConfigMemory), &bytesNeeded)) {
QUERY_SERVICE_CONFIG* cfg = (QUERY_SERVICE_CONFIG*)&serviceConfigMemory;
std::string command = std::string("\"") + std::string(path) +
std::string("\" --start-service");
if (strcmp(cfg->lpBinaryPathName, command.c_str())) {
if (!force) {
std::cerr << "NOT removing service of other installation: "
<< cfg->lpBinaryPathName << " Our path is: " << path
<< std::endl;
CloseServiceHandle(schSCManager);
return;
} else {
std::cerr << "Removing service of other installation because of FORCE: "
<< cfg->lpBinaryPathName << "Our path is: " << path
<< std::endl;
}
}
}
CloseServiceHandle(schSCManager);
if (schService == 0) {
std::cerr << "FATAL: OpenServiceA failed with " << GetLastError()
<< std::endl;
exit(EXIT_FAILURE);
}
if (!DeleteService(schService)) {
std::cerr << "FATAL: DeleteService failed with " << GetLastError()
<< std::endl;
exit(EXIT_FAILURE);
}
CloseServiceHandle(schService);
}
void WindowsService::serviceControlStart(bool waitForRunning) {
TRI_ERRORBUF;
SERVICE_STATUS_PROCESS ssp;
DWORD bytesNeeded;
SC_HANDLE schSCManager =
OpenSCManager(nullptr, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
if (schSCManager == 0) {
TRI_SYSTEM_ERROR();
std::cerr << "FATAL: OpenSCManager failed with " << windowsErrorBuf
<< std::endl;
exit(EXIT_FAILURE);
}
// Get a handle to the service.
auto arangoService = OpenService(
schSCManager, ServiceName.c_str(),
SERVICE_START | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS);
if (arangoService == nullptr) {
TRI_SYSTEM_ERROR();
std::cerr << "INFO: OpenService failed with " << windowsErrorBuf
<< std::endl;
exit(EXIT_FAILURE);
}
// Make sure the service is not already started.
if (!QueryServiceStatusEx(arangoService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
sizeof(SERVICE_STATUS_PROCESS), &bytesNeeded)) {
TRI_SYSTEM_ERROR();
std::cerr << "INFO: QueryServiceStatusEx failed with " << windowsErrorBuf
<< std::endl;
CloseServiceHandle(schSCManager);
exit(EXIT_FAILURE);
}
if (ssp.dwCurrentState == SERVICE_RUNNING) {
CloseServiceHandle(schSCManager);
exit(EXIT_SUCCESS);
}
if (!StartService(arangoService, 0, nullptr)) {
TRI_SYSTEM_ERROR();
std::cerr << "StartService failed " << windowsErrorBuf << std::endl;
CloseServiceHandle(arangoService);
CloseServiceHandle(schSCManager);
exit(EXIT_FAILURE);
}
// Save the tick count and initial checkpoint.
ssp.dwCurrentState = SERVICE_START_PENDING;
while (WaitForRunning && ssp.dwCurrentState != SERVICE_START_PENDING) {
// we sleep 1 second before we re-check the status.
Sleep(1000);
// Check the status again.
if (!QueryServiceStatusEx(
arangoService,
SC_STATUS_PROCESS_INFO, // info level
(LPBYTE)&ssp, // address of structure
sizeof(SERVICE_STATUS_PROCESS), // size of structure
&bytesNeeded)) {
TRI_SYSTEM_ERROR();
std::cerr << "INFO: QueryServiceStatusEx failed with " << windowsErrorBuf
<< std::endl;
break;
}
}
CloseServiceHandle(arangoService);
CloseServiceHandle(schSCManager);
exit(EXIT_SUCCESS);
}
void WindowsService::serviceControlStop(bool waitForRunning) {
TRI_ERRORBUF;
SERVICE_STATUS_PROCESS ssp;
DWORD bytesNeeded;
SC_HANDLE schSCManager =
OpenSCManager(nullptr, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
if (schSCManager == 0) {
TRI_SYSTEM_ERROR();
std::cerr << "FATAL: OpenSCManager failed with " << windowsErrorBuf
<< std::endl;
exit(EXIT_FAILURE);
}
// Get a handle to the service.
auto arangoService = OpenService(
schSCManager, ServiceName.c_str(),
SERVICE_STOP | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS);
if (arangoService == nullptr) {
TRI_SYSTEM_ERROR();
std::cerr << "INFO: OpenService failed with " << windowsErrorBuf
<< std::endl;
CloseServiceHandle(schSCManager);
return;
}
// Make sure the service is not already stopped.
if (!QueryServiceStatusEx(arangoService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
sizeof(SERVICE_STATUS_PROCESS), &bytesNeeded)) {
TRI_SYSTEM_ERROR();
std::cerr << "INFO: QueryServiceStatusEx failed with " << windowsErrorBuf
<< std::endl;
CloseServiceHandle(schSCManager);
exit(EXIT_FAILURE);
}
if (ssp.dwCurrentState == SERVICE_STOPPED) {
CloseServiceHandle(schSCManager);
exit(EXIT_SUCCESS);
}
// Send a stop code to the service.
if (!ControlService(arangoService, SERVICE_CONTROL_STOP,
(LPSERVICE_STATUS)&ssp)) {
TRI_SYSTEM_ERROR();
std::cerr << "ControlService failed with " << windowsErrorBuf << std::endl;
CloseServiceHandle(arangoService);
CloseServiceHandle(schSCManager);
exit(EXIT_FAILURE);
}
while (WaitForShutdown && ssp.dwCurrentState == SERVICE_STOPPED) {
// we sleep 1 second before we re-check the status.
Sleep(1000);
if (!QueryServiceStatusEx(arangoService, SC_STATUS_PROCESS_INFO,
(LPBYTE)&ssp, sizeof(SERVICE_STATUS_PROCESS),
&bytesNeeded)) {
TRI_SYSTEM_ERROR();
printf("QueryServiceStatusEx failed (%s)\n", windowsErrorBuf);
CloseServiceHandle(arangoService);
CloseServiceHandle(schSCManager);
exit(EXIT_FAILURE);
}
}
CloseServiceHandle(arangoService);
CloseServiceHandle(schSCManager);
exit(EXIT_SUCCESS);
}
void WindowsService::checkService(int argc, char* argv[],
std::function<int(int, char**)> runServer) {
if (argc < 2) {
return;
}
std::string cmd = argv[1];
if (cmd == "--install-service") {
installService(argc, argv);
}
else if (cmd == "--start-service") {
startService(runServer);
}
else if (cmd == "--servicectl-start") {
serviceControlStart(false);
}
else if (cmd == "--servicectl-start-wait") {
serviceControlStart(true);
}
else if (cmd == "--servicectl-stop") {
serviceControlStop(false);
}
else if (cmd == "--servicectl-stop-wait") {
serviceControlStop(true);
}
else if (cmd == "--uninstall-service") {
bool force = ((argc > 2) && !strcmp(argv[2], "--force"));
uninstallService(force);
}
}

View File

@ -71,7 +71,6 @@ static std::string FriendlyServiceName = "ArangoDB - the multi-model database";
static SERVICE_STATUS_HANDLE ServiceStatus; static SERVICE_STATUS_HANDLE ServiceStatus;
// So we have a valid minidump area during startup: // So we have a valid minidump area during startup:
static std::string miniDumpFilename = "c:\\arangodpanic.dmp";
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief installs arangod as service with command-line /// @brief installs arangod as service with command-line
@ -123,259 +122,6 @@ static void InstallServiceCommand(std::string command) {
CloseServiceHandle(schService); CloseServiceHandle(schService);
} }
////////////////////////////////////////////////////////////////////////////////
/// @brief installs a windows service
////////////////////////////////////////////////////////////////////////////////
static void InstallService(int argc, char* argv[]) {
CHAR path[MAX_PATH];
if (!GetModuleFileNameA(nullptr, path, MAX_PATH)) {
std::cerr << "FATAL: GetModuleFileNameA failed" << std::endl;
exit(EXIT_FAILURE);
}
// build command
std::string command;
command += "\"";
command += path;
command += "\"";
command += " --start-service";
// register service
InstallServiceCommand(command);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief deletes a windows service
////////////////////////////////////////////////////////////////////////////////
static void DeleteService(int argc, char* argv[], bool force) {
CHAR path[MAX_PATH] = "";
if (!GetModuleFileNameA(nullptr, path, MAX_PATH)) {
std::cerr << "FATAL: GetModuleFileNameA failed" << std::endl;
exit(EXIT_FAILURE);
}
std::cout << "INFO: removing service '" << ServiceName << "'" << std::endl;
SC_HANDLE schSCManager =
OpenSCManager(nullptr, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
if (schSCManager == 0) {
std::cerr << "FATAL: OpenSCManager failed with " << GetLastError()
<< std::endl;
exit(EXIT_FAILURE);
}
SC_HANDLE schService = OpenServiceA(
schSCManager, // SCManager database
ServiceName.c_str(), // name of service
DELETE |
SERVICE_QUERY_CONFIG); // first validate whether its us, then delete.
char serviceConfigMemory[8192]; // msdn says: 8k is enough.
DWORD bytesNeeded = 0;
if (QueryServiceConfig(schService,
(LPQUERY_SERVICE_CONFIGA)&serviceConfigMemory,
sizeof(serviceConfigMemory), &bytesNeeded)) {
QUERY_SERVICE_CONFIG* cfg = (QUERY_SERVICE_CONFIG*)&serviceConfigMemory;
std::string command = std::string("\"") + std::string(path) +
std::string("\" --start-service");
if (strcmp(cfg->lpBinaryPathName, command.c_str())) {
if (!force) {
std::cerr << "NOT removing service of other installation: "
<< cfg->lpBinaryPathName << " Our path is: " << path
<< std::endl;
CloseServiceHandle(schSCManager);
return;
} else {
std::cerr << "Removing service of other installation because of FORCE: "
<< cfg->lpBinaryPathName << "Our path is: " << path
<< std::endl;
}
}
}
CloseServiceHandle(schSCManager);
if (schService == 0) {
std::cerr << "FATAL: OpenServiceA failed with " << GetLastError()
<< std::endl;
exit(EXIT_FAILURE);
}
if (!DeleteService(schService)) {
std::cerr << "FATAL: DeleteService failed with " << GetLastError()
<< std::endl;
exit(EXIT_FAILURE);
}
CloseServiceHandle(schService);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief Start the service and optionaly wait till its up & running
////////////////////////////////////////////////////////////////////////////////
static void StartArangoService(bool WaitForRunning) {
TRI_ERRORBUF;
SERVICE_STATUS_PROCESS ssp;
DWORD bytesNeeded;
SC_HANDLE schSCManager =
OpenSCManager(nullptr, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
if (schSCManager == 0) {
TRI_SYSTEM_ERROR();
std::cerr << "FATAL: OpenSCManager failed with " << windowsErrorBuf
<< std::endl;
exit(EXIT_FAILURE);
}
// Get a handle to the service.
auto arangoService = OpenService(
schSCManager, ServiceName.c_str(),
SERVICE_START | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS);
if (arangoService == nullptr) {
TRI_SYSTEM_ERROR();
std::cerr << "INFO: OpenService failed with " << windowsErrorBuf
<< std::endl;
exit(EXIT_FAILURE);
}
// Make sure the service is not already started.
if (!QueryServiceStatusEx(arangoService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
sizeof(SERVICE_STATUS_PROCESS), &bytesNeeded)) {
TRI_SYSTEM_ERROR();
std::cerr << "INFO: QueryServiceStatusEx failed with " << windowsErrorBuf
<< std::endl;
CloseServiceHandle(schSCManager);
exit(EXIT_FAILURE);
}
if (ssp.dwCurrentState == SERVICE_RUNNING) {
CloseServiceHandle(schSCManager);
exit(EXIT_SUCCESS);
}
if (!StartService(arangoService, 0, nullptr)) {
TRI_SYSTEM_ERROR();
std::cerr << "StartService failed " << windowsErrorBuf << std::endl;
CloseServiceHandle(arangoService);
CloseServiceHandle(schSCManager);
exit(EXIT_FAILURE);
}
// Save the tick count and initial checkpoint.
ssp.dwCurrentState = SERVICE_START_PENDING;
while (WaitForRunning && ssp.dwCurrentState != SERVICE_START_PENDING) {
// we sleep 1 second before we re-check the status.
Sleep(1000);
// Check the status again.
if (!QueryServiceStatusEx(
arangoService,
SC_STATUS_PROCESS_INFO, // info level
(LPBYTE)&ssp, // address of structure
sizeof(SERVICE_STATUS_PROCESS), // size of structure
&bytesNeeded)) {
TRI_SYSTEM_ERROR();
std::cerr << "INFO: QueryServiceStatusEx failed with " << windowsErrorBuf
<< std::endl;
break;
}
}
CloseServiceHandle(arangoService);
CloseServiceHandle(schSCManager);
exit(EXIT_SUCCESS);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief Stop the service and optionaly wait till its all dead
////////////////////////////////////////////////////////////////////////////////
static void StopArangoService(bool WaitForShutdown) {
TRI_ERRORBUF;
SERVICE_STATUS_PROCESS ssp;
DWORD bytesNeeded;
SC_HANDLE schSCManager =
OpenSCManager(nullptr, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
if (schSCManager == 0) {
TRI_SYSTEM_ERROR();
std::cerr << "FATAL: OpenSCManager failed with " << windowsErrorBuf
<< std::endl;
exit(EXIT_FAILURE);
}
// Get a handle to the service.
auto arangoService = OpenService(
schSCManager, ServiceName.c_str(),
SERVICE_STOP | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS);
if (arangoService == nullptr) {
TRI_SYSTEM_ERROR();
std::cerr << "INFO: OpenService failed with " << windowsErrorBuf
<< std::endl;
CloseServiceHandle(schSCManager);
return;
}
// Make sure the service is not already stopped.
if (!QueryServiceStatusEx(arangoService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
sizeof(SERVICE_STATUS_PROCESS), &bytesNeeded)) {
TRI_SYSTEM_ERROR();
std::cerr << "INFO: QueryServiceStatusEx failed with " << windowsErrorBuf
<< std::endl;
CloseServiceHandle(schSCManager);
exit(EXIT_FAILURE);
}
if (ssp.dwCurrentState == SERVICE_STOPPED) {
CloseServiceHandle(schSCManager);
exit(EXIT_SUCCESS);
}
// Send a stop code to the service.
if (!ControlService(arangoService, SERVICE_CONTROL_STOP,
(LPSERVICE_STATUS)&ssp)) {
TRI_SYSTEM_ERROR();
std::cerr << "ControlService failed with " << windowsErrorBuf << std::endl;
CloseServiceHandle(arangoService);
CloseServiceHandle(schSCManager);
exit(EXIT_FAILURE);
}
while (WaitForShutdown && ssp.dwCurrentState == SERVICE_STOPPED) {
// we sleep 1 second before we re-check the status.
Sleep(1000);
if (!QueryServiceStatusEx(arangoService, SC_STATUS_PROCESS_INFO,
(LPBYTE)&ssp, sizeof(SERVICE_STATUS_PROCESS),
&bytesNeeded)) {
TRI_SYSTEM_ERROR();
printf("QueryServiceStatusEx failed (%s)\n", windowsErrorBuf);
CloseServiceHandle(arangoService);
CloseServiceHandle(schSCManager);
exit(EXIT_FAILURE);
}
}
CloseServiceHandle(arangoService);
CloseServiceHandle(schSCManager);
exit(EXIT_SUCCESS);
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief flips the status for a service /// @brief flips the status for a service
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -452,57 +198,6 @@ static void WINAPI ServiceCtrl(DWORD dwCtrlCode) {
} }
} }
#include <DbgHelp.h>
LONG CALLBACK unhandledExceptionHandler(EXCEPTION_POINTERS* e) {
#if ARANGODB_ENABLE_BACKTRACE
if ((e != nullptr) && (e->ExceptionRecord != nullptr)) {
LOG_FATAL_WINDOWS("Unhandled exception: %d",
(int)e->ExceptionRecord->ExceptionCode);
} else {
LOG_FATAL_WINDOWS("Unhandled exception without ExceptionCode!");
}
std::string bt;
TRI_GetBacktrace(bt);
std::cerr << bt << std::endl;
LOG_FATAL_WINDOWS(bt.c_str());
HANDLE hFile =
CreateFile(miniDumpFilename.c_str(), GENERIC_WRITE, FILE_SHARE_READ, 0,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile == INVALID_HANDLE_VALUE) {
LOG_FATAL_WINDOWS("could not open minidump file : %lu", GetLastError());
return EXCEPTION_CONTINUE_SEARCH;
}
MINIDUMP_EXCEPTION_INFORMATION exceptionInfo;
exceptionInfo.ThreadId = GetCurrentThreadId();
exceptionInfo.ExceptionPointers = e;
exceptionInfo.ClientPointers = FALSE;
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile,
MINIDUMP_TYPE(MiniDumpWithIndirectlyReferencedMemory |
MiniDumpScanMemory | MiniDumpWithFullMemory),
e ? &exceptionInfo : nullptr, nullptr, nullptr);
if (hFile) {
CloseHandle(hFile);
hFile = nullptr;
}
LOG_FATAL_WINDOWS("wrote minidump: %s", miniDumpFilename.c_str());
#endif
if ((e != nullptr) && (e->ExceptionRecord != nullptr)) {
LOG_FATAL_WINDOWS("Unhandled exception: %d - will crash now.",
(int)e->ExceptionRecord->ExceptionCode);
} else {
LOG_FATAL_WINDOWS(
"Unhandled exception without ExceptionCode - will crash now.!");
}
return EXCEPTION_CONTINUE_SEARCH;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief starts server as service /// @brief starts server as service
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -511,73 +206,9 @@ class WindowsArangoServer : public ArangoServer {
private: private:
DWORD _progress; DWORD _progress;
#if 0
// TODO doesn't work that way.
protected:
//////////////////////////////////////////////////////////////////////////////
/// @brief wrap ArangoDB server so we can properly emmit a status once we're
/// really up and running.
//////////////////////////////////////////////////////////////////////////////
virtual void startupProgress() override final {
SetServiceStatus(SERVICE_START_PENDING, NO_ERROR, _progress++, 20000);
}
//////////////////////////////////////////////////////////////////////////////
/// @brief wrap ArangoDB server so we can properly emmit a status once we're
/// really up and running.
//////////////////////////////////////////////////////////////////////////////
virtual void startupFinished() override final {
// startup finished - signalize we're running.
SetServiceStatus(SERVICE_RUNNING, NO_ERROR, 0, 0);
}
//////////////////////////////////////////////////////////////////////////////
/// @brief wrap ArangoDB server so we can properly emmit a status on shutdown
/// starting
//////////////////////////////////////////////////////////////////////////////
virtual void shutDownBegins() override final {
// startup finished - signalize we're running.
SetServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, 0, 0);
}
#endif
public:
WindowsArangoServer(int argc, char** argv) : ArangoServer(argc, argv) {
_progress = 2;
miniDumpFilename = TRI_GetTempPath();
miniDumpFilename +=
"\\minidump_" + std::to_string(GetCurrentProcessId()) + ".dmp";
}
};
static int ARGC; static int ARGC;
static char** ARGV; static char** ARGV;
static void WINAPI ServiceMain(DWORD dwArgc, LPSTR* lpszArgv) {
if (!TRI_InitWindowsEventLog()) {
return;
}
// register the service ctrl handler, lpszArgv[0] contains service name
ServiceStatus =
RegisterServiceCtrlHandlerA(lpszArgv[0], (LPHANDLER_FUNCTION)ServiceCtrl);
// set start pending
SetServiceStatus(SERVICE_START_PENDING, 0, 1, 10000);
IsRunning = true;
ArangoInstance = new WindowsArangoServer(ARGC, ARGV);
ArangoInstance->setMode(ArangoServer::ServerMode::MODE_SERVICE);
ArangoInstance->start();
IsRunning = false;
// service has stopped
SetServiceStatus(SERVICE_STOPPED, NO_ERROR, 0, 0);
TRI_CloseWindowsEventlog();
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief parse windows specific commandline options /// @brief parse windows specific commandline options
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -627,26 +258,6 @@ bool TRI_ParseMoreArgs(int argc, char* argv[]) {
return false; return false;
} }
////////////////////////////////////////////////////////////////////////////////
/// @brief start the windows service
////////////////////////////////////////////////////////////////////////////////
void TRI_StartService(int argc, char* argv[]) {
// create and start an ArangoDB server
SERVICE_TABLE_ENTRY ste[] = {{TEXT(""), (LPSERVICE_MAIN_FUNCTION)ServiceMain},
{nullptr, nullptr}};
ARGC = argc;
ARGV = argv;
if (!StartServiceCtrlDispatcher(ste)) {
std::cerr << "FATAL: StartServiceCtrlDispatcher has failed with "
<< GetLastError() << std::endl;
exit(EXIT_FAILURE);
}
}
#endif #endif
#endif #endif

View File

@ -68,26 +68,13 @@
using namespace arangodb; using namespace arangodb;
using namespace arangodb::wal; using namespace arangodb::wal;
////////////////////////////////////////////////////////////////////////////////
/// @brief Hooks for OS-Specific functions
////////////////////////////////////////////////////////////////////////////////
// YYY #warning TODO
#if 0 #if 0
#ifdef _WIN32 #ifdef _WIN32
extern bool TRI_ParseMoreArgs(int argc, char* argv[]); WindowsService WINDOWS_SERVICE;
extern void TRI_StartService(int argc, char* argv[]);
#else
bool TRI_ParseMoreArgs(int argc, char* argv[]) { return false; }
void TRI_StartService(int argc, char* argv[]) {}
#endif #endif
#endif #endif
//////////////////////////////////////////////////////////////////////////////// static int runServer(int argc, char** argv) {
/// @brief creates an application server
////////////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[]) {
ArangoGlobalContext context(argc, argv); ArangoGlobalContext context(argc, argv);
context.installSegv(); context.installSegv();
context.maskAllSignals(); context.maskAllSignals();
@ -100,6 +87,45 @@ int main(int argc, char* argv[]) {
application_features::ApplicationServer server(options); application_features::ApplicationServer server(options);
#if 0
#ifdef _WIN32
application_features::ProgressHandler reporter{
[](application_features::ServerState state) {
switch (_state) {
case ServerState::IN_WAIT:
WINDOWS_SERVICE.startupFinished();
break;
case ServerState::IN_STOP:
server.shutdownBegins();
break;
case ServerState::IN_COLLECT_OPTIONS:
case ServerState::IN_VALIDATE_OPTIONS:
case ServerState::IN_PREPARE:
case ServerState::IN_START:
WINDOWS_SERVICE.startupProgress();
break;
case ServerState::UNINITIALIZED:
case ServerState::STOPPED:
break;
}
},
[](application_features::ServerState state, std::string const& name) {
switch (_state) {
case ServerState::IN_COLLECT_OPTIONS:
case ServerState::IN_VALIDATE_OPTIONS:
case ServerState::IN_PREPARE:
case ServerState::IN_START:
WINDOWS_SERVICE.startupProgress();
break;
default:
break;
}
}};
server.addReporter(reporter);
#endif
#endif
std::vector<std::string> nonServerFeatures = { std::vector<std::string> nonServerFeatures = {
"Action", "Affinity", "Agency", "Action", "Affinity", "Agency",
"Cluster", "Daemon", "Dispatcher", "Cluster", "Daemon", "Dispatcher",
@ -175,35 +201,12 @@ int main(int argc, char* argv[]) {
return context.exit(ret); return context.exit(ret);
} }
// YYY #warning TODO int main(int argc, char* argv[]) {
#if 0 #if 0
#ifdef _WIN32
// windows only WINDOWS_SERVICE.serviceStart(argc, argv, runServer);
bool const startAsService = TRI_ParseMoreArgs(argc, argv);
// initialize sub-systems
if (startAsService) {
TRI_StartService(argc, argv);
} else {
ArangoInstance = new ArangoServer(argc, argv);
res = ArangoInstance->start();
}
if (ArangoInstance != nullptr) {
try {
delete ArangoInstance;
} catch (...) {
// caught an error during shutdown
res = EXIT_FAILURE;
#ifdef ARANGODB_ENABLE_MAINTAINER_MODE
std::cerr << "Caught an exception during shutdown" << std::endl;
#endif #endif
}
ArangoInstance = nullptr;
}
// shutdown sub-systems
return context.exit(ret);
#endif #endif
return runServer(argc, argv);
}

View File

@ -24,6 +24,9 @@
using namespace arangodb; using namespace arangodb;
// constants
std::string const StaticStrings::N1800("1800");
// system attribute names // system attribute names
std::string const StaticStrings::IdString("_id"); std::string const StaticStrings::IdString("_id");
std::string const StaticStrings::KeyString("_key"); std::string const StaticStrings::KeyString("_key");
@ -32,8 +35,21 @@ std::string const StaticStrings::FromString("_from");
std::string const StaticStrings::ToString("_to"); std::string const StaticStrings::ToString("_to");
// HTTP headers // HTTP headers
std::string const StaticStrings::AcceptHeader("accept"); std::string const StaticStrings::Accept("accept");
std::string const StaticStrings::AccessControlAllowCredentials("access-control-allow-credentials");
std::string const StaticStrings::AccessControlAllowHeaders("access-control-allow-headers");
std::string const StaticStrings::AccessControlAllowMethods("access-control-allow-methods");
std::string const StaticStrings::AccessControlAllowOrigin("access-control-allow-origin");
std::string const StaticStrings::AccessControlExposeHeaders("access-control-expose-headers");
std::string const StaticStrings::AccessControlMaxAge("access-control-max-age");
std::string const StaticStrings::AccessControlRequestHeaders("access-control-request-headers");
std::string const StaticStrings::Allow("allow");
std::string const StaticStrings::Close("Close");
std::string const StaticStrings::Connection("connection");
std::string const StaticStrings::ContentTypeHeader("content-type"); std::string const StaticStrings::ContentTypeHeader("content-type");
std::string const StaticStrings::KeepAlive("Close");
std::string const StaticStrings::Location("location");
std::string const StaticStrings::WwwAuthenticate("www-authenticate");
// mime types // mime types
std::string const StaticStrings::MimeTypeJson("application/json; charset=utf-8"); std::string const StaticStrings::MimeTypeJson("application/json; charset=utf-8");

View File

@ -28,7 +28,11 @@
namespace arangodb { namespace arangodb {
class StaticStrings { class StaticStrings {
StaticStrings() = delete; StaticStrings() = delete;
public: public:
// constants
static std::string const N1800;
// system attribute names // system attribute names
static std::string const IdString; static std::string const IdString;
static std::string const KeyString; static std::string const KeyString;
@ -37,8 +41,21 @@ class StaticStrings {
static std::string const ToString; static std::string const ToString;
// HTTP headers // HTTP headers
static std::string const AcceptHeader; static std::string const Accept;
static std::string const AccessControlAllowCredentials;
static std::string const AccessControlAllowHeaders;
static std::string const AccessControlAllowMethods;
static std::string const AccessControlAllowOrigin;
static std::string const AccessControlExposeHeaders;
static std::string const AccessControlMaxAge;
static std::string const AccessControlRequestHeaders;
static std::string const Allow;
static std::string const Close;
static std::string const Connection;
static std::string const ContentTypeHeader; static std::string const ContentTypeHeader;
static std::string const KeepAlive;
static std::string const Location;
static std::string const WwwAuthenticate;
// mime types // mime types
static std::string const MimeTypeVPack; static std::string const MimeTypeVPack;

View File

@ -127,7 +127,7 @@ function main(argv) {
serverArgs["javascript.app-path"] = fs.join(tmpDataDir, "apps"); serverArgs["javascript.app-path"] = fs.join(tmpDataDir, "apps");
serverArgs["javascript.startup-directory"] = "js"; serverArgs["javascript.startup-directory"] = "js";
serverArgs["log.file"] = fs.join(tmpDataDir, "log"); serverArgs["log.file"] = fs.join(tmpDataDir, "log");
serverArgs["server.disable-authentication"] = "true"; serverArgs["server.authentication"] = "false";
serverArgs["server.endpoint"] = serverEndpoint; serverArgs["server.endpoint"] = serverEndpoint;
serverArgs["server.threads"] = "3"; serverArgs["server.threads"] = "3";