1
0
Fork 0

issue #1054: add info whether server is running in service or user mode?

This commit is contained in:
Jan Steemann 2015-03-27 16:49:47 +01:00
parent a0420101e2
commit 960b464c57
9 changed files with 180 additions and 65 deletions

View File

@ -1,6 +1,15 @@
v2.6.0 (XXXX-XX-XX)
-------------------
* issue #1051: add info whether server is running in service or user mode?
This will add a "mode" attribute to the result of the result of HTTP GET `/_api/version?details=true`
"mode" can have the following values:
- `standalone`: server was started manually (e.g. on command-line)
- `service`: service is running as Windows service, in daemon mode or under the supervisor
* increased default value of `--server.request-timeout` from 300 to 1200 seconds for client tools
(arangosh, arangoimp, arangodump, arangorestore)

View File

@ -28,15 +28,14 @@
////////////////////////////////////////////////////////////////////////////////
#include "Basics/Common.h"
#include "Basics/messages.h"
#include "Basics/logging.h"
#include "Basics/tri-strings.h"
#include "Rest/InitialiseRest.h"
#include "Basics/files.h"
#include "RestServer/ArangoServer.h"
#include <signal.h>
#include <signal.h>
using namespace triagens;
using namespace triagens::rest;
@ -81,7 +80,6 @@ static SERVICE_STATUS_HANDLE ServiceStatus;
void TRI_GlobalEntryFunction ();
void TRI_GlobalExitFunction (int, void*);
////////////////////////////////////////////////////////////////////////////////
/// @brief installs arangod as service with command-line
////////////////////////////////////////////////////////////////////////////////
@ -135,7 +133,7 @@ static void InstallServiceCommand (std::string command) {
static void InstallService (int argc, char* argv[]) {
CHAR path[MAX_PATH];
if(! GetModuleFileNameA(NULL, path, MAX_PATH)) {
if (! GetModuleFileNameA(NULL, path, MAX_PATH)) {
std::cerr << "FATAL: GetModuleFileNameA failed" << std::endl;
exit(EXIT_FAILURE);
}
@ -160,7 +158,7 @@ static void InstallService (int argc, char* argv[]) {
static void DeleteService (int argc, char* argv[], bool force) {
CHAR path[MAX_PATH] = "";
if(! GetModuleFileNameA(NULL, path, MAX_PATH)) {
if (! GetModuleFileNameA(NULL, path, MAX_PATH)) {
std::cerr << "FATAL: GetModuleFileNameA failed" << std::endl;
exit(EXIT_FAILURE);
}
@ -189,7 +187,7 @@ static void DeleteService (int argc, char* argv[], bool force) {
std::string command = std::string("\"") + std::string(path) + std::string("\" --start-service");
if (strcmp(cfg->lpBinaryPathName, command.c_str())) {
if (!force) {
if (! force) {
std::cerr << "NOT removing service of other installation: " <<
cfg->lpBinaryPathName <<
" Our path is: " <<
@ -272,7 +270,7 @@ static void StartArangoService (bool WaitForRunning) {
exit(EXIT_SUCCESS);
}
if (!StartService(arangoService, 0, NULL) ) {
if (! StartService(arangoService, 0, NULL) ) {
TRI_SYSTEM_ERROR();
std::cout << "StartService failed " << windowsErrorBuf << std::endl;
CloseServiceHandle(arangoService);
@ -289,11 +287,11 @@ static void StartArangoService (bool WaitForRunning) {
// 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 ) ) {
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;
@ -354,7 +352,7 @@ static void StopArangoService (bool WaitForShutdown) {
}
// Send a stop code to the service.
if ( !ControlService(arangoService,
if (! ControlService(arangoService,
SERVICE_CONTROL_STOP,
(LPSERVICE_STATUS) &ssp ) ) {
TRI_SYSTEM_ERROR();
@ -380,6 +378,7 @@ static void StopArangoService (bool WaitForShutdown) {
exit(EXIT_FAILURE);
}
}
CloseServiceHandle(arangoService);
CloseServiceHandle(schSCManager);
exit(EXIT_SUCCESS);
@ -570,8 +569,6 @@ void TRI_GlobalEntryFunction () {
TRI_Application_Exit_SetExit(TRI_GlobalExitFunction);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief global exit function
///
@ -579,7 +576,6 @@ void TRI_GlobalEntryFunction () {
////////////////////////////////////////////////////////////////////////////////
void TRI_GlobalExitFunction (int exitCode, void* data) {
// ...........................................................................
// TODO: need a terminate function for windows to be called and cleanup
// any windows specific stuff.
@ -609,7 +605,7 @@ protected:
/// @brief wrap ArangoDB server so we can properly emmit a status once we're
/// really up and running.
//////////////////////////////////////////////////////////////////////////////
virtual void startupProgress () {
virtual void startupProgress () override final {
SetServiceStatus(SERVICE_START_PENDING, NO_ERROR, _progress++, 20000);
}
@ -617,7 +613,7 @@ protected:
/// @brief wrap ArangoDB server so we can properly emmit a status once we're
/// really up and running.
//////////////////////////////////////////////////////////////////////////////
virtual void startupFinished () {
virtual void startupFinished () override final {
// startup finished - signalize we're running.
SetServiceStatus(SERVICE_RUNNING, NO_ERROR, 0, 0);
}
@ -626,16 +622,18 @@ protected:
/// @brief wrap ArangoDB server so we can properly emmit a status on shutdown
/// starting
//////////////////////////////////////////////////////////////////////////////
virtual void shutDownBegins () {
virtual void shutDownBegins () override final {
// startup finished - signalize we're running.
SetServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, 0, 0);
}
public:
WindowsArangoServer (int argc, char ** argv) :
ArangoServer(argc, argv) {
_progress = 2;
WindowsArangoServer (int argc, char ** argv)
: ArangoServer(argc, argv) {
_progress = 2;
}
};
static int ARGC;
@ -650,6 +648,7 @@ static void WINAPI ServiceMain (DWORD dwArgc, LPSTR *lpszArgv) {
IsRunning = true;
ArangoInstance = new WindowsArangoServer(ARGC, ARGV);
ArangoInstance->setMode(ServerMode::MODE_SERVICE);
ArangoInstance->start();
IsRunning = false;
@ -661,8 +660,7 @@ static void WINAPI ServiceMain (DWORD dwArgc, LPSTR *lpszArgv) {
/// @brief parse windows specific commandline options
////////////////////////////////////////////////////////////////////////////////
bool TRI_ParseMoreArgs (int argc, char* argv[])
{
bool TRI_ParseMoreArgs (int argc, char* argv[]) {
SetUnhandledExceptionFilter(unhandledExceptionHandler);
if (1 < argc) {
@ -702,8 +700,7 @@ bool TRI_ParseMoreArgs (int argc, char* argv[])
/// @brief start the windows service
////////////////////////////////////////////////////////////////////////////////
void TRI_StartService (int argc, char* argv[])
{
void TRI_StartService (int argc, char* argv[]) {
// create and start an ArangoDB server
SERVICE_TABLE_ENTRY ste[] = {

View File

@ -37,7 +37,6 @@
#include "RestServer/ArangoServer.h"
#include <signal.h>
using namespace triagens;
using namespace triagens::rest;
using namespace triagens::arango;
@ -50,8 +49,7 @@ using namespace triagens::arango;
/// @brief ArangoDB server
////////////////////////////////////////////////////////////////////////////////
ArangoServer* ArangoInstance = nullptr;
AnyServer* ArangoInstance = nullptr;
// -----------------------------------------------------------------------------
// --SECTION-- private functions
@ -77,17 +75,17 @@ void TRI_StartService(int argc, char* argv[]) { }
/// @brief handle fatal SIGNALs; print backtrace,
/// and rethrow signal for coredumps.
////////////////////////////////////////////////////////////////////////////////
void abortHandler(int signum) {
TRI_PrintBacktrace();
TRI_PrintBacktrace();
#ifdef _WIN32
exit(255 + signum);
exit(255 + signum);
#else
signal(signum, SIG_DFL);
kill(getpid(), signum);
signal(signum, SIG_DFL);
kill(getpid(), signum);
#endif
}
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
@ -101,7 +99,11 @@ int main (int argc, char* argv[]) {
signal(SIGSEGV, abortHandler);
bool startAsService = TRI_ParseMoreArgs(argc, argv);
#if _WIN32
bool const startAsService = TRI_ParseMoreArgs(argc, argv);
#else
bool const startAsService = false;
#endif
// initialise sub-systems
TRI_GlobalEntryFunction();

View File

@ -92,7 +92,7 @@ V8ClientConnection::V8ClientConnection (Endpoint* endpoint,
// connect to server and get version number
map<string, string> headerFields;
SimpleHttpResult* result = _client->request(HttpRequest::HTTP_REQUEST_GET, "/_api/version", 0, 0, headerFields);
SimpleHttpResult* result = _client->request(HttpRequest::HTTP_REQUEST_GET, "/_api/version?details=true", nullptr, 0, headerFields);
if (! result || ! result->isComplete()) {
// save error message
@ -105,22 +105,29 @@ V8ClientConnection::V8ClientConnection (Endpoint* endpoint,
if (result->getHttpReturnCode() == HttpResponse::OK) {
// default value
_version = "arango";
_mode = "unknown mode";
// convert response body to json
TRI_json_t* json = TRI_JsonString(TRI_UNKNOWN_MEM_ZONE,
result->getBody().c_str());
std::unique_ptr<TRI_json_t> json(TRI_JsonString(TRI_UNKNOWN_MEM_ZONE, result->getBody().c_str()));
if (json != nullptr) {
// look up "server" value
const string server = JsonHelper::getStringValue(json, "server", "");
const string server = JsonHelper::getStringValue(json.get(), "server", "");
// "server" value is a string and content is "arango"
if (server == "arango") {
// look up "version" value
_version = JsonHelper::getStringValue(json, "version", "");
}
_version = JsonHelper::getStringValue(json.get(), "version", "");
auto const* details = TRI_LookupObjectJson(json.get(), "details");
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
if (TRI_IsObjectJson(details)) {
auto const* mode = TRI_LookupObjectJson(details, "mode");
if (TRI_IsStringJson(mode)) {
_mode = std::string(mode->_value._string.data, mode->_value._string.length - 1);
}
}
}
}
}
else {
@ -224,6 +231,14 @@ const string& V8ClientConnection::getVersion () {
return _version;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the server mode
////////////////////////////////////////////////////////////////////////////////
const string& V8ClientConnection::getMode () {
return _mode;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get the last http return code
////////////////////////////////////////////////////////////////////////////////

View File

@ -130,6 +130,12 @@ namespace triagens {
const std::string& getVersion ();
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the server mode
////////////////////////////////////////////////////////////////////////////////
const std::string& getMode ();
////////////////////////////////////////////////////////////////////////////////
/// @brief get the last http return code
///
@ -348,6 +354,12 @@ namespace triagens {
std::string _version;
////////////////////////////////////////////////////////////////////////////////
/// @brief mode
////////////////////////////////////////////////////////////////////////////////
std::string _mode;
////////////////////////////////////////////////////////////////////////////////
/// @brief last http return code
////////////////////////////////////////////////////////////////////////////////

View File

@ -675,7 +675,7 @@ static void ClientConnection_ConstructorCallback (const v8::FunctionCallbackInfo
if (connection->isConnected() && connection->getLastHttpReturnCode() == HttpResponse::OK) {
ostringstream s;
s << "Connected to ArangoDB '" << BaseClient.endpointServer()->getSpecification()
<< "', version " << connection->getVersion() << ", database '" << BaseClient.databaseName()
<< "', version " << connection->getVersion() << " [" << connection->getMode() << "], database '" << BaseClient.databaseName()
<< "', username: '" << BaseClient.username() << "'";
BaseClient.printLine(s.str());
}
@ -769,7 +769,7 @@ static void ClientConnection_reconnect (const v8::FunctionCallbackInfo<v8::Value
if (newConnection->isConnected() && newConnection->getLastHttpReturnCode() == HttpResponse::OK) {
ostringstream s;
s << "Connected to ArangoDB '" << BaseClient.endpointServer()->getSpecification()
<< "' version: " << newConnection->getVersion() << ", database: '" << BaseClient.databaseName()
<< "' version: " << newConnection->getVersion() << " [" << newConnection->getMode() << "], database: '" << BaseClient.databaseName()
<< "', username: '" << BaseClient.username() << "'";
BaseClient.printLine(s.str());
@ -1371,6 +1371,29 @@ static void ClientConnection_getVersion (const v8::FunctionCallbackInfo<v8::Valu
TRI_V8_RETURN_STD_STRING(connection->getVersion());
}
////////////////////////////////////////////////////////////////////////////////
/// @brief ClientConnection method "getMode"
////////////////////////////////////////////////////////////////////////////////
static void ClientConnection_getMode (const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
v8::HandleScope scope(isolate);
// get the connection
V8ClientConnection* connection = TRI_UnwrapClass<V8ClientConnection>(args.Holder(), WRAP_TYPE_CONNECTION);
if (connection == nullptr) {
TRI_V8_THROW_EXCEPTION_INTERNAL("connection class corrupted");
}
if (args.Length() != 0) {
TRI_V8_THROW_EXCEPTION_USAGE("getMode()");
}
TRI_V8_RETURN_STD_STRING(connection->getMode());
}
////////////////////////////////////////////////////////////////////////////////
/// @brief ClientConnection method "getDatabaseName"
////////////////////////////////////////////////////////////////////////////////
@ -2070,7 +2093,8 @@ static bool printHelo(bool useServer, bool promptError) {
if (ClientConnection->isConnected() && ClientConnection->getLastHttpReturnCode() == HttpResponse::OK) {
ostringstream is;
is << "Connected to ArangoDB '" << BaseClient.endpointString()
<< "' version: " << ClientConnection->getVersion() << ", database: '" << BaseClient.databaseName()
<< "' version: " << ClientConnection->getVersion()
<< " [" << ClientConnection->getMode() << "], database: '" << BaseClient.databaseName()
<< "', username: '" << BaseClient.username() << "'";
BaseClient.printLine(is.str(), true);
@ -2147,6 +2171,7 @@ void InitCallbacks (v8::Isolate *isolate,
connection_proto->Set(isolate, "reconnect", v8::FunctionTemplate::New(isolate, ClientConnection_reconnect));
connection_proto->Set(isolate, "toString", v8::FunctionTemplate::New(isolate, ClientConnection_toString));
connection_proto->Set(isolate, "getVersion", v8::FunctionTemplate::New(isolate, ClientConnection_getVersion));
connection_proto->Set(isolate, "getMode", v8::FunctionTemplate::New(isolate, ClientConnection_getMode));
connection_proto->Set(isolate, "getDatabaseName", v8::FunctionTemplate::New(isolate, ClientConnection_getDatabaseName));
connection_proto->Set(isolate, "setDatabaseName", v8::FunctionTemplate::New(isolate, ClientConnection_setDatabaseName));
connection_proto->SetCallAsFunctionHandler(ClientConnection_ConstructorCallback);

View File

@ -32,6 +32,7 @@
#include "Basics/json.h"
#include "Basics/tri-strings.h"
#include "Basics/conversions.h"
#include "Rest/AnyServer.h"
#include "Rest/HttpRequest.h"
#include "Rest/Version.h"
@ -40,6 +41,12 @@ using namespace triagens::rest;
using namespace triagens::admin;
using namespace std;
////////////////////////////////////////////////////////////////////////////////
/// @brief ArangoDB server
////////////////////////////////////////////////////////////////////////////////
extern AnyServer* ArangoInstance;
////////////////////////////////////////////////////////////////////////////////
/// @brief name of the queue
////////////////////////////////////////////////////////////////////////////////
@ -140,15 +147,15 @@ HttpHandler::status_t RestVersionHandler::execute () {
RequestStatisticsAgentSetIgnore(this);
TRI_InitObjectJson(TRI_CORE_MEM_ZONE, &result, 3);
TRI_InitObjectJson(TRI_UNKNOWN_MEM_ZONE, &result, 3);
TRI_json_t server;
TRI_InitStringJson(&server, TRI_DuplicateStringZ(TRI_CORE_MEM_ZONE, "arango"), strlen("arango"));
TRI_Insert2ObjectJson(TRI_CORE_MEM_ZONE, &result, "server", &server);
TRI_InitStringJson(&server, TRI_DuplicateStringZ(TRI_UNKNOWN_MEM_ZONE, "arango"), strlen("arango"));
TRI_Insert2ObjectJson(TRI_UNKNOWN_MEM_ZONE, &result, "server", &server);
TRI_json_t version;
TRI_InitStringJson(&version, TRI_DuplicateStringZ(TRI_CORE_MEM_ZONE, TRI_VERSION), strlen(TRI_VERSION));
TRI_Insert2ObjectJson(TRI_CORE_MEM_ZONE, &result, "version", &version);
TRI_InitStringJson(&version, TRI_DuplicateStringZ(TRI_UNKNOWN_MEM_ZONE, TRI_VERSION), strlen(TRI_VERSION));
TRI_Insert2ObjectJson(TRI_UNKNOWN_MEM_ZONE, &result, "version", &version);
bool found;
char const* detailsStr = _request->value("details", found);
@ -156,14 +163,20 @@ HttpHandler::status_t RestVersionHandler::execute () {
if (found && StringUtils::boolean(detailsStr)) {
TRI_json_t details;
TRI_InitObjectJson(TRI_CORE_MEM_ZONE, &details);
TRI_InitObjectJson(TRI_UNKNOWN_MEM_ZONE, &details);
Version::getJson(TRI_CORE_MEM_ZONE, &details);
TRI_Insert2ObjectJson(TRI_CORE_MEM_ZONE, &result, "details", &details);
Version::getJson(TRI_UNKNOWN_MEM_ZONE, &details);
if (ArangoInstance != nullptr) {
std::string mode = ArangoInstance->modeString();
TRI_Insert2ObjectJson(TRI_UNKNOWN_MEM_ZONE, &details, "mode", TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, mode.c_str(), mode.size()));
}
TRI_Insert2ObjectJson(TRI_UNKNOWN_MEM_ZONE, &result, "details", &details);
}
generateResult(&result);
TRI_DestroyJson(TRI_CORE_MEM_ZONE, &result);
TRI_DestroyJson(TRI_UNKNOWN_MEM_ZONE, &result);
return status_t(HANDLER_DONE);
}

View File

@ -136,7 +136,7 @@ static void CheckPidFile (string const& pidFile) {
#ifdef TRI_HAVE_FORK
static int forkProcess (string const& workingDirectory, string& current) {
static int ForkProcess (string const& workingDirectory, string& current) {
// fork off the parent process
TRI_pid_t pid = fork();
@ -213,7 +213,7 @@ static int forkProcess (string const& workingDirectory, string& current) {
// TODO: use windows API CreateProcess & CreateThread to minic fork()
// ..............................................................................
static int forkProcess (string const& workingDirectory, string& current) {
static int ForkProcess (string const& workingDirectory, string& current) {
// fork off the parent process
TRI_pid_t pid = -1; // fork();
@ -236,7 +236,7 @@ static int forkProcess (string const& workingDirectory, string& current) {
////////////////////////////////////////////////////////////////////////////////
AnyServer::AnyServer ()
: _daemonMode(false),
: _mode(ServerMode::MODE_STANDALONE),
_supervisorMode(false),
_pidFile(""),
_workingDirectory(""),
@ -248,9 +248,7 @@ AnyServer::AnyServer ()
////////////////////////////////////////////////////////////////////////////////
AnyServer::~AnyServer () {
if (_applicationServer != nullptr) {
delete _applicationServer;
}
delete _applicationServer;
}
// -----------------------------------------------------------------------------
@ -262,7 +260,6 @@ AnyServer::~AnyServer () {
////////////////////////////////////////////////////////////////////////////////
int AnyServer::start () {
startupProgress();
if (_applicationServer == nullptr) {
@ -343,7 +340,7 @@ int AnyServer::startupSupervisor () {
_applicationServer->setupLogging(false, true, false);
string current;
int result = forkProcess(_workingDirectory, current);
int result = ForkProcess(_workingDirectory, current);
// main process
if (result != 0) {
@ -352,6 +349,8 @@ int AnyServer::startupSupervisor () {
// child process
else {
setMode(ServerMode::MODE_SERVICE);
time_t startTime = time(0);
time_t t;
bool done = false;
@ -481,7 +480,7 @@ int AnyServer::startupDaemon () {
_applicationServer->setupLogging(false, true, false);
string current;
int result = forkProcess(_workingDirectory, current);
int result = ForkProcess(_workingDirectory, current);
// main process
if (result != 0) {
@ -494,6 +493,7 @@ int AnyServer::startupDaemon () {
// child process
else {
setMode(ServerMode::MODE_SERVICE);
_applicationServer->setupLogging(true, false, true);
LOG_DEBUG("daemon mode: within child");

View File

@ -50,8 +50,8 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
class AnyServer {
AnyServer (AnyServer const&);
AnyServer& operator= (AnyServer const&);
AnyServer (AnyServer const&) = delete;
AnyServer& operator= (AnyServer const&) = delete;
// -----------------------------------------------------------------------------
// --SECTION-- constructors and destructors
@ -71,6 +71,21 @@ namespace triagens {
virtual ~AnyServer ();
// -----------------------------------------------------------------------------
// --SECTION-- public types
// -----------------------------------------------------------------------------
public:
////////////////////////////////////////////////////////////////////////////////
/// @brief enumeration for server modes
////////////////////////////////////////////////////////////////////////////////
enum class ServerMode {
MODE_STANDALONE,
MODE_SERVICE
};
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
@ -89,6 +104,27 @@ namespace triagens {
void beginShutdown ();
////////////////////////////////////////////////////////////////////////////////
/// @brief set the server mode
////////////////////////////////////////////////////////////////////////////////
void setMode (ServerMode mode) {
_mode = mode;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get the server mode as a string
////////////////////////////////////////////////////////////////////////////////
char const* modeString () const {
if (_mode == ServerMode::MODE_STANDALONE) {
return "standalone";
}
TRI_ASSERT(_mode == ServerMode::MODE_SERVICE) {
return "service";
}
}
// -----------------------------------------------------------------------------
// --SECTION-- protected methods
// -----------------------------------------------------------------------------
@ -137,6 +173,12 @@ namespace triagens {
protected:
////////////////////////////////////////////////////////////////////////////////
/// @brief the server mode
////////////////////////////////////////////////////////////////////////////////
ServerMode _mode;
////////////////////////////////////////////////////////////////////////////////
/// @brief running in daemon mode
////////////////////////////////////////////////////////////////////////////////