diff --git a/Documentation/ImplementorManual/HttpEndpoint.md b/Documentation/ImplementorManual/HttpEndpoint.md new file mode 100644 index 0000000000..44fc38ea7f --- /dev/null +++ b/Documentation/ImplementorManual/HttpEndpoint.md @@ -0,0 +1,43 @@ +HTTP Interface for managing Endpoints {#HttpEndpoint} +===================================================== + +@NAVIGATE_HttpEndpoint +@EMBEDTOC{HttpEndpointTOC} + +Endpoints {#HttpEndpointIntro} +============================== + +The ArangoDB server can listen for incoming requests on multiple *endpoints*. + +The endpoint is normally specified either in ArangoDB's configuration file or on +the command-line, using the @ref CommandLineArangoEndpoint option. + +The number of endpoints can also be changed at runtime using the API described +below. Each endpoint can optionally be restricted to a specific list of databases +only, thus allowing the usage of different port numbers for different databases. + +This may be useful in multi-tenant setups. +A multi-endpoint setup may also be useful to turn on encrypted communication for +just specific databases. + +The HTTP interface provides operations to add new endpoints at runtime, and +optionally restrict them for use with specific databases. The interface also can +be used to update existing endpoints or remove them at runtime. + +Please note that all endpoint management operations can only be accessed via +the default database (`_system`) and none of the other databases. + +Managing Endpoints via HTTP {#HttpEndpointHttp} +=============================================== + +@anchor HttpEndpointPost +@copydetails JSF_post_api_endpoint + +@CLEARPAGE +@anchor HttpEndpointDelete +@copydetails JSF_delete_api_endpoint + +@CLEARPAGE +@anchor HttpEndpointGet +@copydetails JSF_get_api_endpoint + diff --git a/Documentation/ImplementorManual/HttpEndpointTOC.md b/Documentation/ImplementorManual/HttpEndpointTOC.md new file mode 100644 index 0000000000..abb70494c0 --- /dev/null +++ b/Documentation/ImplementorManual/HttpEndpointTOC.md @@ -0,0 +1,9 @@ +TOC {#HttpEndpointTOC} +====================== + +- @ref HttpEndpoint + - @ref HttpEndpointIntro + - @ref HttpEndpointHttp + - @ref HttpEndpointPost "POST /_api/endpoint" + - @ref HttpEndpointDelete "DELETE /_api/database/endpoint" + - @ref HttpEndpointGet "GET /_api/endpoint" diff --git a/Documentation/ImplementorManual/ImplementorManual.md b/Documentation/ImplementorManual/ImplementorManual.md index dda5eeff66..b3db5f9a4b 100644 --- a/Documentation/ImplementorManual/ImplementorManual.md +++ b/Documentation/ImplementorManual/ImplementorManual.md @@ -26,6 +26,7 @@ ArangoDB for API Implementors (@VERSION) {#ImplementorManual} @CHAPTER_REF{HttpBatch} @CHAPTER_REF{HttpSystem} @CHAPTER_REF{HttpUser} +@CHAPTER_REF{HttpEndpoint} @CHAPTER_REF{HttpMisc} @CHAPTER_REF{Communication} @CHAPTER_REF{NamingConventions} diff --git a/Documentation/Makefile.files b/Documentation/Makefile.files index 135c595e6a..8d746cf1c6 100644 --- a/Documentation/Makefile.files +++ b/Documentation/Makefile.files @@ -41,6 +41,7 @@ WIKI = \ HttpCurrentDatabase \ HttpCursor \ HttpDatabase \ + HttpEndpoint \ HttpGraph \ HttpImport \ HttpIndex \ diff --git a/Documentation/Scripts/generateExamples.py b/Documentation/Scripts/generateExamples.py index a827d107ca..6a8b07f534 100644 --- a/Documentation/Scripts/generateExamples.py +++ b/Documentation/Scripts/generateExamples.py @@ -281,6 +281,8 @@ def generateArangoshRun(): print "var appender = function(text) { output += text; };" print "var logCurlRequestRaw = require('internal').appendCurlRequest(appender);" print "var logCurlRequest = function () { var r = logCurlRequestRaw.apply(logCurlRequestRaw, arguments); db._collections(); return r; };" + print "var curlRequestRaw = require('internal').appendCurlRequest(function (text) { });" + print "var curlRequest = function () { return curlRequestRaw.apply(curlRequestRaw, arguments); };" print "var logJsonResponse = require('internal').appendJsonResponse(appender);" print "var logRawResponse = require('internal').appendRawResponse(appender);" print "var assert = function(a) { if (! a) { internal.output('%s\\nASSERTION FAILED: %s\\n%s\\n'); throw new Error('assertion failed'); } };" % ('#' * 80, key, '#' * 80) diff --git a/arangod/V8Server/v8-vocbase.cpp b/arangod/V8Server/v8-vocbase.cpp index d83d7b61f9..0b4294435b 100644 --- a/arangod/V8Server/v8-vocbase.cpp +++ b/arangod/V8Server/v8-vocbase.cpp @@ -8042,7 +8042,7 @@ static v8::Handle JS_RemoveEndpoint (v8::Arguments const& argv) { bool result = s->removeEndpoint(TRI_ObjectToString(argv[0])); if (! result) { - TRI_V8_EXCEPTION_MESSAGE(scope, TRI_ERROR_BAD_PARAMETER, "endpoint is not registered"); + TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_ENDPOINT_NOT_FOUND); } return scope.Close(v8::True()); diff --git a/js/actions/api-endpoint.js b/js/actions/api-endpoint.js index d84578b564..71a76953e9 100644 --- a/js/actions/api-endpoint.js +++ b/js/actions/api-endpoint.js @@ -1,5 +1,5 @@ /*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true, evil: true */ -/*global require, exports, module */ +/*global require */ //////////////////////////////////////////////////////////////////////////////// /// @brief endpoint management @@ -24,7 +24,7 @@ /// /// Copyright holder is triAGENS GmbH, Cologne, Germany /// -/// @author Dr. Frank Celler +/// @author Jan Steemann /// @author Copyright 2012, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// @@ -50,22 +50,230 @@ var internal = require("internal"); /// /// @RESTHEADER{GET /_api/endpoint,returns a list of all endpoints} /// +/// @RESTDESCRIPTION +/// Returns a list of all configured endpoints the server is listening on. For +/// each endpoint, the list of allowed databases is returned too if set. +/// +/// The result is a JSON hash which has the endpoints as keys, and the list of +/// mapped database names as values for each endpoint. +/// +/// If a list of mapped databases is empty, it means that all databases can be +/// accessed via the endpoint. If a list of mapped databases contains more than +/// one database name, this means that any of the databases might be accessed +/// via the endpoint, and the first database in the list will be treated as +/// the default database for the endpoint. The default database will be used +/// when an incoming request does not specify a database name in the request +/// explicitly. +/// +/// Note: retrieving the list of all endpoints is allowed in the system database +/// only. Calling this action in any other database will make the server return +/// an error. +/// +/// @RESTRETURNCODES +/// +/// @RESTRETURNCODE{200} +/// is returned when the list of endpoints can be determined successfully. +/// +/// @RESTRETURNCODE{400} +/// is returned if the action is not carried out in the system database. +/// +/// @RESTRETURNCODE{405} +/// The server will respond with `HTTP 405` if an unsupported HTTP method is used. +/// +/// @EXAMPLES +/// +/// @EXAMPLE_ARANGOSH_RUN{RestEndpointGet} +/// var url = "/_api/endpoint"; +/// var endpoint = "tcp://127.0.0.1:8532"; +/// var body = { +/// endpoint: endpoint, +/// databases: [ "mydb1", "mydb2" ] +/// }; +/// curlRequest('POST', url, JSON.stringify(body)); +/// +/// var response = logCurlRequest('GET', url); +/// +/// assert(response.code === 200); +/// +/// logJsonResponse(response); +/// curlRequest('DELETE', url + '/' + encodeURIComponent(endpoint)); +/// @END_EXAMPLE_ARANGOSH_RUN //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// /// @fn JSF_post_api_endpoint /// @brief connects a new endpoint or reconfigures an existing endpoint /// -/// @RESTHEADER{POST /_api/endpoint,connects a new endpoint or reconfigures an existing one} +/// @RESTHEADER{POST /_api/endpoint,adds a new endpoint or reconfigures an existing endpoint} /// +/// @RESTBODYPARAM{description,json,required} +/// A JSON object describing the endpoint. +/// +/// @RESTDESCRIPTION +/// The request body must be JSON hash with the following attributes: +/// +/// - `endpoint`: the endpoint specification, e.g. `tcp://127.0.0.1:8530` +/// +/// - `databases`: a list of database names the endpoint is responsible for. +/// +/// If `databases` is an empty list, all databases present in the server will +/// become accessible via the endpoint, with the `_system` database being the +/// default database. +/// +/// If `databases` is non-empty, only the specified databases will become +/// available via the endpoint. The first database name in the `databases` +/// list will also become the default database for the endpoint. The default +/// database will always be used if a request coming in on the endpoint does +/// not specify the database name explicitly. +/// +/// Note: adding or reconfiguring endpoints is allowed in the system database +/// only. Calling this action in any other database will make the server +/// return an error. +/// +/// Adding SSL endpoints at runtime is only supported if the server was started +/// with SSL properly configured (e.g. `--server.keyfile` must have been set). +/// +/// @RESTRETURNCODES +/// +/// @RESTRETURNCODE{200} +/// is returned when the endpoint was added or changed successfully. +/// +/// @RESTRETURNCODE{400} +/// is returned if the request is malformed or if the action is not carried out +/// in the system database. +/// +/// @RESTRETURNCODE{405} +/// The server will respond with `HTTP 405` if an unsupported HTTP method is used. +/// +/// @EXAMPLES +/// Adding an endpoint `tcp://127.0.0.1:8532` with two mapped databases +/// (`mydb1` and `mydb2`). `mydb1` will become the default database for the +/// endpoint. +/// +/// @EXAMPLE_ARANGOSH_RUN{RestEndpointPostOne} +/// var url = "/_api/endpoint"; +/// var endpoint = "tcp://127.0.0.1:8532"; +/// var body = { +/// endpoint: endpoint, +/// databases: [ "mydb1", "mydb2" ] +/// }; +/// var response = logCurlRequest('POST', url, JSON.stringify(body)); +/// +/// assert(response.code === 200); +/// +/// logJsonResponse(response); +/// curlRequest('DELETE', url + '/' + encodeURIComponent(endpoint)); +/// @END_EXAMPLE_ARANGOSH_RUN +/// +/// Adding an endpoint `tcp://127.0.0.1:8533` with no database names specified. +/// This will allow access to all databases on this endpoint. The `_system` +/// database will become the default database for requests that come in on this +/// endpoint and do not specify the database name explicitly. +/// +/// @EXAMPLE_ARANGOSH_RUN{RestEndpointPostTwo} +/// var url = "/_api/endpoint"; +/// var endpoint = "tcp://127.0.0.1:8533"; +/// var body = { +/// endpoint: endpoint, +/// databases: [ ] +/// }; +/// var response = logCurlRequest('POST', url, JSON.stringify(body)); +/// +/// assert(response.code === 200); +/// +/// logJsonResponse(response); +/// curlRequest('DELETE', url + '/' + encodeURIComponent(endpoint)); +/// @END_EXAMPLE_ARANGOSH_RUN +/// +/// Adding an endpoint `tcp://127.0.0.1:8533` without any databases first, +/// and then updating the databases for the endpoint to `testdb1`, `testdb2`, and +/// `testdb3`. +/// +/// @EXAMPLE_ARANGOSH_RUN{RestEndpointPostChange} +/// var url = "/_api/endpoint"; +/// var endpoint = "tcp://127.0.0.1:8533"; +/// var body = { +/// endpoint: endpoint, +/// databases: [ ] +/// }; +/// var response = logCurlRequest('POST', url, JSON.stringify(body)); +/// +/// assert(response.code === 200); +/// +/// logJsonResponse(response); +/// +/// body.database = [ "testdb1", "testdb2", "testdb3" ]; +/// response = logCurlRequest('POST', url, JSON.stringify(body)); +/// +/// assert(response.code === 200); +/// +/// logJsonResponse(response); +/// curlRequest('DELETE', url + '/' + encodeURIComponent(endpoint)); +/// @END_EXAMPLE_ARANGOSH_RUN //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// /// @fn JSF_delete_api_endpoint /// @brief disconnects an existing endpoint /// -/// @RESTHEADER{DELETE /_api/endpoint/{endpoint},disconnects an existing endpoint} +/// @RESTHEADER{DELETE /_api/endpoint/{endpoint},deletes and disconnects an existing endpoint} /// +/// @RESTDESCRIPTION +/// This operation deletes an existing endpoint from the list of all endpoints, +/// and makes the server stop listening on the endpoint. +/// +/// Note: deleting and disconnecting an endpoint is allowed in the system +/// database only. Calling this action in any other database will make the server +/// return an error. +/// +/// Futhermore, the last remaining endpoint cannot be deleted as this would make +/// the server kaputt. +/// +/// @RESTRETURNCODES +/// +/// @RESTRETURNCODE{200} +/// is returned when the endpoint was deleted and disconnected successfully. +/// +/// @RESTRETURNCODE{400} +/// is returned if the request is malformed or if the action is not carried out +/// in the system database. +/// +/// @RESTRETURNCODE{404} +/// is returned if the endpoint is not found. +/// +/// @RESTRETURNCODE{405} +/// The server will respond with `HTTP 405` if an unsupported HTTP method is used. +/// +/// @EXAMPLES +/// +/// Deleting an existing endpoint +/// +/// @EXAMPLE_ARANGOSH_RUN{RestEndpointDelete} +/// var url = "/_api/endpoint"; +/// var endpoint = "tcp://127.0.0.1:8532"; +/// var body = { +/// endpoint: endpoint, +/// databases: [ ] +/// }; +/// curlRequest('POST', url, JSON.stringify(body)); +/// var response = logCurlRequest('DELETE', url + '/' + encodeURIComponent(endpoint)); +/// +/// assert(response.code === 200); +/// +/// logJsonResponse(response); +/// @END_EXAMPLE_ARANGOSH_RUN +/// +/// Deleting a non-existing endpoint +/// +/// @EXAMPLE_ARANGOSH_RUN{RestEndpointDeleteNonExisting} +/// var url = "/_api/endpoint"; +/// var endpoint = "tcp://127.0.0.1:8532"; +/// var response = logCurlRequest('DELETE', url + '/' + encodeURIComponent(endpoint)); +/// +/// assert(response.code === 404); +/// +/// logJsonResponse(response); +/// @END_EXAMPLE_ARANGOSH_RUN //////////////////////////////////////////////////////////////////////////////// actions.defineHttp({ @@ -91,7 +299,7 @@ actions.defineHttp({ } result = internal.configureEndpoint(body.endpoint, body.databases || [ ]); - actions.resultOk(req, res, actions.HTTP_OK, { result: result }); + actions.resultOk(req, res, actions.HTTP_OK, { result: result }); } else if (req.requestType === actions.DELETE) { diff --git a/js/apps/aardvark/frontend/js/bootstrap/errors.js b/js/apps/aardvark/frontend/js/bootstrap/errors.js index e3bb4668ef..e6585bb82b 100644 --- a/js/apps/aardvark/frontend/js/bootstrap/errors.js +++ b/js/apps/aardvark/frontend/js/bootstrap/errors.js @@ -91,6 +91,7 @@ "ERROR_ARANGO_DATABASE_NOT_FOUND" : { "code" : 1228, "message" : "database not found" }, "ERROR_ARANGO_DATABASE_NAME_INVALID" : { "code" : 1229, "message" : "database name invalid" }, "ERROR_ARANGO_USE_SYSTEM_DATABASE" : { "code" : 1230, "message" : "operation only allowed in system database" }, + "ERROR_ARANGO_ENDPOINT_NOT_FOUND" : { "code" : 1231, "message" : "endpoint not found" }, "ERROR_ARANGO_DATAFILE_FULL" : { "code" : 1300, "message" : "datafile full" }, "ERROR_REPLICATION_NO_RESPONSE" : { "code" : 1400, "message" : "no response" }, "ERROR_REPLICATION_INVALID_RESPONSE" : { "code" : 1401, "message" : "invalid response" }, @@ -144,11 +145,10 @@ "ERROR_USER_INVALID_PASSWORD" : { "code" : 1701, "message" : "invalid password" }, "ERROR_USER_DUPLICATE" : { "code" : 1702, "message" : "duplicate user" }, "ERROR_USER_NOT_FOUND" : { "code" : 1703, "message" : "user not found" }, - "ERROR_APPLICATION_NOT_FOUND" : { "code" : 1750, "message" : "application not found" }, - "ERROR_APPLICATION_INVALID_NAME" : { "code" : 1751, "message" : "invalid application name" }, - "ERROR_APPLICATION_INVALID_MOUNT" : { "code" : 1752, "message" : "invalid mount" }, - "ERROR_APPLICATION_DOWNLOAD_FAILED" : { "code" : 1753, "message" : "application download failed" }, - "ERROR_APPLICATION_UPLOAD_FAILED" : { "code" : 1754, "message" : "application upload failed" }, + "ERROR_APPLICATION_INVALID_NAME" : { "code" : 1750, "message" : "invalid application name" }, + "ERROR_APPLICATION_INVALID_MOUNT" : { "code" : 1751, "message" : "invalid mount" }, + "ERROR_APPLICATION_DOWNLOAD_FAILED" : { "code" : 1752, "message" : "application download failed" }, + "ERROR_APPLICATION_UPLOAD_FAILED" : { "code" : 1753, "message" : "application upload failed" }, "ERROR_KEYVALUE_INVALID_KEY" : { "code" : 1800, "message" : "invalid key declaration" }, "ERROR_KEYVALUE_KEY_EXISTS" : { "code" : 1801, "message" : "key already exists" }, "ERROR_KEYVALUE_KEY_NOT_FOUND" : { "code" : 1802, "message" : "key not found" }, diff --git a/js/common/bootstrap/errors.js b/js/common/bootstrap/errors.js index e3bb4668ef..e6585bb82b 100644 --- a/js/common/bootstrap/errors.js +++ b/js/common/bootstrap/errors.js @@ -91,6 +91,7 @@ "ERROR_ARANGO_DATABASE_NOT_FOUND" : { "code" : 1228, "message" : "database not found" }, "ERROR_ARANGO_DATABASE_NAME_INVALID" : { "code" : 1229, "message" : "database name invalid" }, "ERROR_ARANGO_USE_SYSTEM_DATABASE" : { "code" : 1230, "message" : "operation only allowed in system database" }, + "ERROR_ARANGO_ENDPOINT_NOT_FOUND" : { "code" : 1231, "message" : "endpoint not found" }, "ERROR_ARANGO_DATAFILE_FULL" : { "code" : 1300, "message" : "datafile full" }, "ERROR_REPLICATION_NO_RESPONSE" : { "code" : 1400, "message" : "no response" }, "ERROR_REPLICATION_INVALID_RESPONSE" : { "code" : 1401, "message" : "invalid response" }, @@ -144,11 +145,10 @@ "ERROR_USER_INVALID_PASSWORD" : { "code" : 1701, "message" : "invalid password" }, "ERROR_USER_DUPLICATE" : { "code" : 1702, "message" : "duplicate user" }, "ERROR_USER_NOT_FOUND" : { "code" : 1703, "message" : "user not found" }, - "ERROR_APPLICATION_NOT_FOUND" : { "code" : 1750, "message" : "application not found" }, - "ERROR_APPLICATION_INVALID_NAME" : { "code" : 1751, "message" : "invalid application name" }, - "ERROR_APPLICATION_INVALID_MOUNT" : { "code" : 1752, "message" : "invalid mount" }, - "ERROR_APPLICATION_DOWNLOAD_FAILED" : { "code" : 1753, "message" : "application download failed" }, - "ERROR_APPLICATION_UPLOAD_FAILED" : { "code" : 1754, "message" : "application upload failed" }, + "ERROR_APPLICATION_INVALID_NAME" : { "code" : 1750, "message" : "invalid application name" }, + "ERROR_APPLICATION_INVALID_MOUNT" : { "code" : 1751, "message" : "invalid mount" }, + "ERROR_APPLICATION_DOWNLOAD_FAILED" : { "code" : 1752, "message" : "application download failed" }, + "ERROR_APPLICATION_UPLOAD_FAILED" : { "code" : 1753, "message" : "application upload failed" }, "ERROR_KEYVALUE_INVALID_KEY" : { "code" : 1800, "message" : "invalid key declaration" }, "ERROR_KEYVALUE_KEY_EXISTS" : { "code" : 1801, "message" : "key already exists" }, "ERROR_KEYVALUE_KEY_NOT_FOUND" : { "code" : 1802, "message" : "key not found" }, diff --git a/lib/BasicsC/errors.dat b/lib/BasicsC/errors.dat index 00b843faa3..a59bb18efb 100755 --- a/lib/BasicsC/errors.dat +++ b/lib/BasicsC/errors.dat @@ -109,6 +109,7 @@ ERROR_ARANGO_DOCUMENT_TYPE_INVALID,1227,"invalid document type","Will be raised ERROR_ARANGO_DATABASE_NOT_FOUND,1228,"database not found","Will be raised when a non-existing database is accessed." ERROR_ARANGO_DATABASE_NAME_INVALID,1229,"database name invalid","Will be raised when an invalid database name is used." ERROR_ARANGO_USE_SYSTEM_DATABASE,1230,"operation only allowed in system database","Will be raised when an operation is requested in a database other than the system database." +ERROR_ARANGO_ENDPOINT_NOT_FOUND,1231,"endpoint not found","Will be raised when there is an attempt to delete a non-existing endpoint." ################################################################################ ## ArangoDB storage errors @@ -204,11 +205,10 @@ ERROR_USER_NOT_FOUND,1703,"user not found","Will be raised when a user name is u ## Application management ################################################################################ -ERROR_APPLICATION_NOT_FOUND,1750,"application not found","Will be raised when an application is not found or not present in the specified version." -ERROR_APPLICATION_INVALID_NAME,1751,"invalid application name","Will be raised when an invalid application name is specified." -ERROR_APPLICATION_INVALID_MOUNT,1752,"invalid mount","Will be raised when an invalid mount is specified." -ERROR_APPLICATION_DOWNLOAD_FAILED,1753,"application download failed","Will be raised when an application download from the central repository failed." -ERROR_APPLICATION_UPLOAD_FAILED,1754,"application upload failed","Will be raised when an application upload from the client to the ArangoDB server failed." +ERROR_APPLICATION_INVALID_NAME,1750,"invalid application name","Will be raised when an invalid application name is specified." +ERROR_APPLICATION_INVALID_MOUNT,1751,"invalid mount","Will be raised when an invalid mount is specified." +ERROR_APPLICATION_DOWNLOAD_FAILED,1752,"application download failed","Will be raised when an application download from the central repository failed." +ERROR_APPLICATION_UPLOAD_FAILED,1753,"application upload failed","Will be raised when an application upload from the client to the ArangoDB server failed." ################################################################################ ## Key value access diff --git a/lib/BasicsC/voc-errors.c b/lib/BasicsC/voc-errors.c index 75361cf238..898123db0e 100644 --- a/lib/BasicsC/voc-errors.c +++ b/lib/BasicsC/voc-errors.c @@ -87,6 +87,7 @@ void TRI_InitialiseErrorMessages (void) { REG_ERROR(ERROR_ARANGO_DATABASE_NOT_FOUND, "database not found"); REG_ERROR(ERROR_ARANGO_DATABASE_NAME_INVALID, "database name invalid"); REG_ERROR(ERROR_ARANGO_USE_SYSTEM_DATABASE, "operation only allowed in system database"); + REG_ERROR(ERROR_ARANGO_ENDPOINT_NOT_FOUND, "endpoint not found"); REG_ERROR(ERROR_ARANGO_DATAFILE_FULL, "datafile full"); REG_ERROR(ERROR_REPLICATION_NO_RESPONSE, "no response"); REG_ERROR(ERROR_REPLICATION_INVALID_RESPONSE, "invalid response"); @@ -140,7 +141,6 @@ void TRI_InitialiseErrorMessages (void) { REG_ERROR(ERROR_USER_INVALID_PASSWORD, "invalid password"); REG_ERROR(ERROR_USER_DUPLICATE, "duplicate user"); REG_ERROR(ERROR_USER_NOT_FOUND, "user not found"); - REG_ERROR(ERROR_APPLICATION_NOT_FOUND, "application not found"); REG_ERROR(ERROR_APPLICATION_INVALID_NAME, "invalid application name"); REG_ERROR(ERROR_APPLICATION_INVALID_MOUNT, "invalid mount"); REG_ERROR(ERROR_APPLICATION_DOWNLOAD_FAILED, "application download failed"); diff --git a/lib/BasicsC/voc-errors.h b/lib/BasicsC/voc-errors.h index db053d01f2..58836079f0 100644 --- a/lib/BasicsC/voc-errors.h +++ b/lib/BasicsC/voc-errors.h @@ -182,6 +182,8 @@ extern "C" { /// - 1230: @LIT{operation only allowed in system database} /// Will be raised when an operation is requested in a database other than /// the system database. +/// - 1231: @LIT{endpoint not found} +/// Will be raised when there is an attempt to delete a non-existing endpoint. /// - 1300: @LIT{datafile full} /// Will be raised when the datafile reaches its limit. /// - 1400: @LIT{no response} @@ -318,17 +320,14 @@ extern "C" { /// Will be raised when a user name already exists /// - 1703: @LIT{user not found} /// Will be raised when a user name is updated that does not exist -/// - 1750: @LIT{application not found} -/// Will be raised when an application is not found or not present in the -/// specified version. -/// - 1751: @LIT{invalid application name} +/// - 1750: @LIT{invalid application name} /// Will be raised when an invalid application name is specified. -/// - 1752: @LIT{invalid mount} +/// - 1751: @LIT{invalid mount} /// Will be raised when an invalid mount is specified. -/// - 1753: @LIT{application download failed} +/// - 1752: @LIT{application download failed} /// Will be raised when an application download from the central repository /// failed. -/// - 1754: @LIT{application upload failed} +/// - 1753: @LIT{application upload failed} /// Will be raised when an application upload from the client to the ArangoDB /// server failed. /// - 1800: @LIT{invalid key declaration} @@ -1257,6 +1256,16 @@ void TRI_InitialiseErrorMessages (void); #define TRI_ERROR_ARANGO_USE_SYSTEM_DATABASE (1230) +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1231: ERROR_ARANGO_ENDPOINT_NOT_FOUND +/// +/// endpoint not found +/// +/// Will be raised when there is an attempt to delete a non-existing endpoint. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_ARANGO_ENDPOINT_NOT_FOUND (1231) + //////////////////////////////////////////////////////////////////////////////// /// @brief 1300: ERROR_ARANGO_DATAFILE_FULL /// @@ -1812,38 +1821,27 @@ void TRI_InitialiseErrorMessages (void); #define TRI_ERROR_USER_NOT_FOUND (1703) //////////////////////////////////////////////////////////////////////////////// -/// @brief 1750: ERROR_APPLICATION_NOT_FOUND -/// -/// application not found -/// -/// Will be raised when an application is not found or not present in the -/// specified version. -//////////////////////////////////////////////////////////////////////////////// - -#define TRI_ERROR_APPLICATION_NOT_FOUND (1750) - -//////////////////////////////////////////////////////////////////////////////// -/// @brief 1751: ERROR_APPLICATION_INVALID_NAME +/// @brief 1750: ERROR_APPLICATION_INVALID_NAME /// /// invalid application name /// /// Will be raised when an invalid application name is specified. //////////////////////////////////////////////////////////////////////////////// -#define TRI_ERROR_APPLICATION_INVALID_NAME (1751) +#define TRI_ERROR_APPLICATION_INVALID_NAME (1750) //////////////////////////////////////////////////////////////////////////////// -/// @brief 1752: ERROR_APPLICATION_INVALID_MOUNT +/// @brief 1751: ERROR_APPLICATION_INVALID_MOUNT /// /// invalid mount /// /// Will be raised when an invalid mount is specified. //////////////////////////////////////////////////////////////////////////////// -#define TRI_ERROR_APPLICATION_INVALID_MOUNT (1752) +#define TRI_ERROR_APPLICATION_INVALID_MOUNT (1751) //////////////////////////////////////////////////////////////////////////////// -/// @brief 1753: ERROR_APPLICATION_DOWNLOAD_FAILED +/// @brief 1752: ERROR_APPLICATION_DOWNLOAD_FAILED /// /// application download failed /// @@ -1851,10 +1849,10 @@ void TRI_InitialiseErrorMessages (void); /// failed. //////////////////////////////////////////////////////////////////////////////// -#define TRI_ERROR_APPLICATION_DOWNLOAD_FAILED (1753) +#define TRI_ERROR_APPLICATION_DOWNLOAD_FAILED (1752) //////////////////////////////////////////////////////////////////////////////// -/// @brief 1754: ERROR_APPLICATION_UPLOAD_FAILED +/// @brief 1753: ERROR_APPLICATION_UPLOAD_FAILED /// /// application upload failed /// @@ -1862,7 +1860,7 @@ void TRI_InitialiseErrorMessages (void); /// server failed. //////////////////////////////////////////////////////////////////////////////// -#define TRI_ERROR_APPLICATION_UPLOAD_FAILED (1754) +#define TRI_ERROR_APPLICATION_UPLOAD_FAILED (1753) //////////////////////////////////////////////////////////////////////////////// /// @brief 1800: ERROR_KEYVALUE_INVALID_KEY diff --git a/lib/GeneralServer/GeneralServer.h b/lib/GeneralServer/GeneralServer.h index 02aaa6a4fe..4a1eeb08fb 100644 --- a/lib/GeneralServer/GeneralServer.h +++ b/lib/GeneralServer/GeneralServer.h @@ -195,7 +195,7 @@ namespace triagens { LOGGER_DEBUG("bound to endpoint '" << (*i).first << "'"); } else { - LOGGER_FATAL_AND_EXIT("failed to bind to endpoint '" << (*i).first << "'"); + LOGGER_FATAL_AND_EXIT("failed to bind to endpoint '" << (*i).first << "'. Please review your endpoints configuration."); } } } @@ -465,6 +465,7 @@ namespace triagens { deleteTask(task); return false; } + _scheduler->registerTask(task); _listenTasks.push_back(task); diff --git a/lib/Rest/EndpointIp.cpp b/lib/Rest/EndpointIp.cpp index 00d54d8aab..9718f4c5bd 100644 --- a/lib/Rest/EndpointIp.cpp +++ b/lib/Rest/EndpointIp.cpp @@ -116,7 +116,9 @@ EndpointIp::~EndpointIp () { TRI_socket_t EndpointIp::connectSocket (const struct addrinfo* aip, double connectTimeout, double requestTimeout) { // set address and port - char host[NI_MAXHOST], serv[NI_MAXSERV]; + char host[NI_MAXHOST]; + char serv[NI_MAXSERV]; + if (::getnameinfo(aip->ai_addr, aip->ai_addrlen, host, sizeof(host), serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV) == 0) { @@ -129,6 +131,7 @@ TRI_socket_t EndpointIp::connectSocket (const struct addrinfo* aip, double conne listenSocket.fileHandle = ::socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol); if (listenSocket.fileHandle == INVALID_SOCKET) { + LOGGER_ERROR("socket() failed with " << errno << " (" << strerror(errno) << ")"); listenSocket.fileDescriptor = 0; listenSocket.fileHandle = 0; return listenSocket; @@ -138,7 +141,7 @@ TRI_socket_t EndpointIp::connectSocket (const struct addrinfo* aip, double conne // try to reuse address int opt = 1; if (setsockopt(listenSocket.fileHandle, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast (&opt), sizeof (opt)) == -1) { - LOGGER_ERROR("setsockopt failed with " << errno << " (" << strerror(errno) << ")"); + LOGGER_ERROR("setsockopt() failed with " << errno << " (" << strerror(errno) << ")"); TRI_CLOSE_SOCKET(listenSocket); @@ -152,6 +155,8 @@ TRI_socket_t EndpointIp::connectSocket (const struct addrinfo* aip, double conne int result = ::bind(listenSocket.fileHandle, aip->ai_addr, aip->ai_addrlen); if (result != 0) { // error + LOGGER_ERROR("bind() failed with " << errno << " (" << strerror(errno) << ")"); + TRI_CLOSE_SOCKET(listenSocket); listenSocket.fileDescriptor = 0; @@ -164,9 +169,10 @@ TRI_socket_t EndpointIp::connectSocket (const struct addrinfo* aip, double conne result = ::listen(listenSocket.fileHandle, _listenBacklog); if (result == INVALID_SOCKET) { - TRI_CLOSE_SOCKET(listenSocket); // todo: get the correct error code using WSAGetLastError for windows - LOGGER_ERROR("listen failed with " << errno << " (" << strerror(errno) << ")"); + LOGGER_ERROR("listen() failed with " << errno << " (" << strerror(errno) << ")"); + + TRI_CLOSE_SOCKET(listenSocket); listenSocket.fileDescriptor = 0; listenSocket.fileHandle = 0; diff --git a/lib/Rest/EndpointUnixDomain.cpp b/lib/Rest/EndpointUnixDomain.cpp index ad611bf167..f5b3fc4727 100644 --- a/lib/Rest/EndpointUnixDomain.cpp +++ b/lib/Rest/EndpointUnixDomain.cpp @@ -119,6 +119,7 @@ TRI_socket_t EndpointUnixDomain::connect (double connectTimeout, double requestT listenSocket.fileHandle = socket(AF_UNIX, SOCK_STREAM, 0); if (listenSocket.fileHandle == -1) { + LOGGER_ERROR("socket() failed with " << errno << " (" << strerror(errno) << ")"); listenSocket.fileDescriptor = 0; listenSocket.fileHandle = 0; return listenSocket; @@ -128,7 +129,7 @@ TRI_socket_t EndpointUnixDomain::connect (double connectTimeout, double requestT int opt = 1; if (setsockopt(listenSocket.fileHandle, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast (&opt), sizeof (opt)) == -1) { - LOGGER_ERROR("setsockopt failed with " << errno << " (" << strerror(errno) << ")"); + LOGGER_ERROR("setsockopt() failed with " << errno << " (" << strerror(errno) << ")"); TRI_CLOSE_SOCKET(listenSocket); listenSocket.fileDescriptor = 0; @@ -147,6 +148,7 @@ TRI_socket_t EndpointUnixDomain::connect (double connectTimeout, double requestT int result = bind(listenSocket.fileHandle, (struct sockaddr*) &address, SUN_LEN(&address)); if (result != 0) { // bind error + LOGGER_ERROR("bind() failed with " << errno << " (" << strerror(errno) << ")"); TRI_CLOSE_SOCKET(listenSocket); listenSocket.fileDescriptor = 0; listenSocket.fileHandle = 0; @@ -158,8 +160,8 @@ TRI_socket_t EndpointUnixDomain::connect (double connectTimeout, double requestT result = listen(listenSocket.fileHandle, _listenBacklog); if (result < 0) { + LOGGER_ERROR("listen() failed with " << errno << " (" << strerror(errno) << ")"); TRI_CLOSE_SOCKET(listenSocket); - LOGGER_ERROR("listen failed with " << errno << " (" << strerror(errno) << ")"); listenSocket.fileDescriptor = 0; listenSocket.fileHandle = 0; return listenSocket; diff --git a/lib/Scheduler/ListenTask.cpp b/lib/Scheduler/ListenTask.cpp index 7c0d53e60e..f3cb7bea55 100644 --- a/lib/Scheduler/ListenTask.cpp +++ b/lib/Scheduler/ListenTask.cpp @@ -245,9 +245,11 @@ bool ListenTask::handleEvent (EventToken token, EventType revents) { bool ListenTask::bindSocket () { _listenSocket = _endpoint->connect(30, 300); // connect timeout in seconds + if (_listenSocket.fileHandle == 0) { return false; } return true; } +