diff --git a/nomad/cli/admin/__init__.py b/nomad/cli/admin/__init__.py index 32109390a4dbbaa3d7ba0a7381111cde70df010d..48157c3e7d39c2442201949378d9ea5077e09312 100644 --- a/nomad/cli/admin/__init__.py +++ b/nomad/cli/admin/__init__.py @@ -13,4 +13,4 @@ # limitations under the License. -from . import admin, uploads, run, clean, users +from . import admin, uploads, entries, run, clean, users diff --git a/nomad/cli/admin/entries.py b/nomad/cli/admin/entries.py new file mode 100644 index 0000000000000000000000000000000000000000..3ca0d7b1798caca727826aea9781423c96555c22 --- /dev/null +++ b/nomad/cli/admin/entries.py @@ -0,0 +1,39 @@ +# Copyright 2018 Markus Scheidgen +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an"AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import click + +from nomad import processing as proc, infrastructure, search +from .admin import admin + + +@admin.group(help='Entry related commands') +def entries(): + infrastructure.setup_mongo() + infrastructure.setup_elastic() + + +@entries.command(help='Delete selected entries from mongo and elastic') +@click.argument('ENTRIES', nargs=-1) +@click.option('--skip-es', help='Keep the elastic index version of the data.', is_flag=True) +@click.option('--skip-mongo', help='Keep uploads and calcs in mongo.', is_flag=True) +def rm(entries, skip_es, skip_mongo): + print('%d entries selected, deleting ...' % len(entries)) + + if not skip_es: + for entry in entries: + search.delete_entry(calc_id=entry) + + if not skip_mongo: + proc.Calc.objects(calc_id__in=entries).delete() diff --git a/nomad/search.py b/nomad/search.py index 492f13c806ec21a27d0e9ad46e29277fdce1876f..1bbff8ce6385c124ac5f27171e4b17146b0d55ac 100644 --- a/nomad/search.py +++ b/nomad/search.py @@ -167,6 +167,12 @@ def delete_upload(upload_id): Search(index=index).query('match', upload_id=upload_id).delete() +def delete_entry(calc_id): + """ Delete the entry with the given ``calc_id`` from the index. """ + index = Entry._default_index() + Search(index=index).query('match', calc_id=calc_id).delete() + + def publish(calcs: Iterable[datamodel.CalcWithMetadata]) -> None: """ Update all given calcs with their metadata and set ``publish = True``. """ def elastic_updates(): diff --git a/tests/test_cli.py b/tests/test_cli.py index 18dd6f1b06346f5dab7dba0f2c51086bd0fec719..ee34730b298bd9b32cbdc952ba8843205d5e32ab 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -79,6 +79,19 @@ class TestAdmin: assert search.SearchRequest().search_parameter('comment', 'specific').execute()['total'] == 1 + def test_delete_entry(self, published): + upload_id = published.upload_id + calc = Calc.objects(upload_id=upload_id).first() + + result = click.testing.CliRunner().invoke( + cli, ['admin', 'entries', 'rm', calc.calc_id], catch_exceptions=False, obj=utils.POPO()) + + print(result.output) + assert result.exit_code == 0 + assert 'deleting' in result.stdout + assert Upload.objects(upload_id=upload_id).first() is not None + assert Calc.objects(calc_id=calc.calc_id).first() is None + @pytest.mark.usefixtures('reset_config', 'no_warn') class TestAdminUploads: