From f4071f2d47ba785c4209a79a577bb43a47ca2c5c Mon Sep 17 00:00:00 2001 From: Anthony Mahanna <43019056+aMahanna@users.noreply.github.com> Date: Wed, 24 Apr 2024 11:50:17 -0400 Subject: [PATCH] DE-741 | Options API [3.12] (#317) * DE-741 | initial commit * doc: update docstrings * fix import * fix starter * cleanup `.conf` files * fix: typo * Update cluster-3.12.conf * fix eof --- arango/database.py | 54 +++++++++++++++++++ arango/exceptions.py | 8 +++ starter.sh | 7 ++- .../{cluster.conf => cluster-3.11.conf} | 0 tests/static/cluster-3.12.conf | 15 ++++++ .../static/{single.conf => single-3.11.conf} | 0 tests/static/single-3.12.conf | 13 +++++ tests/test_database.py | 10 ++++ 8 files changed, 103 insertions(+), 4 deletions(-) rename tests/static/{cluster.conf => cluster-3.11.conf} (100%) create mode 100644 tests/static/cluster-3.12.conf rename tests/static/{single.conf => single-3.11.conf} (100%) create mode 100644 tests/static/single-3.12.conf diff --git a/arango/database.py b/arango/database.py index 935d4186..7348c256 100644 --- a/arango/database.py +++ b/arango/database.py @@ -42,6 +42,8 @@ PermissionListError, PermissionResetError, PermissionUpdateError, + ServerAvailableOptionsGetError, + ServerCurrentOptionsGetError, ServerDetailsError, ServerEchoError, ServerEncryptionError, @@ -1118,6 +1120,58 @@ def response_handler(resp: Response) -> Json: return self._execute(request, response_handler) + def options(self) -> Result[Json]: + """Return the currently-set server options (ArangoDB 3.12+) + + As this API may reveal sensitive data about the deployment, it can only + be accessed from inside the _system database. In addition, there is a + policy control startup option --server.options-api that determines if and + to whom the API is made available. This option can have the following + values: + - disabled: API is disabled. + - jwt: API can only be accessed via superuser JWT. + - admin: API can be accessed by admin users in the _system database only. + - public: everyone with access to _system database can access the API. + + :return: Server options. + :rtype: dict + """ + request = Request(method="get", endpoint="/_admin/options") + + def response_handler(resp: Response) -> Json: + if resp.is_success: + result: Json = resp.body + return result + raise ServerCurrentOptionsGetError(resp, request) + + return self._execute(request, response_handler) + + def options_available(self) -> Result[Json]: + """Return a description of all available server options (ArangoDB 3.12+) + + As this API may reveal sensitive data about the deployment, it can only + be accessed from inside the _system database. In addition, there is a + policy control startup option --server.options-api that determines if and + to whom the API is made available. This option can have the following + values: + - disabled: API is disabled. + - jwt: API can only be accessed via superuser JWT. + - admin: API can be accessed by admin users in the _system database only. + - public: everyone with access to _system database can access the options API. + + :return: Server options. + :rtype: dict + """ + request = Request(method="get", endpoint="/_admin/options-description") + + def response_handler(resp: Response) -> Json: + if resp.is_success: + result: Json = resp.body + return result + raise ServerAvailableOptionsGetError(resp, request) + + return self._execute(request, response_handler) + ####################### # Database Management # ####################### diff --git a/arango/exceptions.py b/arango/exceptions.py index 2adb718c..d03fd841 100644 --- a/arango/exceptions.py +++ b/arango/exceptions.py @@ -722,6 +722,14 @@ class ServerEncryptionError(ArangoServerError): """Failed to reload user-defined encryption keys.""" +class ServerCurrentOptionsGetError(ArangoServerError): + """Failed to retrieve currently-set server options.""" + + +class ServerAvailableOptionsGetError(ArangoServerError): + """Failed to retrieve available server options.""" + + class ServerExecuteError(ArangoServerError): """Failed to execute raw JavaScript command.""" diff --git a/starter.sh b/starter.sh index d0973f37..3716dc22 100755 --- a/starter.sh +++ b/starter.sh @@ -32,11 +32,10 @@ else exit 1 fi -conf_file="" -if [[ "${version%.*}" == "3.10" ]]; then - conf_file="${setup}-3.10" +if [ "$version" == "latest" ]; then + conf_file="${setup}-3.12" else - conf_file="${setup}" + conf_file="${setup}-${version%.*.*}" fi docker run -d \ diff --git a/tests/static/cluster.conf b/tests/static/cluster-3.11.conf similarity index 100% rename from tests/static/cluster.conf rename to tests/static/cluster-3.11.conf diff --git a/tests/static/cluster-3.12.conf b/tests/static/cluster-3.12.conf new file mode 100644 index 00000000..d33e07a3 --- /dev/null +++ b/tests/static/cluster-3.12.conf @@ -0,0 +1,15 @@ +[starter] +mode = cluster +local = true +address = 0.0.0.0 +port = 8528 + +[auth] +jwt-secret = /tests/static/keyfile + +[args] +all.database.password = passwd +all.database.extended-names = true +all.log.api-enabled = true +all.javascript.allow-admin-execute = true +all.server.options-api = admin diff --git a/tests/static/single.conf b/tests/static/single-3.11.conf similarity index 100% rename from tests/static/single.conf rename to tests/static/single-3.11.conf diff --git a/tests/static/single-3.12.conf b/tests/static/single-3.12.conf new file mode 100644 index 00000000..424d809e --- /dev/null +++ b/tests/static/single-3.12.conf @@ -0,0 +1,13 @@ +[starter] +mode = single +address = 0.0.0.0 +port = 8528 + +[auth] +jwt-secret = /tests/static/keyfile + +[args] +all.database.password = passwd +all.database.extended-names = true +all.javascript.allow-admin-execute = true +all.server.options-api = admin \ No newline at end of file diff --git a/tests/test_database.py b/tests/test_database.py index 0a9bb6b4..cab4bd24 100644 --- a/tests/test_database.py +++ b/tests/test_database.py @@ -1,6 +1,7 @@ from datetime import datetime import pytest +from packaging import version from arango.aql import AQL from arango.backup import Backup @@ -438,3 +439,12 @@ def test_license(sys_db, enterprise): assert license == {"license": "none"} with pytest.raises(ServerLicenseSetError): sys_db.set_license("abc") + + +def test_options(sys_db, db_version): + # Skip if below 3.12 + if db_version < version.parse("3.12.0"): + pytest.skip("Database options require ArangoDB 3.12+") + + assert sys_db.options() + assert sys_db.options_available()