From 4cb908acc63fb75fabd99253cc1f56e35a09f30a Mon Sep 17 00:00:00 2001 From: Markus Scheidgen <markus.scheidgen@gmail.com> Date: Sun, 13 Jan 2019 21:25:34 +0100 Subject: [PATCH] operation Fixes to bravado client. Separation of admin commands into api resources. Minor backend changes. --- nomad/api/admin.py | 63 +++++++++++++++++++++++----------------- nomad/api/app.py | 2 +- nomad/client.py | 6 ++-- nomad/parsing/backend.py | 30 +++++++++---------- tests/test_api.py | 2 +- 5 files changed, 55 insertions(+), 48 deletions(-) diff --git a/nomad/api/admin.py b/nomad/api/admin.py index ea6a8d006b..02a88afa55 100644 --- a/nomad/api/admin.py +++ b/nomad/api/admin.py @@ -24,40 +24,49 @@ from .auth import login_really_required ns = api.namespace('admin', description='Administrative operations') -@ns.route('/<string:operation>') -@api.doc(params={'operation': 'The operation to perform.'}) -class AdminOperationsResource(Resource): - @api.doc('exec_admin_command') - @api.response(200, 'Operation performed') - @api.response(404, 'Operation does not exist') - @api.response(400, 'Operation not available/disabled') +@ns.route('/reset') +class AdminRemoveResource(Resource): + @api.doc('exec_reset_command') + @api.response(200, 'Reset performed') + @api.response(400, 'Reset not available/disabled') @login_really_required - def post(self, operation): + def post(self): """ - Allows to perform administrative operations on the nomad services. - - The possible operations are ``reset`` and ``remove``. - The ``reset`` operation will attempt to clear the contents of all databased and indices. + Nomad can be configured to disable reset and the operation might not be available. + """ + if not g.user.is_admin: + abort(401, message='Only the admin user can perform reset.') + + if config.services.disable_reset: + abort(400, message='Operation is disabled') + + infrastructure.reset() + + return dict(messager='Reset performed.'), 200 + + +@ns.route('/remove') +class AdminResetResource(Resource): + @api.doc('exec_remove_command') + @api.response(200, 'Remove performed') + @api.response(400, 'Remove not available/disabled') + @login_really_required + def post(self): + """ The ``remove``operation will attempt to remove all databases. Expect the api to stop functioning after this request. - Reset and remove can be disabled. + Nomad can be configured to disable remove and the operation might not be available. """ if not g.user.is_admin: - abort(401, message='Only the admin user can perform this operation.') - - if operation == 'reset': - if config.services.disable_reset: - abort(400, message='Operation is disabled') - infrastructure.reset() - elif operation == 'remove': - if config.services.disable_reset: - abort(400, message='Operation is disabled') - infrastructure.remove() - else: - abort(404, message='Unknown operation %s' % operation) - - return dict(messager='Operation %s performed.' % operation), 200 + abort(401, message='Only the admin user can perform remove.') + + if config.services.disable_reset: + abort(400, message='Operation is disabled') + + infrastructure.remove() + + return dict(messager='Remove performed.'), 200 diff --git a/nomad/api/app.py b/nomad/api/app.py index 43cc686687..30774675fa 100644 --- a/nomad/api/app.py +++ b/nomad/api/app.py @@ -61,7 +61,7 @@ api = Api( @app.errorhandler(Exception) -@api.errorhandler(Exception) +@api.errorhandler def handle(error: Exception): status_code = getattr(error, 'code', 500) name = getattr(error, 'name', 'Internal Server Error') diff --git a/nomad/client.py b/nomad/client.py index dd1c64130e..ec49277904 100644 --- a/nomad/client.py +++ b/nomad/client.py @@ -49,11 +49,9 @@ def create_client( user: str = user, password: str = pw): """ A factory method to create the client. """ + http_client = RequestsClient() if user is not None: - http_client = RequestsClient() http_client.set_basic_auth(host, user, pw) - else: - http_client = None client = SwaggerClient.from_url( 'http://%s:%d%s/swagger.json' % (host, port, base_path), @@ -299,7 +297,7 @@ def upload(path, name: str, offline: bool, unstage: bool): @cli.command(help='Attempts to reset the nomad.') def reset(): - _cli_client().admin.exec_admin_command(operation='reset').reponse() + _cli_client().admin.exec_reset_command().response() @cli.command(help='Run processing locally.') diff --git a/nomad/parsing/backend.py b/nomad/parsing/backend.py index f16a2cafcf..76176d8076 100644 --- a/nomad/parsing/backend.py +++ b/nomad/parsing/backend.py @@ -458,17 +458,19 @@ class LocalBackend(LegacyParserBackend): sections = self._delegate.results[meta_name] return [section.gIndex for section in sections] - @staticmethod def _write( - json_writer: JSONStreamWriter, - value: Any, + self, json_writer: JSONStreamWriter, value: Any, filter: Callable[[str, Any], Any] = None): if isinstance(value, list): - json_writer.open_array() - for item in value: - LocalBackend._write(json_writer, item, filter=filter) - json_writer.close_array() + if len(value) == 1 and isinstance(value[0], Section) and \ + not self._delegate.metaInfoEnv().infoKindEl(value[0].name).repeats: + self._write(json_writer, value[0], filter=filter) + else: + json_writer.open_array() + for item in value: + self._write(json_writer, item, filter=filter) + json_writer.close_array() elif isinstance(value, Section): section = value @@ -482,7 +484,7 @@ class LocalBackend(LegacyParserBackend): if value is not None: json_writer.key(name) - LocalBackend._write(json_writer, value, filter=filter) + self._write(json_writer, value, filter=filter) json_writer.close_object() @@ -491,10 +493,11 @@ class LocalBackend(LegacyParserBackend): def _obj(self, value: Any, filter: Callable[[str, Any], Any] = None) -> Any: if isinstance(value, list): - if len(value) == 1 and isinstance(value[0], Section) and not self._delegate.metaInfoEnv().infoKindEl(value[0].name).repeats: - return self._obj(value[0]) + if len(value) == 1 and isinstance(value[0], Section) and \ + not self._delegate.metaInfoEnv().infoKindEl(value[0].name).repeats: + return self._obj(value[0], filter=filter) else: - return [self._obj(item) for item in value] + return [self._obj(item, filter=filter) for item in value] elif isinstance(value, Section): section = value @@ -543,10 +546,7 @@ class LocalBackend(LegacyParserBackend): # TODO the root sections should be determined programatically for root_section in ['section_run', 'section_calculation_info', 'section_repository_info']: json_writer.key(root_section) - json_writer.open_array() - for section in self._delegate.results[root_section]: - LocalBackend._write(json_writer, section, filter=filter) - json_writer.close_array() + self._write(json_writer, self._delegate.results[root_section], filter=filter) json_writer.close_object() json_writer.close() diff --git a/tests/test_api.py b/tests/test_api.py index d548b096c7..57fd830b46 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -98,7 +98,7 @@ class TestAdmin: assert rv.status_code == 404 def test_only_admin(self, client, test_user_auth): - rv = client.post('/admin/doesnotexist', headers=test_user_auth) + rv = client.post('/admin/reset', headers=test_user_auth) assert rv.status_code == 401 @pytest.fixture(scope='function') -- GitLab